create-jinmankn-app 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/bin/index.js +76 -0
  2. package/package.json +20 -0
  3. package/templates/blueprint/BLUEPRINT_REPRODUCTION_PROMPT.md +996 -0
  4. package/templates/blueprint/HOW_IT_WORKS.md +286 -0
  5. package/templates/blueprint/README.md +123 -0
  6. package/templates/blueprint/backend/config/db.js +12 -0
  7. package/templates/blueprint/backend/controllers/authController.js +90 -0
  8. package/templates/blueprint/backend/controllers/itemController.js +74 -0
  9. package/templates/blueprint/backend/middleware/auth.js +32 -0
  10. package/templates/blueprint/backend/middleware/errorHandler.js +23 -0
  11. package/templates/blueprint/backend/models/Item.js +26 -0
  12. package/templates/blueprint/backend/models/User.js +28 -0
  13. package/templates/blueprint/backend/package-lock.json +2190 -0
  14. package/templates/blueprint/backend/package.json +23 -0
  15. package/templates/blueprint/backend/routes/authRoutes.js +11 -0
  16. package/templates/blueprint/backend/routes/healthRoutes.js +9 -0
  17. package/templates/blueprint/backend/routes/itemRoutes.js +21 -0
  18. package/templates/blueprint/backend/server.js +29 -0
  19. package/templates/blueprint/frontend/.env.example +1 -0
  20. package/templates/blueprint/frontend/index.html +13 -0
  21. package/templates/blueprint/frontend/package-lock.json +2844 -0
  22. package/templates/blueprint/frontend/package.json +23 -0
  23. package/templates/blueprint/frontend/public/favicon.svg +4 -0
  24. package/templates/blueprint/frontend/src/App.jsx +78 -0
  25. package/templates/blueprint/frontend/src/assets/logo.svg +4 -0
  26. package/templates/blueprint/frontend/src/components/DashboardLayout.jsx +103 -0
  27. package/templates/blueprint/frontend/src/components/ProtectedRoute.jsx +18 -0
  28. package/templates/blueprint/frontend/src/index.css +1 -0
  29. package/templates/blueprint/frontend/src/main.jsx +13 -0
  30. package/templates/blueprint/frontend/src/pages/DashboardHome.jsx +74 -0
  31. package/templates/blueprint/frontend/src/pages/Items.jsx +243 -0
  32. package/templates/blueprint/frontend/src/pages/Login.jsx +101 -0
  33. package/templates/blueprint/frontend/src/pages/Profile.jsx +79 -0
  34. package/templates/blueprint/frontend/src/pages/Register.jsx +122 -0
  35. package/templates/blueprint/frontend/src/pages/Report.jsx +124 -0
  36. package/templates/blueprint/frontend/vite.config.js +10 -0
  37. package/templates/blueprint/package.json +13 -0
  38. package/templates/blueprint/scripts/pack-blueprint.ps1 +18 -0
  39. package/templates/chom/Backend/app.js +25 -0
  40. package/templates/chom/Backend/package-lock.json +1551 -0
  41. package/templates/chom/Backend/package.json +23 -0
  42. package/templates/chom/Backend/seedAdmin.js +21 -0
  43. package/templates/chom/Backend/src/controllers/payment.c.js +57 -0
  44. package/templates/chom/Backend/src/controllers/students.c.js +58 -0
  45. package/templates/chom/Backend/src/controllers/users.c.js +62 -0
  46. package/templates/chom/Backend/src/middleware/authentication.js +18 -0
  47. package/templates/chom/Backend/src/models/payment.m.js +13 -0
  48. package/templates/chom/Backend/src/models/students.m.js +10 -0
  49. package/templates/chom/Backend/src/models/users.m.js +11 -0
  50. package/templates/chom/Backend/src/routes/users.r.js +21 -0
  51. package/templates/chom/Frontend/README.md +16 -0
  52. package/templates/chom/Frontend/eslint.config.js +21 -0
  53. package/templates/chom/Frontend/index.html +13 -0
  54. package/templates/chom/Frontend/package-lock.json +3075 -0
  55. package/templates/chom/Frontend/package.json +31 -0
  56. package/templates/chom/Frontend/public/favicon.svg +1 -0
  57. package/templates/chom/Frontend/public/icons.svg +24 -0
  58. package/templates/chom/Frontend/src/App.css +189 -0
  59. package/templates/chom/Frontend/src/App.jsx +28 -0
  60. package/templates/chom/Frontend/src/api/api.jsx +27 -0
  61. package/templates/chom/Frontend/src/assets/hero.png +0 -0
  62. package/templates/chom/Frontend/src/assets/react.svg +1 -0
  63. package/templates/chom/Frontend/src/assets/vite.svg +1 -0
  64. package/templates/chom/Frontend/src/components/Navbar.jsx +21 -0
  65. package/templates/chom/Frontend/src/index.css +8 -0
  66. package/templates/chom/Frontend/src/main.jsx +10 -0
  67. package/templates/chom/Frontend/src/pages/Dashboard.jsx +21 -0
  68. package/templates/chom/Frontend/src/pages/Landing.jsx +39 -0
  69. package/templates/chom/Frontend/src/pages/Login.jsx +49 -0
  70. package/templates/chom/Frontend/src/pages/Overview.jsx +42 -0
  71. package/templates/chom/Frontend/src/pages/Register.jsx +76 -0
  72. package/templates/chom/Frontend/src/pages/Students.jsx +14 -0
  73. package/templates/chom/Frontend/vite.config.js +8 -0
  74. package/templates/chom/package.json +13 -0
  75. package/templates/hospital-faisal/backend/.env.example +9 -0
  76. package/templates/hospital-faisal/backend/config/db.js +96 -0
  77. package/templates/hospital-faisal/backend/controllers/appointmentController.js +164 -0
  78. package/templates/hospital-faisal/backend/controllers/authController.js +106 -0
  79. package/templates/hospital-faisal/backend/controllers/hospitalReportController.js +72 -0
  80. package/templates/hospital-faisal/backend/controllers/medicalReportController.js +105 -0
  81. package/templates/hospital-faisal/backend/controllers/patientController.js +98 -0
  82. package/templates/hospital-faisal/backend/database/schema.sql +47 -0
  83. package/templates/hospital-faisal/backend/middleware/auth.js +30 -0
  84. package/templates/hospital-faisal/backend/middleware/errorHandler.js +23 -0
  85. package/templates/hospital-faisal/backend/middleware/role.js +6 -0
  86. package/templates/hospital-faisal/backend/package-lock.json +2092 -0
  87. package/templates/hospital-faisal/backend/package.json +23 -0
  88. package/templates/hospital-faisal/backend/routes/appointmentRoutes.js +25 -0
  89. package/templates/hospital-faisal/backend/routes/authRoutes.js +12 -0
  90. package/templates/hospital-faisal/backend/routes/healthRoutes.js +9 -0
  91. package/templates/hospital-faisal/backend/routes/hospitalReportRoutes.js +10 -0
  92. package/templates/hospital-faisal/backend/routes/medicalReportRoutes.js +16 -0
  93. package/templates/hospital-faisal/backend/routes/patientRoutes.js +22 -0
  94. package/templates/hospital-faisal/backend/server.js +46 -0
  95. package/templates/hospital-faisal/frontend/.env.example +1 -0
  96. package/templates/hospital-faisal/frontend/index.html +10 -0
  97. package/templates/hospital-faisal/frontend/package-lock.json +2844 -0
  98. package/templates/hospital-faisal/frontend/package.json +23 -0
  99. package/templates/hospital-faisal/frontend/public/favicon.svg +4 -0
  100. package/templates/hospital-faisal/frontend/src/App.jsx +56 -0
  101. package/templates/hospital-faisal/frontend/src/api.js +20 -0
  102. package/templates/hospital-faisal/frontend/src/assets/logo.svg +4 -0
  103. package/templates/hospital-faisal/frontend/src/components/DashboardLayout.jsx +114 -0
  104. package/templates/hospital-faisal/frontend/src/components/ProtectedRoute.jsx +18 -0
  105. package/templates/hospital-faisal/frontend/src/components/RoleRoute.jsx +14 -0
  106. package/templates/hospital-faisal/frontend/src/index.css +1 -0
  107. package/templates/hospital-faisal/frontend/src/main.jsx +13 -0
  108. package/templates/hospital-faisal/frontend/src/pages/Appointments.jsx +305 -0
  109. package/templates/hospital-faisal/frontend/src/pages/DashboardHome.jsx +105 -0
  110. package/templates/hospital-faisal/frontend/src/pages/Login.jsx +98 -0
  111. package/templates/hospital-faisal/frontend/src/pages/MedicalReports.jsx +182 -0
  112. package/templates/hospital-faisal/frontend/src/pages/Patients.jsx +237 -0
  113. package/templates/hospital-faisal/frontend/src/pages/Profile.jsx +78 -0
  114. package/templates/hospital-faisal/frontend/src/pages/Register.jsx +133 -0
  115. package/templates/hospital-faisal/frontend/src/pages/Report.jsx +167 -0
  116. package/templates/hospital-faisal/frontend/vite.config.js +10 -0
  117. package/templates/hospital-faisal/package.json +13 -0
