create-vrrsystem-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 (64) hide show
  1. package/bin/index.js +30 -0
  2. package/package.json +29 -0
  3. package/templates/VehicleRentalReservationSystem/Documentation/API.md +57 -0
  4. package/templates/VehicleRentalReservationSystem/Documentation/DFD.md +62 -0
  5. package/templates/VehicleRentalReservationSystem/Documentation/ERD.md +109 -0
  6. package/templates/VehicleRentalReservationSystem/Documentation/Installation.md +40 -0
  7. package/templates/VehicleRentalReservationSystem/README.md +165 -0
  8. package/templates/VehicleRentalReservationSystem/backend-project/.env.example +8 -0
  9. package/templates/VehicleRentalReservationSystem/backend-project/config/db.js +10 -0
  10. package/templates/VehicleRentalReservationSystem/backend-project/controllers/auth.controller.js +39 -0
  11. package/templates/VehicleRentalReservationSystem/backend-project/controllers/customer.controller.js +19 -0
  12. package/templates/VehicleRentalReservationSystem/backend-project/controllers/dashboard.controller.js +48 -0
  13. package/templates/VehicleRentalReservationSystem/backend-project/controllers/report.controller.js +45 -0
  14. package/templates/VehicleRentalReservationSystem/backend-project/controllers/reservation.controller.js +94 -0
  15. package/templates/VehicleRentalReservationSystem/backend-project/controllers/user.controller.js +16 -0
  16. package/templates/VehicleRentalReservationSystem/backend-project/controllers/vehicle.controller.js +20 -0
  17. package/templates/VehicleRentalReservationSystem/backend-project/middleware/auth.js +22 -0
  18. package/templates/VehicleRentalReservationSystem/backend-project/middleware/errorHandler.js +10 -0
  19. package/templates/VehicleRentalReservationSystem/backend-project/middleware/validate.js +6 -0
  20. package/templates/VehicleRentalReservationSystem/backend-project/models/Customer.js +11 -0
  21. package/templates/VehicleRentalReservationSystem/backend-project/models/ReservationRental.js +17 -0
  22. package/templates/VehicleRentalReservationSystem/backend-project/models/User.js +20 -0
  23. package/templates/VehicleRentalReservationSystem/backend-project/models/Vehicle.js +14 -0
  24. package/templates/VehicleRentalReservationSystem/backend-project/package-lock.json +1695 -0
  25. package/templates/VehicleRentalReservationSystem/backend-project/package.json +26 -0
  26. package/templates/VehicleRentalReservationSystem/backend-project/routes/auth.routes.js +21 -0
  27. package/templates/VehicleRentalReservationSystem/backend-project/routes/customer.routes.js +20 -0
  28. package/templates/VehicleRentalReservationSystem/backend-project/routes/dashboard.routes.js +6 -0
  29. package/templates/VehicleRentalReservationSystem/backend-project/routes/report.routes.js +6 -0
  30. package/templates/VehicleRentalReservationSystem/backend-project/routes/reservation.routes.js +14 -0
  31. package/templates/VehicleRentalReservationSystem/backend-project/routes/user.routes.js +10 -0
  32. package/templates/VehicleRentalReservationSystem/backend-project/routes/vehicle.routes.js +21 -0
  33. package/templates/VehicleRentalReservationSystem/backend-project/seed/seed.js +80 -0
  34. package/templates/VehicleRentalReservationSystem/backend-project/server.js +40 -0
  35. package/templates/VehicleRentalReservationSystem/backend-project/utils/token.js +3 -0
  36. package/templates/VehicleRentalReservationSystem/frontend-project/index.html +14 -0
  37. package/templates/VehicleRentalReservationSystem/frontend-project/package-lock.json +3759 -0
  38. package/templates/VehicleRentalReservationSystem/frontend-project/package.json +32 -0
  39. package/templates/VehicleRentalReservationSystem/frontend-project/postcss.config.js +1 -0
  40. package/templates/VehicleRentalReservationSystem/frontend-project/src/App.jsx +33 -0
  41. package/templates/VehicleRentalReservationSystem/frontend-project/src/components/ConfirmDelete.jsx +12 -0
  42. package/templates/VehicleRentalReservationSystem/frontend-project/src/components/Modal.jsx +22 -0
  43. package/templates/VehicleRentalReservationSystem/frontend-project/src/components/ProtectedRoute.jsx +9 -0
  44. package/templates/VehicleRentalReservationSystem/frontend-project/src/components/Sidebar.jsx +42 -0
  45. package/templates/VehicleRentalReservationSystem/frontend-project/src/components/Topbar.jsx +24 -0
  46. package/templates/VehicleRentalReservationSystem/frontend-project/src/context/AuthContext.jsx +30 -0
  47. package/templates/VehicleRentalReservationSystem/frontend-project/src/context/ThemeContext.jsx +13 -0
  48. package/templates/VehicleRentalReservationSystem/frontend-project/src/index.css +37 -0
  49. package/templates/VehicleRentalReservationSystem/frontend-project/src/layouts/AppLayout.jsx +18 -0
  50. package/templates/VehicleRentalReservationSystem/frontend-project/src/main.jsx +20 -0
  51. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Customers.jsx +95 -0
  52. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Dashboard.jsx +84 -0
  53. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Login.jsx +54 -0
  54. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Register.jsx +36 -0
  55. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Rentals.jsx +58 -0
  56. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Reports.jsx +108 -0
  57. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Reservations.jsx +125 -0
  58. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Settings.jsx +32 -0
  59. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Users.jsx +78 -0
  60. package/templates/VehicleRentalReservationSystem/frontend-project/src/pages/Vehicles.jsx +110 -0
  61. package/templates/VehicleRentalReservationSystem/frontend-project/src/services/api.js +16 -0
  62. package/templates/VehicleRentalReservationSystem/frontend-project/src/utils/format.js +20 -0
  63. package/templates/VehicleRentalReservationSystem/frontend-project/tailwind.config.js +18 -0
  64. package/templates/VehicleRentalReservationSystem/frontend-project/vite.config.js +9 -0
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "vrs-backend",
3
+ "version": "1.0.0",
4
+ "description": "Vehicle Rental & Reservation System - Backend",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "start": "node server.js",
8
+ "dev": "nodemon server.js",
9
+ "seed": "node seed/seed.js"
10
+ },
11
+ "dependencies": {
12
+ "bcryptjs": "^2.4.3",
13
+ "cors": "^2.8.5",
14
+ "dotenv": "^16.3.1",
15
+ "express": "^4.18.2",
16
+ "express-rate-limit": "^7.1.5",
17
+ "express-validator": "^7.0.1",
18
+ "helmet": "^7.1.0",
19
+ "jsonwebtoken": "^9.0.2",
20
+ "mongoose": "^8.0.3",
21
+ "morgan": "^1.10.0"
22
+ },
23
+ "devDependencies": {
24
+ "nodemon": "^3.0.2"
25
+ }
26
+ }
@@ -0,0 +1,21 @@
1
+ const router = require('express').Router();
2
+ const { body } = require('express-validator');
3
+ const c = require('../controllers/auth.controller');
4
+ const validate = require('../middleware/validate');
5
+ const { protect } = require('../middleware/auth');
6
+
7
+ router.post('/register', [
8
+ body('username').isLength({ min: 3 }),
9
+ body('password').isLength({ min: 6 }),
10
+ body('role').optional().isIn(['ADMIN','STAFF','MANAGER'])
11
+ ], validate, c.register);
12
+
13
+ router.post('/login', [
14
+ body('username').notEmpty(),
15
+ body('password').notEmpty()
16
+ ], validate, c.login);
17
+
18
+ router.post('/refresh', c.refresh);
19
+ router.post('/logout', c.logout);
20
+ router.get('/me', protect, c.me);
21
+ module.exports = router;
@@ -0,0 +1,20 @@
1
+ const router = require('express').Router();
2
+ const { body } = require('express-validator');
3
+ const c = require('../controllers/customer.controller');
4
+ const validate = require('../middleware/validate');
5
+ const { protect, authorize } = require('../middleware/auth');
6
+
7
+ router.use(protect);
8
+ const rules = [
9
+ body('fullName').notEmpty().withMessage('Full name required'),
10
+ body('nationalId').isLength({ min: 6 }).withMessage('Invalid National ID'),
11
+ body('phone').matches(/^[+0-9\s-]{7,20}$/).withMessage('Invalid phone'),
12
+ body('email').isEmail().withMessage('Invalid email'),
13
+ body('address').notEmpty()
14
+ ];
15
+ router.get('/', c.list);
16
+ router.get('/:id', c.get);
17
+ router.post('/', authorize('ADMIN','STAFF'), rules, validate, c.create);
18
+ router.put('/:id', authorize('ADMIN','STAFF'), c.update);
19
+ router.delete('/:id', authorize('ADMIN'), c.remove);
20
+ module.exports = router;
@@ -0,0 +1,6 @@
1
+ const router = require('express').Router();
2
+ const c = require('../controllers/dashboard.controller');
3
+ const { protect } = require('../middleware/auth');
4
+ router.use(protect);
5
+ router.get('/', c.stats);
6
+ module.exports = router;
@@ -0,0 +1,6 @@
1
+ const router = require('express').Router();
2
+ const c = require('../controllers/report.controller');
3
+ const { protect, authorize } = require('../middleware/auth');
4
+ router.use(protect, authorize('ADMIN','MANAGER','STAFF'));
5
+ router.get('/', c.generate);
6
+ module.exports = router;
@@ -0,0 +1,14 @@
1
+ const router = require('express').Router();
2
+ const c = require('../controllers/reservation.controller');
3
+ const { protect, authorize } = require('../middleware/auth');
4
+ router.use(protect);
5
+ router.get('/', c.list);
6
+ router.get('/:id', c.get);
7
+ router.post('/', authorize('ADMIN','STAFF'), c.create);
8
+ router.put('/:id', authorize('ADMIN','STAFF'), c.update);
9
+ router.delete('/:id', authorize('ADMIN'), c.remove);
10
+ router.patch('/:id/approve', authorize('ADMIN','MANAGER'), c.approve);
11
+ router.patch('/:id/reject', authorize('ADMIN','MANAGER'), c.reject);
12
+ router.patch('/:id/pickup', authorize('ADMIN','STAFF'), c.pickup);
13
+ router.patch('/:id/return', authorize('ADMIN','STAFF'), c.returnVehicle);
14
+ module.exports = router;
@@ -0,0 +1,10 @@
1
+ const router = require('express').Router();
2
+ const c = require('../controllers/user.controller');
3
+ const { protect, authorize } = require('../middleware/auth');
4
+ router.use(protect, authorize('ADMIN'));
5
+ router.get('/', c.list);
6
+ router.get('/:id', c.get);
7
+ router.post('/', c.create);
8
+ router.put('/:id', c.update);
9
+ router.delete('/:id', c.remove);
10
+ module.exports = router;
@@ -0,0 +1,21 @@
1
+ const router = require('express').Router();
2
+ const { body } = require('express-validator');
3
+ const c = require('../controllers/vehicle.controller');
4
+ const validate = require('../middleware/validate');
5
+ const { protect, authorize } = require('../middleware/auth');
6
+
7
+ router.use(protect);
8
+ const rules = [
9
+ body('plateNumber').notEmpty(),
10
+ body('brand').notEmpty(),
11
+ body('model').notEmpty(),
12
+ body('year').isInt({ min: 1980 }),
13
+ body('vehicleType').notEmpty(),
14
+ body('purchasePrice').isFloat({ min: 0 })
15
+ ];
16
+ router.get('/', c.list);
17
+ router.get('/:id', c.get);
18
+ router.post('/', authorize('ADMIN'), rules, validate, c.create);
19
+ router.put('/:id', authorize('ADMIN'), c.update);
20
+ router.delete('/:id', authorize('ADMIN'), c.remove);
21
+ module.exports = router;
@@ -0,0 +1,80 @@
1
+ require('dotenv').config();
2
+ const mongoose = require('mongoose');
3
+ const connectDB = require('../config/db');
4
+ const User = require('../models/User');
5
+ const Customer = require('../models/Customer');
6
+ const Vehicle = require('../models/Vehicle');
7
+ const RR = require('../models/ReservationRental');
8
+
9
+ const firstNames = ['Jean','Eric','Aline','Claudine','Patrick','Diane','Olivier','Sandrine','Emmanuel','Yvette','Pacifique','Ange','Fabrice','Solange','Innocent','Beatrice','Theodore','Josiane','Felix','Mireille'];
10
+ const lastNames = ['Uwase','Niyonsenga','Mukamana','Habimana','Iradukunda','Mugisha','Ndayisaba','Ingabire','Tuyishime','Rugamba','Mutuyimana','Nzeyimana','Kayitesi','Bizimana','Munyaneza','Hakizimana','Uwimana','Mukantwari','Nshimiyimana','Twagirayezu'];
11
+ const types = ['Sedan','SUV','Hatchback','Pickup','Van','Bus','Truck','Coupe'];
12
+ const brands = [['Toyota','Corolla'],['Toyota','Hilux'],['Honda','Civic'],['Nissan','Patrol'],['Hyundai','Tucson'],['Kia','Sportage'],['Ford','Ranger'],['Mazda','CX-5'],['Mitsubishi','Pajero'],['Suzuki','Vitara']];
13
+
14
+ const rand = (a) => a[Math.floor(Math.random()*a.length)];
15
+ const randInt = (a,b) => Math.floor(Math.random()*(b-a+1))+a;
16
+
17
+ (async () => {
18
+ await connectDB();
19
+ console.log('Clearing collections...');
20
+ await Promise.all([User.deleteMany(), Customer.deleteMany(), Vehicle.deleteMany(), RR.deleteMany()]);
21
+
22
+ console.log('Creating users...');
23
+ const users = await User.create([
24
+ { username: 'admin', password: 'admin123', fullName: 'System Administrator', email: 'admin@swiftwheels.rw', role: 'ADMIN' },
25
+ { username: 'manager', password: 'manager123', fullName: 'Operations Manager', email: 'manager@swiftwheels.rw', role: 'MANAGER' },
26
+ { username: 'staff', password: 'staff123', fullName: 'Front Desk Staff', email: 'staff@swiftwheels.rw', role: 'STAFF' }
27
+ ]);
28
+
29
+ console.log('Creating 20 customers...');
30
+ const customers = [];
31
+ for (let i = 0; i < 20; i++) {
32
+ const fn = rand(firstNames), ln = rand(lastNames);
33
+ customers.push(await Customer.create({
34
+ fullName: `${fn} ${ln}`,
35
+ nationalId: '1' + (199500000000 + i * 137 + randInt(0,9)).toString(),
36
+ phone: '+25078' + randInt(1000000, 9999999),
37
+ email: `${fn.toLowerCase()}.${ln.toLowerCase()}${i}@example.rw`,
38
+ address: rand(['Huye','Kigali','Musanze','Rubavu','Nyagatare','Muhanga']) + ', Rwanda'
39
+ }));
40
+ }
41
+
42
+ console.log('Creating 20 vehicles...');
43
+ const vehicles = [];
44
+ for (let i = 0; i < 20; i++) {
45
+ const [brand, model] = rand(brands);
46
+ vehicles.push(await Vehicle.create({
47
+ plateNumber: 'RAB' + randInt(100,999) + String.fromCharCode(65+randInt(0,25)),
48
+ brand, model, year: randInt(2015, 2024),
49
+ vehicleType: rand(types),
50
+ purchasePrice: randInt(15000, 60000),
51
+ dailyRate: randInt(40, 200),
52
+ status: 'AVAILABLE'
53
+ }));
54
+ }
55
+
56
+ console.log('Creating 30 reservations...');
57
+ const statuses = ['PENDING','APPROVED','COMPLETED','REJECTED','CANCELLED'];
58
+ for (let i = 0; i < 30; i++) {
59
+ const start = new Date(); start.setDate(start.getDate() - randInt(-15, 60));
60
+ const end = new Date(start); end.setDate(end.getDate() + randInt(1, 10));
61
+ const days = Math.max(1, Math.ceil((end-start)/86400000));
62
+ const v = rand(vehicles);
63
+ const status = rand(statuses);
64
+ await RR.create({
65
+ customerId: rand(customers)._id,
66
+ vehicleId: v._id,
67
+ userId: rand(users)._id,
68
+ startDate: start, endDate: end,
69
+ reservationStatus: status,
70
+ rentalDate: status === 'COMPLETED' ? start : null,
71
+ returnDate: status === 'COMPLETED' ? end : null,
72
+ rentalStatus: status === 'COMPLETED' ? 'RETURNED' : 'NOT_STARTED',
73
+ rentalFee: days * v.dailyRate
74
+ });
75
+ }
76
+
77
+ console.log('✅ Seed complete');
78
+ console.log('Login: admin/admin123, manager/manager123, staff/staff123');
79
+ await mongoose.disconnect();
80
+ })();
@@ -0,0 +1,40 @@
1
+ require('dotenv').config();
2
+ const express = require('express');
3
+ const cors = require('cors');
4
+ const helmet = require('helmet');
5
+ const morgan = require('morgan');
6
+ const rateLimit = require('express-rate-limit');
7
+ const connectDB = require('./config/db');
8
+
9
+ const authRoutes = require('./routes/auth.routes');
10
+ const customerRoutes = require('./routes/customer.routes');
11
+ const vehicleRoutes = require('./routes/vehicle.routes');
12
+ const reservationRoutes = require('./routes/reservation.routes');
13
+ const userRoutes = require('./routes/user.routes');
14
+ const reportRoutes = require('./routes/report.routes');
15
+ const dashboardRoutes = require('./routes/dashboard.routes');
16
+ const errorHandler = require('./middleware/errorHandler');
17
+
18
+ const app = express();
19
+ connectDB();
20
+
21
+ app.use(helmet());
22
+ app.use(cors({ origin: process.env.CLIENT_URL || '*', credentials: true }));
23
+ app.use(express.json({ limit: '5mb' }));
24
+ app.use(morgan('dev'));
25
+ app.use('/api/', rateLimit({ windowMs: 15 * 60 * 1000, max: 500 }));
26
+
27
+ app.get('/', (req, res) => res.json({ message: 'VRS API running', version: '1.0.0' }));
28
+ app.use('/api/auth', authRoutes);
29
+ app.use('/api/customers', customerRoutes);
30
+ app.use('/api/vehicles', vehicleRoutes);
31
+ app.use('/api/reservations', reservationRoutes);
32
+ app.use('/api/users', userRoutes);
33
+ app.use('/api/reports', reportRoutes);
34
+ app.use('/api/dashboard', dashboardRoutes);
35
+
36
+ app.use((req, res) => res.status(404).json({ message: 'Route not found' }));
37
+ app.use(errorHandler);
38
+
39
+ const PORT = process.env.PORT || 5000;
40
+ app.listen(PORT, () => console.log(`🚗 VRS Backend running on port ${PORT}`));
@@ -0,0 +1,3 @@
1
+ const jwt = require('jsonwebtoken');
2
+ exports.signAccess = (user) => jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES_IN || '1d' });
3
+ exports.signRefresh = (user) => jwt.sign({ id: user._id }, process.env.JWT_REFRESH_SECRET, { expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d' });
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>SwiftWheels VRS</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ <script type="module" src="/src/main.jsx"></script>
13
+ </body>
14
+ </html>