create-ishvexa-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.
- package/index.js +62 -0
- package/package.json +14 -0
- package/templates/epms-app/.env +7 -0
- package/templates/epms-app/README.md +113 -0
- package/templates/epms-app/backend-mongodb/.env +3 -0
- package/templates/epms-app/backend-mongodb/.env.example +3 -0
- package/templates/epms-app/backend-mongodb/config/db.js +29 -0
- package/templates/epms-app/backend-mongodb/controllers/authController.js +93 -0
- package/templates/epms-app/backend-mongodb/controllers/departmentController.js +24 -0
- package/templates/epms-app/backend-mongodb/controllers/employeeController.js +39 -0
- package/templates/epms-app/backend-mongodb/controllers/reportController.js +57 -0
- package/templates/epms-app/backend-mongodb/controllers/salaryController.js +101 -0
- package/templates/epms-app/backend-mongodb/middleware/auth.js +16 -0
- package/templates/epms-app/backend-mongodb/models/Counter.js +13 -0
- package/templates/epms-app/backend-mongodb/models/Department.js +11 -0
- package/templates/epms-app/backend-mongodb/models/Employee.js +18 -0
- package/templates/epms-app/backend-mongodb/models/Salary.js +19 -0
- package/templates/epms-app/backend-mongodb/models/User.js +9 -0
- package/templates/epms-app/backend-mongodb/package-lock.json +1571 -0
- package/templates/epms-app/backend-mongodb/package.json +22 -0
- package/templates/epms-app/backend-mongodb/routes/authRoutes.js +8 -0
- package/templates/epms-app/backend-mongodb/routes/departmentRoutes.js +6 -0
- package/templates/epms-app/backend-mongodb/routes/employeeRoutes.js +6 -0
- package/templates/epms-app/backend-mongodb/routes/reportRoutes.js +5 -0
- package/templates/epms-app/backend-mongodb/routes/salaryRoutes.js +8 -0
- package/templates/epms-app/backend-mongodb/server.js +39 -0
- package/templates/epms-app/backend-mysql/.env +7 -0
- package/templates/epms-app/backend-mysql/.env.example +7 -0
- package/templates/epms-app/backend-mysql/config/db.js +33 -0
- package/templates/epms-app/backend-mysql/controllers/authController.js +98 -0
- package/templates/epms-app/backend-mysql/controllers/departmentController.js +25 -0
- package/templates/epms-app/backend-mysql/controllers/employeeController.js +39 -0
- package/templates/epms-app/backend-mysql/controllers/reportController.js +41 -0
- package/templates/epms-app/backend-mysql/controllers/salaryController.js +93 -0
- package/templates/epms-app/backend-mysql/database/schema.sql +7 -0
- package/templates/epms-app/backend-mysql/middleware/auth.js +16 -0
- package/templates/epms-app/backend-mysql/package-lock.json +1486 -0
- package/templates/epms-app/backend-mysql/package.json +23 -0
- package/templates/epms-app/backend-mysql/routes/authRoutes.js +8 -0
- package/templates/epms-app/backend-mysql/routes/departmentRoutes.js +6 -0
- package/templates/epms-app/backend-mysql/routes/employeeRoutes.js +6 -0
- package/templates/epms-app/backend-mysql/routes/reportRoutes.js +5 -0
- package/templates/epms-app/backend-mysql/routes/salaryRoutes.js +8 -0
- package/templates/epms-app/backend-mysql/server.js +39 -0
- package/templates/epms-app/frontend/README.md +16 -0
- package/templates/epms-app/frontend/eslint.config.js +21 -0
- package/templates/epms-app/frontend/index.html +12 -0
- package/templates/epms-app/frontend/package-lock.json +3033 -0
- package/templates/epms-app/frontend/package.json +23 -0
- package/templates/epms-app/frontend/public/favicon.svg +1 -0
- package/templates/epms-app/frontend/public/icons.svg +24 -0
- package/templates/epms-app/frontend/src/App.css +184 -0
- package/templates/epms-app/frontend/src/App.jsx +31 -0
- package/templates/epms-app/frontend/src/api/authApi.js +7 -0
- package/templates/epms-app/frontend/src/api/client.js +11 -0
- package/templates/epms-app/frontend/src/api/departmentApi.js +5 -0
- package/templates/epms-app/frontend/src/api/employeeApi.js +4 -0
- package/templates/epms-app/frontend/src/api/reportApi.js +4 -0
- package/templates/epms-app/frontend/src/api/salaryApi.js +6 -0
- package/templates/epms-app/frontend/src/api/sparePartsApi.js +3 -0
- package/templates/epms-app/frontend/src/api/usersApi.js +4 -0
- package/templates/epms-app/frontend/src/assets/hero.png +0 -0
- package/templates/epms-app/frontend/src/assets/react.svg +1 -0
- package/templates/epms-app/frontend/src/assets/vite.svg +1 -0
- package/templates/epms-app/frontend/src/components/AppLayout.jsx +49 -0
- package/templates/epms-app/frontend/src/context/AuthContext.jsx +41 -0
- package/templates/epms-app/frontend/src/hooks/.gitkeep +0 -0
- package/templates/epms-app/frontend/src/index.css +2 -0
- package/templates/epms-app/frontend/src/main.jsx +16 -0
- package/templates/epms-app/frontend/src/pages/DepartmentPage.jsx +165 -0
- package/templates/epms-app/frontend/src/pages/DepartmentsPage.jsx +119 -0
- package/templates/epms-app/frontend/src/pages/EmployeePage.jsx +212 -0
- package/templates/epms-app/frontend/src/pages/EmployeesPage.jsx +217 -0
- package/templates/epms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
- package/templates/epms-app/frontend/src/pages/LoginPage.jsx +105 -0
- package/templates/epms-app/frontend/src/pages/RegisterPage.jsx +84 -0
- package/templates/epms-app/frontend/src/pages/ReportsPage.jsx +192 -0
- package/templates/epms-app/frontend/src/pages/ResetPasswordPage.jsx +83 -0
- package/templates/epms-app/frontend/src/pages/SalariesPage.jsx +274 -0
- package/templates/epms-app/frontend/src/pages/SalaryPage.jsx +254 -0
- package/templates/epms-app/frontend/vite.config.js +8 -0
- package/templates/lms-app/.env +9 -0
- package/templates/lms-app/README.md +89 -0
- package/templates/lms-app/backend-mongodb/.env +5 -0
- package/templates/lms-app/backend-mongodb/.env.example +5 -0
- package/templates/lms-app/backend-mongodb/package-lock.json +1583 -0
- package/templates/lms-app/backend-mongodb/package.json +26 -0
- package/templates/lms-app/backend-mongodb/src/config/db.js +10 -0
- package/templates/lms-app/backend-mongodb/src/config/env.js +28 -0
- package/templates/lms-app/backend-mongodb/src/controllers/authController.js +86 -0
- package/templates/lms-app/backend-mongodb/src/controllers/bookController.js +101 -0
- package/templates/lms-app/backend-mongodb/src/controllers/borrowController.js +106 -0
- package/templates/lms-app/backend-mongodb/src/controllers/dashboardController.js +40 -0
- package/templates/lms-app/backend-mongodb/src/controllers/reportController.js +47 -0
- package/templates/lms-app/backend-mongodb/src/controllers/studentController.js +92 -0
- package/templates/lms-app/backend-mongodb/src/ensureSeedData.js +72 -0
- package/templates/lms-app/backend-mongodb/src/middleware/auth.js +29 -0
- package/templates/lms-app/backend-mongodb/src/models/Book.js +14 -0
- package/templates/lms-app/backend-mongodb/src/models/Borrow.js +16 -0
- package/templates/lms-app/backend-mongodb/src/models/Student.js +14 -0
- package/templates/lms-app/backend-mongodb/src/models/User.js +13 -0
- package/templates/lms-app/backend-mongodb/src/routes/authRoutes.js +12 -0
- package/templates/lms-app/backend-mongodb/src/routes/bookRoutes.js +13 -0
- package/templates/lms-app/backend-mongodb/src/routes/borrowRoutes.js +11 -0
- package/templates/lms-app/backend-mongodb/src/routes/dashboardRoutes.js +9 -0
- package/templates/lms-app/backend-mongodb/src/routes/reportRoutes.js +12 -0
- package/templates/lms-app/backend-mongodb/src/routes/studentRoutes.js +13 -0
- package/templates/lms-app/backend-mongodb/src/seed.js +16 -0
- package/templates/lms-app/backend-mongodb/src/server.js +66 -0
- package/templates/lms-app/backend-mysql/.env +9 -0
- package/templates/lms-app/backend-mysql/.env.example +9 -0
- package/templates/lms-app/backend-mysql/database/schema.sql +45 -0
- package/templates/lms-app/backend-mysql/package-lock.json +1462 -0
- package/templates/lms-app/backend-mysql/package.json +23 -0
- package/templates/lms-app/backend-mysql/src/config/db.js +33 -0
- package/templates/lms-app/backend-mysql/src/config/env.js +21 -0
- package/templates/lms-app/backend-mysql/src/controllers/authController.js +87 -0
- package/templates/lms-app/backend-mysql/src/controllers/bookController.js +106 -0
- package/templates/lms-app/backend-mysql/src/controllers/borrowController.js +113 -0
- package/templates/lms-app/backend-mysql/src/controllers/dashboardController.js +33 -0
- package/templates/lms-app/backend-mysql/src/controllers/reportController.js +40 -0
- package/templates/lms-app/backend-mysql/src/controllers/studentController.js +95 -0
- package/templates/lms-app/backend-mysql/src/ensureSeedData.js +54 -0
- package/templates/lms-app/backend-mysql/src/middleware/auth.js +28 -0
- package/templates/lms-app/backend-mysql/src/routes/authRoutes.js +12 -0
- package/templates/lms-app/backend-mysql/src/routes/bookRoutes.js +13 -0
- package/templates/lms-app/backend-mysql/src/routes/borrowRoutes.js +11 -0
- package/templates/lms-app/backend-mysql/src/routes/dashboardRoutes.js +9 -0
- package/templates/lms-app/backend-mysql/src/routes/reportRoutes.js +12 -0
- package/templates/lms-app/backend-mysql/src/routes/studentRoutes.js +13 -0
- package/templates/lms-app/backend-mysql/src/server.js +69 -0
- package/templates/lms-app/backend-mysql/src/utils/mappers.js +73 -0
- package/templates/lms-app/frontend/.env.example +5 -0
- package/templates/lms-app/frontend/index.html +13 -0
- package/templates/lms-app/frontend/package-lock.json +1592 -0
- package/templates/lms-app/frontend/package.json +23 -0
- package/templates/lms-app/frontend/public/favicon.svg +4 -0
- package/templates/lms-app/frontend/src/App.jsx +107 -0
- package/templates/lms-app/frontend/src/api/authApi.js +5 -0
- package/templates/lms-app/frontend/src/api/booksApi.js +6 -0
- package/templates/lms-app/frontend/src/api/borrowsApi.js +5 -0
- package/templates/lms-app/frontend/src/api/client.js +8 -0
- package/templates/lms-app/frontend/src/api/dashboardApi.js +3 -0
- package/templates/lms-app/frontend/src/api/reportsApi.js +6 -0
- package/templates/lms-app/frontend/src/api/studentsApi.js +6 -0
- package/templates/lms-app/frontend/src/components/AppLayout.jsx +63 -0
- package/templates/lms-app/frontend/src/index.css +34 -0
- package/templates/lms-app/frontend/src/main.jsx +13 -0
- package/templates/lms-app/frontend/src/pages/BooksPage.jsx +206 -0
- package/templates/lms-app/frontend/src/pages/BorrowPage.jsx +134 -0
- package/templates/lms-app/frontend/src/pages/DashboardPage.jsx +42 -0
- package/templates/lms-app/frontend/src/pages/ForgotPassword.jsx +112 -0
- package/templates/lms-app/frontend/src/pages/LoginPage.jsx +71 -0
- package/templates/lms-app/frontend/src/pages/ReportsPage.jsx +176 -0
- package/templates/lms-app/frontend/src/pages/ReturnPage.jsx +75 -0
- package/templates/lms-app/frontend/src/pages/SearchPage.jsx +156 -0
- package/templates/lms-app/frontend/src/pages/StudentsPage.jsx +204 -0
- package/templates/lms-app/frontend/vite.config.js +26 -0
- package/templates/scms-app/.env +7 -0
- package/templates/scms-app/README.md +80 -0
- package/templates/scms-app/backend-mongodb/.env +3 -0
- package/templates/scms-app/backend-mongodb/.env.example +3 -0
- package/templates/scms-app/backend-mongodb/config/db.js +29 -0
- package/templates/scms-app/backend-mongodb/controllers/authController.js +93 -0
- package/templates/scms-app/backend-mongodb/controllers/deliveryController.js +65 -0
- package/templates/scms-app/backend-mongodb/controllers/reportController.js +51 -0
- package/templates/scms-app/backend-mongodb/controllers/shipmentController.js +65 -0
- package/templates/scms-app/backend-mongodb/controllers/supplierController.js +27 -0
- package/templates/scms-app/backend-mongodb/middleware/auth.js +16 -0
- package/templates/scms-app/backend-mongodb/models/Delivery.js +14 -0
- package/templates/scms-app/backend-mongodb/models/Shipment.js +14 -0
- package/templates/scms-app/backend-mongodb/models/Supplier.js +14 -0
- package/templates/scms-app/backend-mongodb/models/User.js +9 -0
- package/templates/scms-app/backend-mongodb/package-lock.json +1571 -0
- package/templates/scms-app/backend-mongodb/package.json +22 -0
- package/templates/scms-app/backend-mongodb/routes/authRoutes.js +8 -0
- package/templates/scms-app/backend-mongodb/routes/deliveryRoutes.js +8 -0
- package/templates/scms-app/backend-mongodb/routes/reportRoutes.js +5 -0
- package/templates/scms-app/backend-mongodb/routes/shipmentRoutes.js +8 -0
- package/templates/scms-app/backend-mongodb/routes/supplierRoutes.js +6 -0
- package/templates/scms-app/backend-mongodb/server.js +39 -0
- package/templates/scms-app/backend-mysql/.env +7 -0
- package/templates/scms-app/backend-mysql/.env.example +7 -0
- package/templates/scms-app/backend-mysql/config/db.js +33 -0
- package/templates/scms-app/backend-mysql/controllers/authController.js +98 -0
- package/templates/scms-app/backend-mysql/controllers/deliveryController.js +62 -0
- package/templates/scms-app/backend-mysql/controllers/reportController.js +39 -0
- package/templates/scms-app/backend-mysql/controllers/shipmentController.js +62 -0
- package/templates/scms-app/backend-mysql/controllers/supplierController.js +28 -0
- package/templates/scms-app/backend-mysql/database/schema.sql +7 -0
- package/templates/scms-app/backend-mysql/middleware/auth.js +16 -0
- package/templates/scms-app/backend-mysql/package-lock.json +1486 -0
- package/templates/scms-app/backend-mysql/package.json +23 -0
- package/templates/scms-app/backend-mysql/routes/authRoutes.js +8 -0
- package/templates/scms-app/backend-mysql/routes/deliveryRoutes.js +8 -0
- package/templates/scms-app/backend-mysql/routes/reportRoutes.js +5 -0
- package/templates/scms-app/backend-mysql/routes/shipmentRoutes.js +8 -0
- package/templates/scms-app/backend-mysql/routes/supplierRoutes.js +6 -0
- package/templates/scms-app/backend-mysql/server.js +39 -0
- package/templates/scms-app/frontend/index.html +12 -0
- package/templates/scms-app/frontend/package-lock.json +1634 -0
- package/templates/scms-app/frontend/package.json +23 -0
- package/templates/scms-app/frontend/src/App.jsx +31 -0
- package/templates/scms-app/frontend/src/api/client.js +11 -0
- package/templates/scms-app/frontend/src/components/AppLayout.jsx +49 -0
- package/templates/scms-app/frontend/src/context/AuthContext.jsx +41 -0
- package/templates/scms-app/frontend/src/hooks/.gitkeep +0 -0
- package/templates/scms-app/frontend/src/index.css +2 -0
- package/templates/scms-app/frontend/src/main.jsx +16 -0
- package/templates/scms-app/frontend/src/pages/DeliveriesPage.jsx +265 -0
- package/templates/scms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
- package/templates/scms-app/frontend/src/pages/LoginPage.jsx +105 -0
- package/templates/scms-app/frontend/src/pages/ReportsPage.jsx +192 -0
- package/templates/scms-app/frontend/src/pages/ShipmentsPage.jsx +259 -0
- package/templates/scms-app/frontend/src/pages/SuppliersPage.jsx +168 -0
- package/templates/scms-app/frontend/vite.config.js +8 -0
- package/templates/sfms-app/.env +7 -0
- package/templates/sfms-app/README.md +72 -0
- package/templates/sfms-app/backend-mongodb/.env +3 -0
- package/templates/sfms-app/backend-mongodb/.env.example +3 -0
- package/templates/sfms-app/backend-mongodb/package-lock.json +1580 -0
- package/templates/sfms-app/backend-mongodb/package.json +23 -0
- package/templates/sfms-app/backend-mongodb/src/config/database.js +7 -0
- package/templates/sfms-app/backend-mongodb/src/config/env.js +35 -0
- package/templates/sfms-app/backend-mongodb/src/middleware/authMiddleware.js +32 -0
- package/templates/sfms-app/backend-mongodb/src/models/Payment.js +12 -0
- package/templates/sfms-app/backend-mongodb/src/models/Student.js +12 -0
- package/templates/sfms-app/backend-mongodb/src/models/User.js +14 -0
- package/templates/sfms-app/backend-mongodb/src/routes/authRoutes.js +140 -0
- package/templates/sfms-app/backend-mongodb/src/routes/paymentRoutes.js +117 -0
- package/templates/sfms-app/backend-mongodb/src/routes/reportRoutes.js +59 -0
- package/templates/sfms-app/backend-mongodb/src/routes/studentRoutes.js +79 -0
- package/templates/sfms-app/backend-mongodb/src/server.js +34 -0
- package/templates/sfms-app/backend-mysql/.env +7 -0
- package/templates/sfms-app/backend-mysql/.env.example +7 -0
- package/templates/sfms-app/backend-mysql/database/schema.sql +29 -0
- package/templates/sfms-app/backend-mysql/package-lock.json +1467 -0
- package/templates/sfms-app/backend-mysql/package.json +24 -0
- package/templates/sfms-app/backend-mysql/src/config/.gitkeep +0 -0
- package/templates/sfms-app/backend-mysql/src/config/db.js +31 -0
- package/templates/sfms-app/backend-mysql/src/config/env.js +20 -0
- package/templates/sfms-app/backend-mysql/src/middleware/.gitkeep +0 -0
- package/templates/sfms-app/backend-mysql/src/middleware/authMiddleware.js +26 -0
- package/templates/sfms-app/backend-mysql/src/models/.gitkeep +0 -0
- package/templates/sfms-app/backend-mysql/src/routes/.gitkeep +0 -0
- package/templates/sfms-app/backend-mysql/src/routes/authRoutes.js +131 -0
- package/templates/sfms-app/backend-mysql/src/routes/paymentRoutes.js +92 -0
- package/templates/sfms-app/backend-mysql/src/routes/reportRoutes.js +41 -0
- package/templates/sfms-app/backend-mysql/src/routes/studentRoutes.js +75 -0
- package/templates/sfms-app/backend-mysql/src/server.js +39 -0
- package/templates/sfms-app/backend-mysql/src/utils/mappers.js +43 -0
- package/templates/sfms-app/frontend/.env.example +9 -0
- package/templates/sfms-app/frontend/index.html +19 -0
- package/templates/sfms-app/frontend/package-lock.json +2667 -0
- package/templates/sfms-app/frontend/package.json +23 -0
- package/templates/sfms-app/frontend/postcss.config.js +6 -0
- package/templates/sfms-app/frontend/public/favicon.svg +4 -0
- package/templates/sfms-app/frontend/src/App.jsx +38 -0
- package/templates/sfms-app/frontend/src/api/apiClient.js +54 -0
- package/templates/sfms-app/frontend/src/components/AppLayout.jsx +61 -0
- package/templates/sfms-app/frontend/src/context/AuthContext.jsx +87 -0
- package/templates/sfms-app/frontend/src/index.css +7 -0
- package/templates/sfms-app/frontend/src/main.jsx +16 -0
- package/templates/sfms-app/frontend/src/pages/DashboardPage.jsx +78 -0
- package/templates/sfms-app/frontend/src/pages/ForgotPassword.jsx +114 -0
- package/templates/sfms-app/frontend/src/pages/LoginPage.jsx +141 -0
- package/templates/sfms-app/frontend/src/pages/PaymentsPage.jsx +309 -0
- package/templates/sfms-app/frontend/src/pages/ReportsPage.jsx +123 -0
- package/templates/sfms-app/frontend/src/pages/StudentsPage.jsx +281 -0
- package/templates/sfms-app/frontend/tailwind.config.js +21 -0
- package/templates/sfms-app/frontend/vite.config.js +61 -0
- package/templates/sims-app/README.md +138 -0
- package/templates/sims-app/backend/.env +4 -0
- package/templates/sims-app/backend/.env.example +4 -0
- package/templates/sims-app/backend/package.json +22 -0
- package/templates/sims-app/backend/src/config/db.js +9 -0
- package/templates/sims-app/backend/src/controllers/authController.js +115 -0
- package/templates/sims-app/backend/src/controllers/simsReportController.js +94 -0
- package/templates/sims-app/backend/src/controllers/sparePartController.js +41 -0
- package/templates/sims-app/backend/src/controllers/stockInController.js +45 -0
- package/templates/sims-app/backend/src/controllers/stockOutController.js +123 -0
- package/templates/sims-app/backend/src/middleware/auth.js +8 -0
- package/templates/sims-app/backend/src/models/SparePart.js +17 -0
- package/templates/sims-app/backend/src/models/StockIn.js +16 -0
- package/templates/sims-app/backend/src/models/StockOut.js +18 -0
- package/templates/sims-app/backend/src/models/User.js +12 -0
- package/templates/sims-app/backend/src/routes/authRoutes.js +12 -0
- package/templates/sims-app/backend/src/routes/simsReportRoutes.js +8 -0
- package/templates/sims-app/backend/src/routes/sparePartRoutes.js +8 -0
- package/templates/sims-app/backend/src/routes/stockInRoutes.js +8 -0
- package/templates/sims-app/backend/src/routes/stockOutRoutes.js +10 -0
- package/templates/sims-app/backend/src/server.js +62 -0
- package/templates/sims-app/backend/src/utils/passwordPolicy.js +10 -0
- package/templates/sims-app/backend/src/utils/sparePartHelpers.js +5 -0
- package/templates/sims-app/frontend/index.html +13 -0
- package/templates/sims-app/frontend/package.json +31 -0
- package/templates/sims-app/frontend/src/App.jsx +110 -0
- package/templates/sims-app/frontend/src/api/authApi.js +7 -0
- package/templates/sims-app/frontend/src/api/client.js +8 -0
- package/templates/sims-app/frontend/src/api/simsReportApi.js +5 -0
- package/templates/sims-app/frontend/src/api/sparePartsApi.js +4 -0
- package/templates/sims-app/frontend/src/api/stockInApi.js +4 -0
- package/templates/sims-app/frontend/src/api/stockOutApi.js +6 -0
- package/templates/sims-app/frontend/src/api/usersApi.js +3 -0
- package/templates/sims-app/frontend/src/components/AppLayout.jsx +47 -0
- package/templates/sims-app/frontend/src/index.css +7 -0
- package/templates/sims-app/frontend/src/main.jsx +13 -0
- package/templates/sims-app/frontend/src/pages/ForgotPassword.jsx +111 -0
- package/templates/sims-app/frontend/src/pages/LoginPage.jsx +71 -0
- package/templates/sims-app/frontend/src/pages/RegisterPage.jsx +99 -0
- package/templates/sims-app/frontend/src/pages/ReportsPage.jsx +120 -0
- package/templates/sims-app/frontend/src/pages/SparePartPage.jsx +148 -0
- package/templates/sims-app/frontend/src/pages/StockInPage.jsx +122 -0
- package/templates/sims-app/frontend/src/pages/StockOutPage.jsx +252 -0
- package/templates/sims-app/frontend/src/utils/passwordPolicy.js +8 -0
- package/templates/sims-app/frontend/vite.config.js +8 -0
- package/templates/smartshop-app/README.md +61 -0
- package/templates/smartshop-app/backend/.env +7 -0
- package/templates/smartshop-app/backend/.env.example +7 -0
- package/templates/smartshop-app/backend/database/schema.sql +46 -0
- package/templates/smartshop-app/backend/package-lock.json +1487 -0
- package/templates/smartshop-app/backend/package.json +26 -0
- package/templates/smartshop-app/backend/src/app.js +57 -0
- package/templates/smartshop-app/backend/src/config/db.js +52 -0
- package/templates/smartshop-app/backend/src/controllers/authController.js +98 -0
- package/templates/smartshop-app/backend/src/controllers/customerController.js +26 -0
- package/templates/smartshop-app/backend/src/controllers/productController.js +21 -0
- package/templates/smartshop-app/backend/src/controllers/reportController.js +29 -0
- package/templates/smartshop-app/backend/src/controllers/saleController.js +11 -0
- package/templates/smartshop-app/backend/src/middleware/authMiddleware.js +22 -0
- package/templates/smartshop-app/backend/src/models/authModel.js +24 -0
- package/templates/smartshop-app/backend/src/models/customerModel.js +43 -0
- package/templates/smartshop-app/backend/src/models/productModel.js +37 -0
- package/templates/smartshop-app/backend/src/models/reportModel.js +56 -0
- package/templates/smartshop-app/backend/src/models/saleModel.js +54 -0
- package/templates/smartshop-app/backend/src/routes/authRoutes.js +10 -0
- package/templates/smartshop-app/backend/src/routes/customerRoutes.js +16 -0
- package/templates/smartshop-app/backend/src/routes/productRoutes.js +16 -0
- package/templates/smartshop-app/backend/src/routes/reportRoutes.js +18 -0
- package/templates/smartshop-app/backend/src/routes/saleRoutes.js +9 -0
- package/templates/smartshop-app/backend/src/server.js +19 -0
- package/templates/smartshop-app/frontend/README.md +18 -0
- package/templates/smartshop-app/frontend/eslint.config.js +21 -0
- package/templates/smartshop-app/frontend/index.html +13 -0
- package/templates/smartshop-app/frontend/package-lock.json +3415 -0
- package/templates/smartshop-app/frontend/package.json +34 -0
- package/templates/smartshop-app/frontend/public/favicon.svg +1 -0
- package/templates/smartshop-app/frontend/public/icons.svg +24 -0
- package/templates/smartshop-app/frontend/src/App.css +184 -0
- package/templates/smartshop-app/frontend/src/App.jsx +41 -0
- package/templates/smartshop-app/frontend/src/assets/hero.png +0 -0
- package/templates/smartshop-app/frontend/src/assets/react.svg +1 -0
- package/templates/smartshop-app/frontend/src/assets/vite.svg +1 -0
- package/templates/smartshop-app/frontend/src/components/AppLayout.jsx +71 -0
- package/templates/smartshop-app/frontend/src/components/FormCard.jsx +12 -0
- package/templates/smartshop-app/frontend/src/components/StatCard.jsx +10 -0
- package/templates/smartshop-app/frontend/src/index.css +28 -0
- package/templates/smartshop-app/frontend/src/main.jsx +13 -0
- package/templates/smartshop-app/frontend/src/pages/CustomersPage.jsx +175 -0
- package/templates/smartshop-app/frontend/src/pages/DashboardPage.jsx +30 -0
- package/templates/smartshop-app/frontend/src/pages/ForgotPassword.jsx +102 -0
- package/templates/smartshop-app/frontend/src/pages/LoginPage.jsx +142 -0
- package/templates/smartshop-app/frontend/src/pages/ProductsPage.jsx +165 -0
- package/templates/smartshop-app/frontend/src/pages/ReportsPage.jsx +204 -0
- package/templates/smartshop-app/frontend/src/pages/SalesPage.jsx +153 -0
- package/templates/smartshop-app/frontend/src/services/api.js +15 -0
- package/templates/smartshop-app/frontend/vite.config.js +13 -0
- package/templates/srms-app/.env +7 -0
- package/templates/srms-app/README.md +82 -0
- package/templates/srms-app/backend-mongodb/.env +3 -0
- package/templates/srms-app/backend-mongodb/.env.example +3 -0
- package/templates/srms-app/backend-mongodb/config/db.js +29 -0
- package/templates/srms-app/backend-mongodb/controllers/authController.js +93 -0
- package/templates/srms-app/backend-mongodb/controllers/customerController.js +27 -0
- package/templates/srms-app/backend-mongodb/controllers/productController.js +26 -0
- package/templates/srms-app/backend-mongodb/controllers/reportController.js +44 -0
- package/templates/srms-app/backend-mongodb/controllers/saleController.js +72 -0
- package/templates/srms-app/backend-mongodb/middleware/auth.js +16 -0
- package/templates/srms-app/backend-mongodb/models/Customer.js +14 -0
- package/templates/srms-app/backend-mongodb/models/Product.js +13 -0
- package/templates/srms-app/backend-mongodb/models/Sale.js +15 -0
- package/templates/srms-app/backend-mongodb/models/User.js +9 -0
- package/templates/srms-app/backend-mongodb/package-lock.json +1571 -0
- package/templates/srms-app/backend-mongodb/package.json +22 -0
- package/templates/srms-app/backend-mongodb/routes/authRoutes.js +8 -0
- package/templates/srms-app/backend-mongodb/routes/customerRoutes.js +6 -0
- package/templates/srms-app/backend-mongodb/routes/productRoutes.js +6 -0
- package/templates/srms-app/backend-mongodb/routes/reportRoutes.js +5 -0
- package/templates/srms-app/backend-mongodb/routes/saleRoutes.js +8 -0
- package/templates/srms-app/backend-mongodb/server.js +39 -0
- package/templates/srms-app/backend-mysql/.env +7 -0
- package/templates/srms-app/backend-mysql/.env.example +7 -0
- package/templates/srms-app/backend-mysql/config/db.js +33 -0
- package/templates/srms-app/backend-mysql/controllers/authController.js +98 -0
- package/templates/srms-app/backend-mysql/controllers/customerController.js +28 -0
- package/templates/srms-app/backend-mysql/controllers/productController.js +27 -0
- package/templates/srms-app/backend-mysql/controllers/reportController.js +29 -0
- package/templates/srms-app/backend-mysql/controllers/saleController.js +68 -0
- package/templates/srms-app/backend-mysql/database/schema.sql +7 -0
- package/templates/srms-app/backend-mysql/middleware/auth.js +16 -0
- package/templates/srms-app/backend-mysql/package-lock.json +1486 -0
- package/templates/srms-app/backend-mysql/package.json +23 -0
- package/templates/srms-app/backend-mysql/routes/authRoutes.js +8 -0
- package/templates/srms-app/backend-mysql/routes/customerRoutes.js +6 -0
- package/templates/srms-app/backend-mysql/routes/productRoutes.js +6 -0
- package/templates/srms-app/backend-mysql/routes/reportRoutes.js +5 -0
- package/templates/srms-app/backend-mysql/routes/saleRoutes.js +8 -0
- package/templates/srms-app/backend-mysql/server.js +39 -0
- package/templates/srms-app/frontend/index.html +12 -0
- package/templates/srms-app/frontend/package-lock.json +1634 -0
- package/templates/srms-app/frontend/package.json +23 -0
- package/templates/srms-app/frontend/src/App.jsx +31 -0
- package/templates/srms-app/frontend/src/api/client.js +11 -0
- package/templates/srms-app/frontend/src/components/AppLayout.jsx +40 -0
- package/templates/srms-app/frontend/src/context/AuthContext.jsx +41 -0
- package/templates/srms-app/frontend/src/hooks/.gitkeep +0 -0
- package/templates/srms-app/frontend/src/index.css +2 -0
- package/templates/srms-app/frontend/src/main.jsx +16 -0
- package/templates/srms-app/frontend/src/pages/CustomersPage.jsx +160 -0
- package/templates/srms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
- package/templates/srms-app/frontend/src/pages/LoginPage.jsx +105 -0
- package/templates/srms-app/frontend/src/pages/ProductsPage.jsx +158 -0
- package/templates/srms-app/frontend/src/pages/ReportsPage.jsx +192 -0
- package/templates/srms-app/frontend/src/pages/SalesPage.jsx +310 -0
- package/templates/srms-app/frontend/vite.config.js +8 -0
- package/templates/stockhub-sms-app/.env +7 -0
- package/templates/stockhub-sms-app/README.md +82 -0
- package/templates/stockhub-sms-app/backend-mongodb/.env +3 -0
- package/templates/stockhub-sms-app/backend-mongodb/.env.example +3 -0
- package/templates/stockhub-sms-app/backend-mongodb/config/db.js +29 -0
- package/templates/stockhub-sms-app/backend-mongodb/controllers/authController.js +93 -0
- package/templates/stockhub-sms-app/backend-mongodb/controllers/productController.js +29 -0
- package/templates/stockhub-sms-app/backend-mongodb/controllers/reportController.js +53 -0
- package/templates/stockhub-sms-app/backend-mongodb/controllers/transactionController.js +74 -0
- package/templates/stockhub-sms-app/backend-mongodb/controllers/warehouseController.js +25 -0
- package/templates/stockhub-sms-app/backend-mongodb/middleware/auth.js +16 -0
- package/templates/stockhub-sms-app/backend-mongodb/models/Counter.js +13 -0
- package/templates/stockhub-sms-app/backend-mongodb/models/Product.js +16 -0
- package/templates/stockhub-sms-app/backend-mongodb/models/StockTransaction.js +19 -0
- package/templates/stockhub-sms-app/backend-mongodb/models/User.js +9 -0
- package/templates/stockhub-sms-app/backend-mongodb/models/Warehouse.js +12 -0
- package/templates/stockhub-sms-app/backend-mongodb/package-lock.json +1571 -0
- package/templates/stockhub-sms-app/backend-mongodb/package.json +22 -0
- package/templates/stockhub-sms-app/backend-mongodb/routes/authRoutes.js +8 -0
- package/templates/stockhub-sms-app/backend-mongodb/routes/productRoutes.js +6 -0
- package/templates/stockhub-sms-app/backend-mongodb/routes/reportRoutes.js +5 -0
- package/templates/stockhub-sms-app/backend-mongodb/routes/transactionRoutes.js +8 -0
- package/templates/stockhub-sms-app/backend-mongodb/routes/warehouseRoutes.js +6 -0
- package/templates/stockhub-sms-app/backend-mongodb/server.js +39 -0
- package/templates/stockhub-sms-app/backend-mysql/.env +7 -0
- package/templates/stockhub-sms-app/backend-mysql/.env.example +7 -0
- package/templates/stockhub-sms-app/backend-mysql/config/db.js +33 -0
- package/templates/stockhub-sms-app/backend-mysql/controllers/authController.js +98 -0
- package/templates/stockhub-sms-app/backend-mysql/controllers/productController.js +30 -0
- package/templates/stockhub-sms-app/backend-mysql/controllers/reportController.js +53 -0
- package/templates/stockhub-sms-app/backend-mysql/controllers/transactionController.js +70 -0
- package/templates/stockhub-sms-app/backend-mysql/controllers/warehouseController.js +26 -0
- package/templates/stockhub-sms-app/backend-mysql/database/schema.sql +40 -0
- package/templates/stockhub-sms-app/backend-mysql/middleware/auth.js +16 -0
- package/templates/stockhub-sms-app/backend-mysql/package-lock.json +1486 -0
- package/templates/stockhub-sms-app/backend-mysql/package.json +23 -0
- package/templates/stockhub-sms-app/backend-mysql/routes/authRoutes.js +8 -0
- package/templates/stockhub-sms-app/backend-mysql/routes/productRoutes.js +6 -0
- package/templates/stockhub-sms-app/backend-mysql/routes/reportRoutes.js +5 -0
- package/templates/stockhub-sms-app/backend-mysql/routes/transactionRoutes.js +8 -0
- package/templates/stockhub-sms-app/backend-mysql/routes/warehouseRoutes.js +6 -0
- package/templates/stockhub-sms-app/backend-mysql/server.js +39 -0
- package/templates/stockhub-sms-app/frontend/index.html +12 -0
- package/templates/stockhub-sms-app/frontend/package-lock.json +1634 -0
- package/templates/stockhub-sms-app/frontend/package.json +23 -0
- package/templates/stockhub-sms-app/frontend/src/App.jsx +31 -0
- package/templates/stockhub-sms-app/frontend/src/api/client.js +11 -0
- package/templates/stockhub-sms-app/frontend/src/components/AppLayout.jsx +40 -0
- package/templates/stockhub-sms-app/frontend/src/context/AuthContext.jsx +41 -0
- package/templates/stockhub-sms-app/frontend/src/hooks/.gitkeep +0 -0
- package/templates/stockhub-sms-app/frontend/src/index.css +13 -0
- package/templates/stockhub-sms-app/frontend/src/main.jsx +16 -0
- package/templates/stockhub-sms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
- package/templates/stockhub-sms-app/frontend/src/pages/LoginPage.jsx +105 -0
- package/templates/stockhub-sms-app/frontend/src/pages/ProductsPage.jsx +132 -0
- package/templates/stockhub-sms-app/frontend/src/pages/ReportsPage.jsx +177 -0
- package/templates/stockhub-sms-app/frontend/src/pages/TransactionsPage.jsx +270 -0
- package/templates/stockhub-sms-app/frontend/src/pages/WarehousesPage.jsx +116 -0
- package/templates/stockhub-sms-app/frontend/vite.config.js +8 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sfms-backend-mysql",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SFMS API — Express + MySQL",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/server.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "node src/server.js",
|
|
9
|
+
"dev": "nodemon src/server.js",
|
|
10
|
+
"db:init": "bash -c 'set -a && source .env && set +a && if [ -n \"$DB_PASSWORD\" ]; then mysql -h \"$DB_HOST\" -P \"$DB_PORT\" -u \"$DB_USER\" -p\"$DB_PASSWORD\" < database/schema.sql; else mysql -h \"$DB_HOST\" -P \"$DB_PORT\" -u \"$DB_USER\" < database/schema.sql; fi'"
|
|
11
|
+
},
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"bcryptjs": "^2.4.3",
|
|
17
|
+
"cors": "^2.8.5",
|
|
18
|
+
"dotenv": "^16.4.5",
|
|
19
|
+
"express": "^4.21.0",
|
|
20
|
+
"jsonwebtoken": "^9.0.2",
|
|
21
|
+
"mysql2": "^3.14.1",
|
|
22
|
+
"nodemon": "^3.1.14"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import mysql from 'mysql2/promise';
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
|
|
4
|
+
const pool = mysql.createPool({
|
|
5
|
+
host: process.env.DB_HOST || 'localhost',
|
|
6
|
+
user: process.env.DB_USER || 'student',
|
|
7
|
+
password: process.env.DB_PASSWORD || '',
|
|
8
|
+
database: process.env.DB_NAME || 'SFMS',
|
|
9
|
+
port: Number(process.env.DB_PORT || 3306),
|
|
10
|
+
waitForConnections: true,
|
|
11
|
+
connectionLimit: 10,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const query = async (sql, params = []) => {
|
|
15
|
+
const [rows] = await pool.execute(sql, params);
|
|
16
|
+
return rows;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export async function connectDatabase() {
|
|
20
|
+
try {
|
|
21
|
+
await query('SELECT 1');
|
|
22
|
+
console.log('Database Connected Successfully');
|
|
23
|
+
return true;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.log('Database Connection Failed');
|
|
26
|
+
console.error(error.message);
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default pool;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const DEFAULT_BACKEND_PORT = 5000;
|
|
2
|
+
|
|
3
|
+
function parsePort(raw, fallback) {
|
|
4
|
+
const n = Number(raw);
|
|
5
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const env = {
|
|
9
|
+
port: parsePort(process.env.PORT || process.env.SFMS_BACKEND_PORT, DEFAULT_BACKEND_PORT),
|
|
10
|
+
jwtSecret: process.env.JWT_SECRET?.trim() || process.env.JWT_INGUFU?.trim() || '',
|
|
11
|
+
nodeEnv: process.env.NODE_ENV || 'development',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function requireJwtSecret() {
|
|
15
|
+
if (!env.jwtSecret) {
|
|
16
|
+
console.error('Missing JWT_SECRET in .env');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
return env.jwtSecret;
|
|
20
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import { env } from '../config/env.js';
|
|
3
|
+
import { query } from '../config/db.js';
|
|
4
|
+
|
|
5
|
+
export async function protect(req, res, next) {
|
|
6
|
+
const header = req.headers.authorization;
|
|
7
|
+
const token = header?.startsWith('Bearer ') ? header.slice(7) : null;
|
|
8
|
+
|
|
9
|
+
if (!token) {
|
|
10
|
+
return res.status(401).json({ message: 'No token provided' });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (!env.jwtSecret) throw new Error('JWT_SECRET missing');
|
|
15
|
+
|
|
16
|
+
const payload = jwt.verify(token, env.jwtSecret);
|
|
17
|
+
const rows = await query('SELECT id, role FROM users WHERE id = ?', [payload.id]);
|
|
18
|
+
if (!rows.length) {
|
|
19
|
+
return res.status(401).json({ message: 'User not found' });
|
|
20
|
+
}
|
|
21
|
+
req.user = { id: String(rows[0].id), role: rows[0].role };
|
|
22
|
+
next();
|
|
23
|
+
} catch {
|
|
24
|
+
return res.status(401).json({ message: 'Invalid or expired token' });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import bcrypt from 'bcryptjs';
|
|
3
|
+
import jwt from 'jsonwebtoken';
|
|
4
|
+
import { env } from '../config/env.js';
|
|
5
|
+
import { query } from '../config/db.js';
|
|
6
|
+
|
|
7
|
+
const router = Router();
|
|
8
|
+
|
|
9
|
+
const normalizeEmail = (email) => String(email || '').trim().toLowerCase();
|
|
10
|
+
|
|
11
|
+
function signToken(user) {
|
|
12
|
+
if (!env.jwtSecret) throw new Error('JWT_SECRET');
|
|
13
|
+
return jwt.sign({ id: String(user.id), role: user.role }, env.jwtSecret, { expiresIn: '7d' });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function toUserApi(user) {
|
|
17
|
+
return {
|
|
18
|
+
id: String(user.id),
|
|
19
|
+
username: user.username,
|
|
20
|
+
name: user.name,
|
|
21
|
+
email: user.email,
|
|
22
|
+
role: user.role,
|
|
23
|
+
created_at: user.created_at,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
router.post('/register', async (req, res) => {
|
|
28
|
+
try {
|
|
29
|
+
const { username, email, password, role } = req.body;
|
|
30
|
+
if (!username || !email || !password) {
|
|
31
|
+
return res.status(400).json({ message: 'Username, email and password are required' });
|
|
32
|
+
}
|
|
33
|
+
if (String(password).length < 6) {
|
|
34
|
+
return res.status(400).json({ message: 'Password must be at least 6 characters' });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const usernameNorm = String(username).trim();
|
|
38
|
+
const emailNorm = normalizeEmail(email);
|
|
39
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailNorm)) {
|
|
40
|
+
return res.status(400).json({ message: 'Enter a valid email address.' });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const existingUser = await query('SELECT id FROM users WHERE username = ?', [usernameNorm]);
|
|
44
|
+
if (existingUser.length) {
|
|
45
|
+
return res.status(409).json({ message: 'Username already exists' });
|
|
46
|
+
}
|
|
47
|
+
const exists = await query('SELECT id FROM users WHERE email = ?', [emailNorm]);
|
|
48
|
+
if (exists.length) {
|
|
49
|
+
return res.status(409).json({ message: 'Email already registered' });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const hash = await bcrypt.hash(String(password), 12);
|
|
53
|
+
const result = await query(
|
|
54
|
+
'INSERT INTO users (username, name, email, password, role) VALUES (?, ?, ?, ?, ?)',
|
|
55
|
+
[usernameNorm, usernameNorm, emailNorm, hash, role === 'staff' ? 'staff' : 'admin']
|
|
56
|
+
);
|
|
57
|
+
const rows = await query(
|
|
58
|
+
'SELECT id, username, name, email, role, created_at FROM users WHERE id = ?',
|
|
59
|
+
[result.insertId]
|
|
60
|
+
);
|
|
61
|
+
const user = rows[0];
|
|
62
|
+
const token = signToken(user);
|
|
63
|
+
return res.status(201).json({ token, user: toUserApi(user) });
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error(err);
|
|
66
|
+
return res.status(500).json({ message: 'Registration failed' });
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
router.post('/login', async (req, res) => {
|
|
71
|
+
try {
|
|
72
|
+
const { username, password } = req.body;
|
|
73
|
+
if (!username || !password) {
|
|
74
|
+
return res.status(400).json({ message: 'Username and password are required' });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const rows = await query('SELECT * FROM users WHERE username = ?', [String(username).trim()]);
|
|
78
|
+
const user = rows[0];
|
|
79
|
+
if (!user) {
|
|
80
|
+
return res.status(401).json({ message: 'Invalid credentials' });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const match = await bcrypt.compare(String(password), user.password);
|
|
84
|
+
if (!match) {
|
|
85
|
+
return res.status(401).json({ message: 'Invalid credentials' });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const token = signToken(user);
|
|
89
|
+
return res.json({
|
|
90
|
+
token,
|
|
91
|
+
user: toUserApi(user),
|
|
92
|
+
});
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.error(err);
|
|
95
|
+
return res.status(500).json({ message: 'Login failed' });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
router.post('/forgot-password', async (req, res) => {
|
|
100
|
+
try {
|
|
101
|
+
const { email, newPassword, confirmPassword } = req.body;
|
|
102
|
+
if (!email) {
|
|
103
|
+
return res.status(400).json({ success: false, message: 'Email is required.' });
|
|
104
|
+
}
|
|
105
|
+
if (!newPassword) {
|
|
106
|
+
return res.status(400).json({ success: false, message: 'New password is required.' });
|
|
107
|
+
}
|
|
108
|
+
if (!confirmPassword) {
|
|
109
|
+
return res.status(400).json({ success: false, message: 'Confirm password is required.' });
|
|
110
|
+
}
|
|
111
|
+
if (newPassword !== confirmPassword) {
|
|
112
|
+
return res.status(400).json({
|
|
113
|
+
success: false,
|
|
114
|
+
message: 'New password and confirm password must match.',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const emailNorm = normalizeEmail(email);
|
|
118
|
+
const rows = await query('SELECT id FROM users WHERE email = ?', [emailNorm]);
|
|
119
|
+
if (!rows.length) {
|
|
120
|
+
return res.status(404).json({ success: false, message: 'User not found' });
|
|
121
|
+
}
|
|
122
|
+
const hash = await bcrypt.hash(String(newPassword), 12);
|
|
123
|
+
await query('UPDATE users SET password = ? WHERE email = ?', [hash, emailNorm]);
|
|
124
|
+
return res.json({ success: true, message: 'Password reset successfully' });
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.error(err);
|
|
127
|
+
return res.status(500).json({ success: false, message: 'Server error.' });
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
export default router;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { query } from '../config/db.js';
|
|
3
|
+
import { protect } from '../middleware/authMiddleware.js';
|
|
4
|
+
import { paymentSelect, toPaymentApi } from '../utils/mappers.js';
|
|
5
|
+
|
|
6
|
+
const router = Router();
|
|
7
|
+
router.use(protect);
|
|
8
|
+
|
|
9
|
+
router.get('/', async (_req, res) => {
|
|
10
|
+
try {
|
|
11
|
+
const rows = await query(`${paymentSelect} ORDER BY p.payment_date DESC`);
|
|
12
|
+
return res.json(rows.map(toPaymentApi));
|
|
13
|
+
} catch (err) {
|
|
14
|
+
console.error(err);
|
|
15
|
+
return res.status(500).json({ message: 'Failed to list payments' });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
router.post('/', async (req, res) => {
|
|
20
|
+
try {
|
|
21
|
+
const { student_id, amount, payment_date } = req.body;
|
|
22
|
+
if (!student_id || amount === undefined || amount === null || !payment_date) {
|
|
23
|
+
return res.status(400).json({ message: 'Student, amount and payment date are required' });
|
|
24
|
+
}
|
|
25
|
+
const students = await query('SELECT id FROM students WHERE id = ?', [student_id]);
|
|
26
|
+
if (!students.length) return res.status(404).json({ message: 'Student not found' });
|
|
27
|
+
|
|
28
|
+
const num = Number(amount);
|
|
29
|
+
if (Number.isNaN(num) || num < 0) {
|
|
30
|
+
return res.status(400).json({ message: 'Amount must be a valid non-negative number' });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const result = await query(
|
|
34
|
+
'INSERT INTO payments (student_id, amount, payment_date) VALUES (?, ?, ?)',
|
|
35
|
+
[student_id, num, payment_date]
|
|
36
|
+
);
|
|
37
|
+
const rows = await query(`${paymentSelect} WHERE p.id = ?`, [result.insertId]);
|
|
38
|
+
return res.status(201).json(toPaymentApi(rows[0]));
|
|
39
|
+
} catch (err) {
|
|
40
|
+
console.error(err);
|
|
41
|
+
return res.status(500).json({ message: 'Failed to create payment' });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
router.put('/:id', async (req, res) => {
|
|
46
|
+
try {
|
|
47
|
+
const existing = await query('SELECT * FROM payments WHERE id = ?', [req.params.id]);
|
|
48
|
+
if (!existing.length) return res.status(404).json({ message: 'Payment not found' });
|
|
49
|
+
|
|
50
|
+
const { student_id, amount, payment_date } = req.body;
|
|
51
|
+
const current = existing[0];
|
|
52
|
+
|
|
53
|
+
if (student_id !== undefined) {
|
|
54
|
+
const students = await query('SELECT id FROM students WHERE id = ?', [student_id]);
|
|
55
|
+
if (!students.length) return res.status(404).json({ message: 'Student not found' });
|
|
56
|
+
}
|
|
57
|
+
if (amount !== undefined) {
|
|
58
|
+
const num = Number(amount);
|
|
59
|
+
if (Number.isNaN(num) || num < 0) {
|
|
60
|
+
return res.status(400).json({ message: 'Amount must be a valid non-negative number' });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await query(
|
|
65
|
+
'UPDATE payments SET student_id = ?, amount = ?, payment_date = ? WHERE id = ?',
|
|
66
|
+
[
|
|
67
|
+
student_id !== undefined ? student_id : current.student_id,
|
|
68
|
+
amount !== undefined ? Number(amount) : current.amount,
|
|
69
|
+
payment_date !== undefined ? payment_date : current.payment_date,
|
|
70
|
+
req.params.id,
|
|
71
|
+
]
|
|
72
|
+
);
|
|
73
|
+
const rows = await query(`${paymentSelect} WHERE p.id = ?`, [req.params.id]);
|
|
74
|
+
return res.json(toPaymentApi(rows[0]));
|
|
75
|
+
} catch (err) {
|
|
76
|
+
console.error(err);
|
|
77
|
+
return res.status(500).json({ message: 'Failed to update payment' });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
router.delete('/:id', async (req, res) => {
|
|
82
|
+
try {
|
|
83
|
+
const result = await query('DELETE FROM payments WHERE id = ?', [req.params.id]);
|
|
84
|
+
if (!result.affectedRows) return res.status(404).json({ message: 'Payment not found' });
|
|
85
|
+
return res.json({ message: 'Deleted', id: req.params.id });
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error(err);
|
|
88
|
+
return res.status(500).json({ message: 'Failed to delete' });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export default router;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { query } from '../config/db.js';
|
|
3
|
+
import { protect } from '../middleware/authMiddleware.js';
|
|
4
|
+
import { paymentSelect, toPaymentApi } from '../utils/mappers.js';
|
|
5
|
+
|
|
6
|
+
const router = Router();
|
|
7
|
+
router.use(protect);
|
|
8
|
+
|
|
9
|
+
router.get('/', async (req, res) => {
|
|
10
|
+
try {
|
|
11
|
+
const { start, end } = req.query;
|
|
12
|
+
if (!start || !end) {
|
|
13
|
+
return res.status(400).json({ message: 'Query params start and end (yyyy-mm-dd) are required' });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const startDate = new Date(String(start));
|
|
17
|
+
const endDate = new Date(String(end));
|
|
18
|
+
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
|
19
|
+
return res.status(400).json({ message: 'Invalid date format; use yyyy-mm-dd' });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const rows = await query(
|
|
23
|
+
`${paymentSelect} WHERE p.payment_date BETWEEN ? AND ? ORDER BY p.payment_date DESC`,
|
|
24
|
+
[String(start), String(end)]
|
|
25
|
+
);
|
|
26
|
+
const payments = rows.map(toPaymentApi);
|
|
27
|
+
const total = payments.reduce((sum, row) => sum + (row.amount || 0), 0);
|
|
28
|
+
|
|
29
|
+
return res.json({
|
|
30
|
+
start: String(start),
|
|
31
|
+
end: String(end),
|
|
32
|
+
payments,
|
|
33
|
+
total_amount_paid: total,
|
|
34
|
+
});
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error(err);
|
|
37
|
+
return res.status(500).json({ message: 'Failed to build report' });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export default router;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { query } from '../config/db.js';
|
|
3
|
+
import { protect } from '../middleware/authMiddleware.js';
|
|
4
|
+
import { toStudentApi } from '../utils/mappers.js';
|
|
5
|
+
|
|
6
|
+
const router = Router();
|
|
7
|
+
router.use(protect);
|
|
8
|
+
|
|
9
|
+
router.get('/', async (_req, res) => {
|
|
10
|
+
try {
|
|
11
|
+
const rows = await query('SELECT * FROM students ORDER BY created_at DESC');
|
|
12
|
+
return res.json(rows.map(toStudentApi));
|
|
13
|
+
} catch (err) {
|
|
14
|
+
console.error(err);
|
|
15
|
+
return res.status(500).json({ message: 'Failed to list students' });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
router.post('/', async (req, res) => {
|
|
20
|
+
try {
|
|
21
|
+
const { full_name, class: className, parent_phone } = req.body;
|
|
22
|
+
if (!full_name || !className || !parent_phone) {
|
|
23
|
+
return res.status(400).json({ message: 'Full name, class and parent phone are required' });
|
|
24
|
+
}
|
|
25
|
+
const result = await query(
|
|
26
|
+
'INSERT INTO students (full_name, class_name, parent_phone) VALUES (?, ?, ?)',
|
|
27
|
+
[String(full_name).trim(), String(className).trim(), String(parent_phone).trim()]
|
|
28
|
+
);
|
|
29
|
+
const rows = await query('SELECT * FROM students WHERE id = ?', [result.insertId]);
|
|
30
|
+
return res.status(201).json(toStudentApi(rows[0]));
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.error(err);
|
|
33
|
+
return res.status(500).json({ message: 'Failed to create student' });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
router.put('/:id', async (req, res) => {
|
|
38
|
+
try {
|
|
39
|
+
const rows = await query('SELECT * FROM students WHERE id = ?', [req.params.id]);
|
|
40
|
+
if (!rows.length) return res.status(404).json({ message: 'Student not found' });
|
|
41
|
+
|
|
42
|
+
const { full_name, class: className, parent_phone } = req.body;
|
|
43
|
+
const current = rows[0];
|
|
44
|
+
await query(
|
|
45
|
+
'UPDATE students SET full_name = ?, class_name = ?, parent_phone = ? WHERE id = ?',
|
|
46
|
+
[
|
|
47
|
+
full_name !== undefined ? String(full_name).trim() : current.full_name,
|
|
48
|
+
className !== undefined ? String(className).trim() : current.class_name,
|
|
49
|
+
parent_phone !== undefined ? String(parent_phone).trim() : current.parent_phone,
|
|
50
|
+
req.params.id,
|
|
51
|
+
]
|
|
52
|
+
);
|
|
53
|
+
const updated = await query('SELECT * FROM students WHERE id = ?', [req.params.id]);
|
|
54
|
+
return res.json(toStudentApi(updated[0]));
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error(err);
|
|
57
|
+
return res.status(500).json({ message: 'Failed to update student' });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
router.delete('/:id', async (req, res) => {
|
|
62
|
+
try {
|
|
63
|
+
const result = await query('DELETE FROM students WHERE id = ?', [req.params.id]);
|
|
64
|
+
if (!result.affectedRows) return res.status(404).json({ message: 'Student not found' });
|
|
65
|
+
return res.json({ message: 'Deleted', id: req.params.id });
|
|
66
|
+
} catch (err) {
|
|
67
|
+
if (err.code === 'ER_ROW_IS_REFERENCED_2') {
|
|
68
|
+
return res.status(409).json({ message: 'Student has payments; delete payments first' });
|
|
69
|
+
}
|
|
70
|
+
console.error(err);
|
|
71
|
+
return res.status(500).json({ message: 'Failed to delete' });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export default router;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import cors from 'cors';
|
|
4
|
+
import { env, requireJwtSecret } from './config/env.js';
|
|
5
|
+
import { connectDatabase } from './config/db.js';
|
|
6
|
+
import authRoutes from './routes/authRoutes.js';
|
|
7
|
+
import studentRoutes from './routes/studentRoutes.js';
|
|
8
|
+
import paymentRoutes from './routes/paymentRoutes.js';
|
|
9
|
+
import reportRoutes from './routes/reportRoutes.js';
|
|
10
|
+
|
|
11
|
+
requireJwtSecret();
|
|
12
|
+
|
|
13
|
+
const app = express();
|
|
14
|
+
|
|
15
|
+
app.use(cors({ origin: true, credentials: true }));
|
|
16
|
+
app.use(express.json());
|
|
17
|
+
|
|
18
|
+
app.get('/api/health', (_req, res) => {
|
|
19
|
+
res.json({ ok: true, app: 'SFMS' });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
app.use('/api/auth', authRoutes);
|
|
23
|
+
app.use('/api/students', studentRoutes);
|
|
24
|
+
app.use('/api/payments', paymentRoutes);
|
|
25
|
+
app.use('/api/reports', reportRoutes);
|
|
26
|
+
|
|
27
|
+
app.use((_req, res) => {
|
|
28
|
+
res.status(404).json({ message: 'Not found' });
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const ok = await connectDatabase();
|
|
32
|
+
if (!ok) {
|
|
33
|
+
console.error('Cannot start without database');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
app.listen(env.port, () => {
|
|
38
|
+
console.log(`SFMS API (MySQL) on http://localhost:${env.port}`);
|
|
39
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const toStudentApi = (row) => {
|
|
2
|
+
if (!row) return null;
|
|
3
|
+
return {
|
|
4
|
+
id: String(row.id),
|
|
5
|
+
full_name: row.full_name,
|
|
6
|
+
class: row.class_name,
|
|
7
|
+
parent_phone: row.parent_phone,
|
|
8
|
+
created_at: row.created_at,
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const toPaymentApi = (row) => {
|
|
13
|
+
if (!row) return null;
|
|
14
|
+
const paymentDate =
|
|
15
|
+
row.payment_date instanceof Date
|
|
16
|
+
? row.payment_date.toISOString().slice(0, 10)
|
|
17
|
+
: String(row.payment_date ?? '').slice(0, 10);
|
|
18
|
+
const student =
|
|
19
|
+
row.student_id && row.student_full_name
|
|
20
|
+
? {
|
|
21
|
+
id: String(row.student_id),
|
|
22
|
+
full_name: row.student_full_name,
|
|
23
|
+
class: row.student_class_name,
|
|
24
|
+
parent_phone: row.student_parent_phone,
|
|
25
|
+
}
|
|
26
|
+
: undefined;
|
|
27
|
+
return {
|
|
28
|
+
id: String(row.id),
|
|
29
|
+
student_id: String(row.student_id),
|
|
30
|
+
amount: Number(row.amount),
|
|
31
|
+
payment_date: paymentDate,
|
|
32
|
+
created_at: row.created_at,
|
|
33
|
+
student,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const paymentSelect = `
|
|
38
|
+
SELECT p.id, p.student_id, p.amount, p.payment_date, p.created_at,
|
|
39
|
+
s.full_name AS student_full_name, s.class_name AS student_class_name,
|
|
40
|
+
s.parent_phone AS student_parent_phone
|
|
41
|
+
FROM payments p
|
|
42
|
+
JOIN students s ON s.id = p.student_id
|
|
43
|
+
`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Dev server — fixed port; strictPort fails if busy (no random port)
|
|
2
|
+
VITE_DEV_SERVER_PORT=5173
|
|
3
|
+
|
|
4
|
+
# Optional: override API proxy target in dev.
|
|
5
|
+
# If omitted, Vite reads PORT from ../backend-mysql/.env or ../backend-mongodb/.env
|
|
6
|
+
# VITE_API_PROXY_TARGET=http://localhost:5000
|
|
7
|
+
|
|
8
|
+
# Production or custom API origin (optional; empty = relative /api)
|
|
9
|
+
# VITE_API_BASE_URL=https://api.example.com
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link
|
|
10
|
+
href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700&family=Outfit:wght@500;600;700&display=swap"
|
|
11
|
+
rel="stylesheet"
|
|
12
|
+
/>
|
|
13
|
+
<title>SFMS — School Fee Management</title>
|
|
14
|
+
</head>
|
|
15
|
+
<body class="antialiased">
|
|
16
|
+
<div id="root"></div>
|
|
17
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|