@@ -0,0 +1,996 @@
1
+ # Blueprint — 100% Identical Reproduction Prompt
2
+
3
+ Copy everything below the line into another AI. Tell it: **Follow exactly. Do not add, remove, rename, or refactor anything. Create every file with the exact paths and contents given. Use only the dependencies and versions listed.**
4
+
5
+ ---
6
+
7
+ ## YOUR TASK
8
+
9
+ Recreate the **Blueprint** full-stack project from scratch in a folder named `blueprint/` with this **exact** structure and **exact** file contents. After creating all files, run `npm install` in `backend/` and `frontend/`.
10
+
11
+ **Hard rules:**
12
+ - Do **not** create `frontend/src/api/axios.js` or any shared API module.
13
+ - Use **axios directly inside pages** with **inline event handlers** (`onSubmit`, `onClick`, `useEffect` IIFEs).
14
+ - Every React component/page: `function Name() { ... }` then **`export default Name` at the end** (never `export default function Name`).
15
+ - Tailwind **v4** via **`@tailwindcss/vite`** plugin only (no `postcss.config.js`, no `tailwind.config.js`, no autoprefixer).
16
+ - Dashboard UI: **side navbar** (`DashboardLayout`) with nested routes under `/dashboard`.
17
+ - Backend entry: **`node src/server.js`** (there is no root `server.js`).
18
+
19
+ ---
20
+
21
+ ## FILE TREE (create exactly these; nothing else except `node_modules`, `dist`, lockfiles after install)
22
+
23
+ ```
24
+ blueprint/
25
+ ├── README.md
26
+ ├── backend/
27
+ │ ├── .env.example
28
+ │ ├── package.json
29
+ │ └── src/
30
+ │ ├── server.js
31
+ │ ├── config/
32
+ │ │ └── db.js
33
+ │ ├── controllers/
34
+ │ │ ├── authController.js
35
+ │ │ └── itemController.js
36
+ │ ├── middleware/
37
+ │ │ ├── auth.js
38
+ │ │ └── errorHandler.js
39
+ │ ├── models/
40
+ │ │ ├── User.js
41
+ │ │ └── Item.js
42
+ │ └── routes/
43
+ │ ├── authRoutes.js
44
+ │ ├── healthRoutes.js
45
+ │ └── itemRoutes.js
46
+ └── frontend/
47
+ ├── .env.example
48
+ ├── index.html
49
+ ├── package.json
50
+ ├── vite.config.js
51
+ └── src/
52
+ ├── main.jsx
53
+ ├── App.jsx
54
+ ├── index.css
55
+ ├── components/
56
+ │ ├── DashboardLayout.jsx
57
+ │ └── ProtectedRoute.jsx
58
+ └── pages/
59
+ ├── Login.jsx
60
+ ├── Register.jsx
61
+ ├── DashboardHome.jsx
62
+ ├── Items.jsx
63
+ └── Profile.jsx
64
+ ```
65
+
66
+ ---
67
+
68
+ ## ROOT: `README.md`
69
+
70
+ Use the README content from the section **README CONTENT** at the end of this document.
71
+
72
+ ---
73
+
74
+ ## BACKEND
75
+
76
+ ### `backend/package.json`
77
+
78
+ ```json
79
+ {
80
+ "name": "blueprint-backend",
81
+ "version": "1.0.0",
82
+ "description": "Blueprint API — Node, Express, MongoDB",
83
+ "main": "server.js",
84
+ "scripts": {
85
+ "dev": "nodemon server.js",
86
+ "start": "node server.js"
87
+ },
88
+ "keywords": [],
89
+ "license": "MIT",
90
+ "dependencies": {
91
+ "bcrypt": "^5.1.1",
92
+ "cors": "^2.8.5",
93
+ "dotenv": "^16.4.7",
94
+ "express": "^4.21.2",
95
+ "jsonwebtoken": "^9.0.2",
96
+ "mongoose": "^8.9.3"
97
+ },
98
+ "devDependencies": {
99
+ "nodemon": "^3.1.9"
100
+ }
101
+ }
102
+ ```
103
+
104
+ ### `backend/.env.example`
105
+
106
+ ```
107
+ PORT=5000
108
+ MONGO_URI=mongodb://127.0.0.1:27017/blueprint_db
109
+ JWT_SECRET=change_this_to_a_long_random_secret
110
+ CLIENT_URL=http://localhost:5173
111
+ ```
112
+
113
+ ### `backend/src/config/db.js`
114
+
115
+ ```javascript
116
+ const mongoose = require('mongoose');
117
+
118
+ async function connectDB() {
119
+ const uri = process.env.MONGO_URI;
120
+ if (!uri) {
121
+ throw new Error('MONGO_URI is not defined');
122
+ }
123
+ await mongoose.connect(uri);
124
+ console.log('MongoDB connected');
125
+ }
126
+
127
+ module.exports = { connectDB };
128
+ ```
129
+
130
+ ### `backend/src/server.js`
131
+
132
+ ```javascript
133
+ require('dotenv').config();
134
+
135
+ const express = require('express');
136
+ const cors = require('cors');
137
+ const { connectDB } = require('./config/db');
138
+ const authRoutes = require('./routes/authRoutes');
139
+ const itemRoutes = require('./routes/itemRoutes');
140
+ const healthRoutes = require('./routes/healthRoutes');
141
+ const { notFound, errorHandler } = require('./middleware/errorHandler');
142
+
143
+ const app = express();
144
+
145
+ app.use(
146
+ cors({
147
+ origin: process.env.CLIENT_URL || 'http://localhost:5173',
148
+ credentials: true,
149
+ })
150
+ );
151
+ app.use(express.json());
152
+
153
+ app.use('/api/health', healthRoutes);
154
+ app.use('/api/auth', authRoutes);
155
+ app.use('/api/items', itemRoutes);
156
+
157
+ app.use(notFound);
158
+ app.use(errorHandler);
159
+
160
+ const PORT = process.env.PORT || 5000;
161
+
162
+ async function start() {
163
+ await connectDB();
164
+ app.listen(PORT, function onListen() {
165
+ console.log(`Server running on http://localhost:${PORT}`);
166
+ });
167
+ }
168
+
169
+ start().catch(function onStartError(err) {
170
+ console.error('Failed to start server:', err.message);
171
+ process.exit(1);
172
+ });
173
+ ```
174
+
175
+ ### `backend/src/middleware/auth.js`
176
+
177
+ ```javascript
178
+ const jwt = require('jsonwebtoken');
179
+ const User = require('../models/User');
180
+
181
+ async function protect(req, res, next) {
182
+ try {
183
+ const header = req.headers.authorization;
184
+
185
+ if (!header || !header.startsWith('Bearer ')) {
186
+ return res.status(401).json({ message: 'Not authorized' });
187
+ }
188
+
189
+ const token = header.split(' ')[1];
190
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);
191
+
192
+ const user = await User.findById(decoded.userId).select('-password');
193
+ if (!user) {
194
+ return res.status(401).json({ message: 'Not authorized' });
195
+ }
196
+
197
+ req.user = user;
198
+ next();
199
+ } catch (err) {
200
+ return res.status(401).json({ message: 'Not authorized' });
201
+ }
202
+ }
203
+
204
+ module.exports = { protect };
205
+ ```
206
+
207
+ ### `backend/src/middleware/errorHandler.js`
208
+
209
+ ```javascript
210
+ function notFound(req, res, next) {
211
+ res.status(404).json({ message: 'Route not found' });
212
+ }
213
+
214
+ function errorHandler(err, req, res, next) {
215
+ console.error(err);
216
+
217
+ if (err.name === 'ValidationError') {
218
+ const messages = Object.values(err.errors).map((e) => e.message);
219
+ return res.status(400).json({ message: messages.join(', ') });
220
+ }
221
+
222
+ if (err.name === 'CastError') {
223
+ return res.status(400).json({ message: 'Invalid ID' });
224
+ }
225
+
226
+ const status = err.statusCode || 500;
227
+ const message = err.message || 'Server error';
228
+
229
+ res.status(status).json({ message });
230
+ }
231
+
232
+ module.exports = { notFound, errorHandler };
233
+ ```
234
+
235
+ ### `backend/src/models/User.js`
236
+
237
+ ```javascript
238
+ const mongoose = require('mongoose');
239
+
240
+ const userSchema = new mongoose.Schema(
241
+ {
242
+ name: {
243
+ type: String,
244
+ required: true,
245
+ trim: true,
246
+ },
247
+ email: {
248
+ type: String,
249
+ required: true,
250
+ unique: true,
251
+ lowercase: true,
252
+ trim: true,
253
+ },
254
+ password: {
255
+ type: String,
256
+ required: true,
257
+ minlength: 6,
258
+ },
259
+ },
260
+ { timestamps: true }
261
+ );
262
+
263
+ const User = mongoose.model('User', userSchema);
264
+
265
+ module.exports = User;
266
+ ```
267
+
268
+ ### `backend/src/models/Item.js`
269
+
270
+ ```javascript
271
+ const mongoose = require('mongoose');
272
+
273
+ const itemSchema = new mongoose.Schema(
274
+ {
275
+ title: {
276
+ type: String,
277
+ required: true,
278
+ trim: true,
279
+ },
280
+ description: {
281
+ type: String,
282
+ default: '',
283
+ trim: true,
284
+ },
285
+ user: {
286
+ type: mongoose.Schema.Types.ObjectId,
287
+ ref: 'User',
288
+ required: true,
289
+ },
290
+ },
291
+ { timestamps: true }
292
+ );
293
+
294
+ const Item = mongoose.model('Item', itemSchema);
295
+
296
+ module.exports = Item;
297
+ ```
298
+
299
+ ### `backend/src/controllers/authController.js`
300
+
301
+ ```javascript
302
+ const bcrypt = require('bcrypt');
303
+ const jwt = require('jsonwebtoken');
304
+ const User = require('../models/User');
305
+
306
+ function createToken(userId) {
307
+ return jwt.sign({ userId }, process.env.JWT_SECRET, { expiresIn: '7d' });
308
+ }
309
+
310
+ function formatUser(user) {
311
+ return {
312
+ id: user._id,
313
+ name: user.name,
314
+ email: user.email,
315
+ };
316
+ }
317
+
318
+ async function register(req, res, next) {
319
+ try {
320
+ const { name, email, password } = req.body;
321
+
322
+ if (!name || !email || !password) {
323
+ return res.status(400).json({ message: 'Name, email, and password are required' });
324
+ }
325
+
326
+ if (password.length < 6) {
327
+ return res.status(400).json({ message: 'Password must be at least 6 characters' });
328
+ }
329
+
330
+ const existing = await User.findOne({ email: email.toLowerCase() });
331
+ if (existing) {
332
+ return res.status(409).json({ message: 'Email already registered' });
333
+ }
334
+
335
+ const hashedPassword = await bcrypt.hash(password, 10);
336
+ const user = await User.create({
337
+ name,
338
+ email: email.toLowerCase(),
339
+ password: hashedPassword,
340
+ });
341
+
342
+ const token = createToken(user._id);
343
+
344
+ res.status(201).json({
345
+ token,
346
+ user: formatUser(user),
347
+ });
348
+ } catch (err) {
349
+ next(err);
350
+ }
351
+ }
352
+
353
+ async function login(req, res, next) {
354
+ try {
355
+ const { email, password } = req.body;
356
+
357
+ if (!email || !password) {
358
+ return res.status(400).json({ message: 'Email and password are required' });
359
+ }
360
+
361
+ const user = await User.findOne({ email: email.toLowerCase() });
362
+ if (!user) {
363
+ return res.status(401).json({ message: 'Invalid email or password' });
364
+ }
365
+
366
+ const match = await bcrypt.compare(password, user.password);
367
+ if (!match) {
368
+ return res.status(401).json({ message: 'Invalid email or password' });
369
+ }
370
+
371
+ const token = createToken(user._id);
372
+
373
+ res.json({
374
+ token,
375
+ user: formatUser(user),
376
+ });
377
+ } catch (err) {
378
+ next(err);
379
+ }
380
+ }
381
+
382
+ async function getMe(req, res, next) {
383
+ try {
384
+ res.json({ user: formatUser(req.user) });
385
+ } catch (err) {
386
+ next(err);
387
+ }
388
+ }
389
+
390
+ module.exports = {
391
+ register,
392
+ login,
393
+ getMe,
394
+ };
395
+ ```
396
+
397
+ ### `backend/src/controllers/itemController.js`
398
+
399
+ ```javascript
400
+ const Item = require('../models/Item');
401
+
402
+ async function getItems(req, res, next) {
403
+ try {
404
+ const items = await Item.find({ user: req.user._id }).sort({ createdAt: -1 });
405
+ res.json({ items });
406
+ } catch (err) {
407
+ next(err);
408
+ }
409
+ }
410
+
411
+ async function getItem(req, res, next) {
412
+ try {
413
+ const item = await Item.findOne({ _id: req.params.id, user: req.user._id });
414
+ if (!item) {
415
+ return res.status(404).json({ message: 'Item not found' });
416
+ }
417
+ res.json({ item });
418
+ } catch (err) {
419
+ next(err);
420
+ }
421
+ }
422
+
423
+ async function createItem(req, res, next) {
424
+ try {
425
+ const { title, description } = req.body;
426
+
427
+ if (!title) {
428
+ return res.status(400).json({ message: 'Title is required' });
429
+ }
430
+
431
+ const item = await Item.create({
432
+ title,
433
+ description: description || '',
434
+ user: req.user._id,
435
+ });
436
+
437
+ res.status(201).json({ item });
438
+ } catch (err) {
439
+ next(err);
440
+ }
441
+ }
442
+
443
+ async function updateItem(req, res, next) {
444
+ try {
445
+ const { title, description } = req.body;
446
+
447
+ const item = await Item.findOne({ _id: req.params.id, user: req.user._id });
448
+ if (!item) {
449
+ return res.status(404).json({ message: 'Item not found' });
450
+ }
451
+
452
+ if (title !== undefined) item.title = title;
453
+ if (description !== undefined) item.description = description;
454
+
455
+ await item.save();
456
+
457
+ res.json({ item });
458
+ } catch (err) {
459
+ next(err);
460
+ }
461
+ }
462
+
463
+ async function deleteItem(req, res, next) {
464
+ try {
465
+ const item = await Item.findOneAndDelete({ _id: req.params.id, user: req.user._id });
466
+ if (!item) {
467
+ return res.status(404).json({ message: 'Item not found' });
468
+ }
469
+ res.json({ message: 'Item deleted' });
470
+ } catch (err) {
471
+ next(err);
472
+ }
473
+ }
474
+
475
+ module.exports = {
476
+ getItems,
477
+ getItem,
478
+ createItem,
479
+ updateItem,
480
+ deleteItem,
481
+ };
482
+ ```
483
+
484
+ ### `backend/src/routes/healthRoutes.js`
485
+
486
+ ```javascript
487
+ const express = require('express');
488
+
489
+ const router = express.Router();
490
+
491
+ router.get('/', function healthCheck(req, res) {
492
+ res.json({ status: 'ok' });
493
+ });
494
+
495
+ module.exports = router;
496
+ ```
497
+
498
+ ### `backend/src/routes/authRoutes.js`
499
+
500
+ ```javascript
501
+ const express = require('express');
502
+ const { register, login, getMe } = require('../controllers/authController');
503
+ const { protect } = require('../middleware/auth');
504
+
505
+ const router = express.Router();
506
+
507
+ router.post('/register', register);
508
+ router.post('/login', login);
509
+ router.get('/me', protect, getMe);
510
+
511
+ module.exports = router;
512
+ ```
513
+
514
+ ### `backend/src/routes/itemRoutes.js`
515
+
516
+ ```javascript
517
+ const express = require('express');
518
+ const {
519
+ getItems,
520
+ getItem,
521
+ createItem,
522
+ updateItem,
523
+ deleteItem,
524
+ } = require('../controllers/itemController');
525
+ const { protect } = require('../middleware/auth');
526
+
527
+ const router = express.Router();
528
+
529
+ router.use(protect);
530
+
531
+ router.get('/', getItems);
532
+ router.get('/:id', getItem);
533
+ router.post('/', createItem);
534
+ router.put('/:id', updateItem);
535
+ router.delete('/:id', deleteItem);
536
+
537
+ module.exports = router;
538
+ ```
539
+
540
+ ---
541
+
542
+ ## FRONTEND
543
+
544
+ ### `frontend/package.json`
545
+
546
+ ```json
547
+ {
548
+ "name": "blueprint-frontend",
549
+ "private": true,
550
+ "version": "1.0.0",
551
+ "type": "module",
552
+ "scripts": {
553
+ "dev": "vite",
554
+ "build": "vite build",
555
+ "preview": "vite preview"
556
+ },
557
+ "dependencies": {
558
+ "axios": "^1.7.9",
559
+ "react": "^18.3.1",
560
+ "react-dom": "^18.3.1",
561
+ "react-router-dom": "^6.28.1"
562
+ },
563
+ "devDependencies": {
564
+ "@tailwindcss/vite": "^4.1.8",
565
+ "@vitejs/plugin-react": "^4.3.4",
566
+ "tailwindcss": "^4.1.8",
567
+ "vite": "^6.0.6"
568
+ }
569
+ }
570
+ ```
571
+
572
+ ### `frontend/.env.example`
573
+
574
+ ```
575
+ VITE_API_URL=http://localhost:5000/api
576
+ ```
577
+
578
+ ### `frontend/index.html`
579
+
580
+ ```html
581
+ <!DOCTYPE html>
582
+ <html lang="en">
583
+ <head>
584
+ <meta charset="UTF-8" />
585
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
586
+ <title>Blueprint</title>
587
+ </head>
588
+ <body>
589
+ <div id="root"></div>
590
+ <script type="module" src="/src/main.jsx"></script>
591
+ </body>
592
+ </html>
593
+ ```
594
+
595
+
596
+ ### `frontend/vite.config.js`
597
+
598
+ ```javascript
599
+ import { defineConfig } from 'vite';
600
+ import react from '@vitejs/plugin-react';
601
+ import tailwindcss from '@tailwindcss/vite';
602
+
603
+ export default defineConfig({
604
+ plugins: [react(), tailwindcss()],
605
+ server: {
606
+ port: 5173,
607
+ },
608
+ });
609
+ ```
610
+
611
+ ### `frontend/src/index.css`
612
+
613
+ ```css
614
+ @import 'tailwindcss';
615
+
616
+ body {
617
+ @apply bg-slate-50 text-slate-900 antialiased;
618
+ }
619
+ ```
620
+
621
+ ### `frontend/src/main.jsx`
622
+
623
+ ```javascript
624
+ import React from 'react';
625
+ import ReactDOM from 'react-dom/client';
626
+ import { BrowserRouter } from 'react-router-dom';
627
+ import App from './App';
628
+ import './index.css';
629
+
630
+ ReactDOM.createRoot(document.getElementById('root')).render(
631
+ <React.StrictMode>
632
+ <BrowserRouter>
633
+ <App />
634
+ </BrowserRouter>
635
+ </React.StrictMode>
636
+ );
637
+ ```
638
+
639
+ ### `frontend/src/App.jsx`
640
+
641
+ ```javascript
642
+ import { Routes, Route, Navigate } from 'react-router-dom';
643
+ import ProtectedRoute from './components/ProtectedRoute';
644
+ import DashboardLayout from './components/DashboardLayout';
645
+ import Login from './pages/Login';
646
+ import Register from './pages/Register';
647
+ import DashboardHome from './pages/DashboardHome';
648
+ import Items from './pages/Items';
649
+ import Profile from './pages/Profile';
650
+
651
+ function App() {
652
+ return (
653
+ <Routes>
654
+ <Route path="/login" element={<Login />} />
655
+ <Route path="/register" element={<Register />} />
656
+
657
+ <Route
658
+ path="/dashboard"
659
+ element={
660
+ <ProtectedRoute>
661
+ <DashboardLayout />
662
+ </ProtectedRoute>
663
+ }
664
+ >
665
+ <Route index element={<DashboardHome />} />
666
+ <Route path="items" element={<Items />} />
667
+ <Route path="profile" element={<Profile />} />
668
+ </Route>
669
+
670
+ <Route path="/items" element={<Navigate to="/dashboard/items" replace />} />
671
+ <Route path="/" element={<Navigate to="/dashboard" replace />} />
672
+ <Route path="*" element={<Navigate to="/dashboard" replace />} />
673
+ </Routes>
674
+ );
675
+ }
676
+
677
+ export default App;
678
+ ```
679
+
680
+ ### `frontend/src/components/ProtectedRoute.jsx`
681
+
682
+ ```javascript
683
+ // this component is helping us to protect our routes so that only authenticated users can access the routes
684
+ import { Navigate } from 'react-router-dom';
685
+
686
+ // this function is firstly checking if the user is authenticated by checking the token in the localStorage
687
+ // if the user is not authenticated, it will redirect the user to the login page
688
+ // if the user is authenticated, it will return the children components
689
+ //and the children component is the component that we want to protect
690
+ function ProtectedRoute({ children }) {
691
+ const token = localStorage.getItem('token');
692
+
693
+ if (!token) {
694
+ return <Navigate to="/login" replace />;
695
+ }
696
+
697
+ return children;
698
+ }
699
+
700
+ export default ProtectedRoute;
701
+ ```
702
+
703
+ ### `frontend/src/components/DashboardLayout.jsx`
704
+
705
+ ```javascript
706
+ import { NavLink, Outlet, useNavigate } from 'react-router-dom';
707
+
708
+ const navLinks = [
709
+ { to: '/dashboard', label: 'Overview', end: true },
710
+ { to: '/dashboard/items', label: 'Items', end: false },
711
+ { to: '/dashboard/profile', label: 'Profile', end: false },
712
+ ];
713
+
714
+ function DashboardLayout() {
715
+ const navigate = useNavigate();
716
+ const storedUser = localStorage.getItem('user');
717
+ const user = storedUser ? JSON.parse(storedUser) : null;
718
+
719
+ return (
720
+ <div className="min-h-screen flex bg-slate-100">
721
+ <aside className="w-64 shrink-0 bg-slate-900 text-slate-100 flex flex-col">
722
+ <div className="px-5 py-6 border-b border-slate-700">
723
+ <p className="text-xs font-semibold uppercase tracking-wider text-slate-400">Blueprint</p>
724
+ <h1 className="text-lg font-bold text-white mt-1">Dashboard</h1>
725
+ </div>
726
+
727
+ <nav className="flex-1 px-3 py-4 space-y-1">
728
+ {navLinks.map(function renderNavLink(link) {
729
+ return (
730
+ <NavLink
731
+ key={link.to}
732
+ to={link.to}
733
+ end={link.end}
734
+ className={function navClass({ isActive }) {
735
+ return [
736
+ 'block rounded-lg px-3 py-2.5 text-sm font-medium transition-colors',
737
+ isActive
738
+ ? 'bg-blue-600 text-white'
739
+ : 'text-slate-300 hover:bg-slate-800 hover:text-white',
740
+ ].join(' ');
741
+ }}
742
+ >
743
+ {link.label}
744
+ </NavLink>
745
+ );
746
+ })}
747
+ </nav>
748
+
749
+ <div className="px-4 py-4 border-t border-slate-700">
750
+ {user && (
751
+ <p className="text-sm font-medium text-white truncate">{user.name}</p>
752
+ )}
753
+ {user && (
754
+ <p className="text-xs text-slate-400 truncate mt-0.5">{user.email}</p>
755
+ )}
756
+ <button
757
+ type="button"
758
+ onClick={function handleLogout() {
759
+ localStorage.removeItem('token');
760
+ localStorage.removeItem('user');
761
+ navigate('/login');
762
+ }}
763
+ className="mt-3 w-full text-sm font-medium text-slate-300 hover:text-white border border-slate-600 rounded-lg px-3 py-2 hover:bg-slate-800 transition-colors"
764
+ >
765
+ Log out
766
+ </button>
767
+ </div>
768
+ </aside>
769
+
770
+ <div className="flex-1 flex flex-col min-w-0">
771
+ <header className="bg-white border-b border-slate-200 px-6 py-4">
772
+ <p className="text-sm text-slate-500">Welcome back</p>
773
+ <h2 className="text-xl font-semibold text-slate-800">
774
+ {user ? `Hello, ${user.name}` : 'Dashboard'}
775
+ </h2>
776
+ </header>
777
+
778
+ <main className="flex-1 p-6 overflow-auto">
779
+ <Outlet />
780
+ </main>
781
+ </div>
782
+ </div>
783
+ );
784
+ }
785
+
786
+ export default DashboardLayout;
787
+ ```
788
+
789
+
790
+
791
+ ---
792
+
793
+ ## FRONTEND PAGES
794
+
795
+ For **Login.jsx**, **Register.jsx**, **DashboardHome.jsx**, **Profile.jsx**, and **Items.jsx**: copy the **exact** contents from the current Blueprint repository files at:
796
+
797
+ - `frontend/src/pages/Login.jsx` (100 lines)
798
+ - `frontend/src/pages/Register.jsx` (118 lines)
799
+ - `frontend/src/pages/DashboardHome.jsx` (75 lines)
800
+ - `frontend/src/pages/Profile.jsx` (38 lines)
801
+ - `frontend/src/pages/Items.jsx` (210 lines)
802
+
803
+ **Patterns all pages must follow:**
804
+ - `const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:5000/api';`
805
+ - `import axios from 'axios';` — no `api/axios.js`
806
+ - Auth requests: `headers: { 'Content-Type': 'application/json' }`
807
+ - Protected requests add: `Authorization: \`Bearer ${localStorage.getItem('token')}\``
808
+ - Login/Register on success: `localStorage.setItem('token', data.token)`, `localStorage.setItem('user', JSON.stringify(data.user))`, `navigate('/dashboard')`
809
+ - Named inline handlers: `function handleX(e) { ... }` inside `onChange` / `onClick` / `onSubmit`
810
+ - `export default` at file end
811
+
812
+ ---
813
+
814
+ ## API CONTRACT (must match exactly)
815
+
816
+ | Method | Path | Auth | Body | Response |
817
+ |--------|------|------|------|----------|
818
+ | GET | /api/health | No | — | `{ status: 'ok' }` |
819
+ | POST | /api/auth/register | No | name, email, password | `{ token, user: { id, name, email } }` |
820
+ | POST | /api/auth/login | No | email, password | `{ token, user }` |
821
+ | GET | /api/auth/me | Bearer | — | `{ user }` |
822
+ | GET | /api/items | Bearer | — | `{ items: [...] }` |
823
+ | GET | /api/items/:id | Bearer | — | `{ item }` |
824
+ | POST | /api/items | Bearer | title, description? | `{ item }` |
825
+ | PUT | /api/items/:id | Bearer | title?, description? | `{ item }` |
826
+ | DELETE | /api/items/:id | Bearer | — | `{ message: 'Item deleted' }` |
827
+
828
+ ---
829
+
830
+ ## UI / ROUTING BEHAVIOR
831
+
832
+ 1. **Public:** `/login`, `/register` — centered white card on slate background.
833
+ 2. **Protected dashboard** at `/dashboard` with layout:
834
+ - Left sidebar (slate-900): brand "Blueprint" / "Dashboard", nav links Overview / Items / Profile, user name/email, Log out.
835
+ - Top header: "Welcome back" + "Hello, {name}".
836
+ - Main: `<Outlet />` for child routes.
837
+ 3. **Redirects:** `/` → `/dashboard`, `/items` → `/dashboard/items`, unknown → `/dashboard`.
838
+ 4. **NavLink** active style: `bg-blue-600 text-white`; inactive: `text-slate-300 hover:bg-slate-800`.
839
+ 5. **Items page:** form (title, description) + list with Edit/Delete; delete uses `window.confirm`.
840
+ 6. **Overview page:** item count card + quick links.
841
+ 7. **Profile page:** name, email, user id from `localStorage` user object.
842
+
843
+ ---
844
+
845
+ ## RUN INSTRUCTIONS (after all files exist)
846
+
847
+ ```bash
848
+ # Terminal 1 — backend
849
+ cd backend
850
+ cp .env.example .env # Windows: Copy-Item .env.example .env
851
+ npm install
852
+ node src/server.js
853
+
854
+ # Terminal 2 — frontend
855
+ cd frontend
856
+ cp .env.example .env
857
+ npm install
858
+ npm run dev
859
+ ```
860
+
861
+ - MongoDB must run at `mongodb://127.0.0.1:27017/blueprint_db`
862
+ - Frontend: http://localhost:5173
863
+ - Backend: http://localhost:5000/api
864
+
865
+ ---
866
+
867
+ ## VERIFICATION CHECKLIST
868
+
869
+ - [ ] No `frontend/src/api/` folder
870
+ - [ ] No `postcss.config.js` or `tailwind.config.js`
871
+ - [ ] `vite.config.js` uses `@tailwindcss/vite`
872
+ - [ ] Dashboard sidebar with 3 links + logout
873
+ - [ ] All components use `export default` at bottom
874
+ - [ ] `npm run build` succeeds in frontend
875
+ - [ ] Register → lands on `/dashboard` with sidebar visible
876
+
877
+ ---
878
+
879
+ ## README CONTENT
880
+
881
+ ```markdown
882
+ # Blueprint
883
+
884
+ A reusable full-stack starter template with authentication, CRUD, and MongoDB. Copy or rename this folder to bootstrap any new project.
885
+
886
+ ## Stack
887
+
888
+ - **Backend:** Node.js, Express, Mongoose, JWT, bcrypt
889
+ - **Frontend:** React (Vite), Tailwind CSS, React Router, axios
890
+
891
+ ## Prerequisites
892
+
893
+ - [Node.js](https://nodejs.org/) (v18+ recommended)
894
+ - [MongoDB](https://www.mongodb.com/try/download/community) running locally (use [MongoDB Compass](https://www.mongodb.com/products/compass) to inspect `blueprint_db`)
895
+
896
+ ## Project structure
897
+
898
+ \`\`\`
899
+ blueprint/
900
+ ├── backend/ # API (port 5000)
901
+ ├── frontend/ # React app (port 5173)
902
+ └── README.md
903
+ \`\`\`
904
+
905
+ ## Setup
906
+
907
+ ### 1. MongoDB
908
+
909
+ Start MongoDB on your machine. The default connection string targets a local instance:
910
+
911
+ \`\`\`
912
+ mongodb://127.0.0.1:27017/blueprint_db
913
+ \`\`\`
914
+
915
+ ### 2. Backend
916
+
917
+ \`\`\`bash
918
+ cd backend
919
+ npm install
920
+ cp .env.example .env
921
+ \`\`\`
922
+
923
+ On Windows (PowerShell):
924
+
925
+ \`\`\`powershell
926
+ Copy-Item .env.example .env
927
+ \`\`\`
928
+
929
+ Edit `.env` and set a strong `JWT_SECRET`. Other defaults work for local development.
930
+
931
+ \`\`\`bash
932
+ node src/server.js
933
+ \`\`\`
934
+
935
+ API base: **http://localhost:5000/api**
936
+
937
+ - Health: `GET /api/health`
938
+ - Auth: `POST /api/auth/register`, `POST /api/auth/login`, `GET /api/auth/me`
939
+ - Items (protected): `GET/POST /api/items`, `GET/PUT/DELETE /api/items/:id`
940
+
941
+ ### 3. Frontend
942
+
943
+ In a second terminal:
944
+
945
+ \`\`\`bash
946
+ cd frontend
947
+ npm install
948
+ cp .env.example .env
949
+ \`\`\`
950
+
951
+ Windows:
952
+
953
+ \`\`\`powershell
954
+ Copy-Item .env.example .env
955
+ \`\`\`
956
+
957
+ \`\`\`bash
958
+ npm run dev
959
+ \`\`\`
960
+
961
+ App URL: **http://localhost:5173**
962
+
963
+ ## Test flow
964
+
965
+ 1. Open **http://localhost:5173/register** and create an account (name, email, password).
966
+ 2. You are redirected to **/dashboard** with a JWT stored in `localStorage`.
967
+ 3. Use the sidebar to open **Items** — create, edit, and delete items.
968
+ 4. Log out, then sign in again at **/login** — your items remain tied to your user only.
969
+
970
+ ## Environment variables
971
+
972
+ **Backend (`backend/.env`)**
973
+
974
+ | Variable | Example |
975
+ |-------------|--------------------------------------|
976
+ | PORT | 5000 |
977
+ | MONGO_URI | mongodb://127.0.0.1:27017/blueprint_db |
978
+ | JWT_SECRET | (long random string) |
979
+ | CLIENT_URL | http://localhost:5173 |
980
+
981
+ **Frontend (`frontend/.env`)**
982
+
983
+ | Variable | Example |
984
+ |---------------|------------------------------|
985
+ | VITE_API_URL | http://localhost:5000/api |
986
+ ```
987
+
988
+ ---
989
+
990
+ ## ALTERNATIVE (fastest 100% match)
991
+
992
+ If the AI has file access, instruct it instead:
993
+
994
+ > Clone or copy the Blueprint repo excluding `node_modules`, `dist`, and lockfiles. Run `npm install` in `backend` and `frontend`. Copy `.env.example` to `.env` in both folders. Start with `node backend/src/server.js` and `npm run dev` in frontend.
995
+
996
+ That guarantees a byte-identical copy without regeneration errors.