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.
Files changed (484) hide show
  1. package/index.js +62 -0
  2. package/package.json +14 -0
  3. package/templates/epms-app/.env +7 -0
  4. package/templates/epms-app/README.md +113 -0
  5. package/templates/epms-app/backend-mongodb/.env +3 -0
  6. package/templates/epms-app/backend-mongodb/.env.example +3 -0
  7. package/templates/epms-app/backend-mongodb/config/db.js +29 -0
  8. package/templates/epms-app/backend-mongodb/controllers/authController.js +93 -0
  9. package/templates/epms-app/backend-mongodb/controllers/departmentController.js +24 -0
  10. package/templates/epms-app/backend-mongodb/controllers/employeeController.js +39 -0
  11. package/templates/epms-app/backend-mongodb/controllers/reportController.js +57 -0
  12. package/templates/epms-app/backend-mongodb/controllers/salaryController.js +101 -0
  13. package/templates/epms-app/backend-mongodb/middleware/auth.js +16 -0
  14. package/templates/epms-app/backend-mongodb/models/Counter.js +13 -0
  15. package/templates/epms-app/backend-mongodb/models/Department.js +11 -0
  16. package/templates/epms-app/backend-mongodb/models/Employee.js +18 -0
  17. package/templates/epms-app/backend-mongodb/models/Salary.js +19 -0
  18. package/templates/epms-app/backend-mongodb/models/User.js +9 -0
  19. package/templates/epms-app/backend-mongodb/package-lock.json +1571 -0
  20. package/templates/epms-app/backend-mongodb/package.json +22 -0
  21. package/templates/epms-app/backend-mongodb/routes/authRoutes.js +8 -0
  22. package/templates/epms-app/backend-mongodb/routes/departmentRoutes.js +6 -0
  23. package/templates/epms-app/backend-mongodb/routes/employeeRoutes.js +6 -0
  24. package/templates/epms-app/backend-mongodb/routes/reportRoutes.js +5 -0
  25. package/templates/epms-app/backend-mongodb/routes/salaryRoutes.js +8 -0
  26. package/templates/epms-app/backend-mongodb/server.js +39 -0
  27. package/templates/epms-app/backend-mysql/.env +7 -0
  28. package/templates/epms-app/backend-mysql/.env.example +7 -0
  29. package/templates/epms-app/backend-mysql/config/db.js +33 -0
  30. package/templates/epms-app/backend-mysql/controllers/authController.js +98 -0
  31. package/templates/epms-app/backend-mysql/controllers/departmentController.js +25 -0
  32. package/templates/epms-app/backend-mysql/controllers/employeeController.js +39 -0
  33. package/templates/epms-app/backend-mysql/controllers/reportController.js +41 -0
  34. package/templates/epms-app/backend-mysql/controllers/salaryController.js +93 -0
  35. package/templates/epms-app/backend-mysql/database/schema.sql +7 -0
  36. package/templates/epms-app/backend-mysql/middleware/auth.js +16 -0
  37. package/templates/epms-app/backend-mysql/package-lock.json +1486 -0
  38. package/templates/epms-app/backend-mysql/package.json +23 -0
  39. package/templates/epms-app/backend-mysql/routes/authRoutes.js +8 -0
  40. package/templates/epms-app/backend-mysql/routes/departmentRoutes.js +6 -0
  41. package/templates/epms-app/backend-mysql/routes/employeeRoutes.js +6 -0
  42. package/templates/epms-app/backend-mysql/routes/reportRoutes.js +5 -0
  43. package/templates/epms-app/backend-mysql/routes/salaryRoutes.js +8 -0
  44. package/templates/epms-app/backend-mysql/server.js +39 -0
  45. package/templates/epms-app/frontend/README.md +16 -0
  46. package/templates/epms-app/frontend/eslint.config.js +21 -0
  47. package/templates/epms-app/frontend/index.html +12 -0
  48. package/templates/epms-app/frontend/package-lock.json +3033 -0
  49. package/templates/epms-app/frontend/package.json +23 -0
  50. package/templates/epms-app/frontend/public/favicon.svg +1 -0
  51. package/templates/epms-app/frontend/public/icons.svg +24 -0
  52. package/templates/epms-app/frontend/src/App.css +184 -0
  53. package/templates/epms-app/frontend/src/App.jsx +31 -0
  54. package/templates/epms-app/frontend/src/api/authApi.js +7 -0
  55. package/templates/epms-app/frontend/src/api/client.js +11 -0
  56. package/templates/epms-app/frontend/src/api/departmentApi.js +5 -0
  57. package/templates/epms-app/frontend/src/api/employeeApi.js +4 -0
  58. package/templates/epms-app/frontend/src/api/reportApi.js +4 -0
  59. package/templates/epms-app/frontend/src/api/salaryApi.js +6 -0
  60. package/templates/epms-app/frontend/src/api/sparePartsApi.js +3 -0
  61. package/templates/epms-app/frontend/src/api/usersApi.js +4 -0
  62. package/templates/epms-app/frontend/src/assets/hero.png +0 -0
  63. package/templates/epms-app/frontend/src/assets/react.svg +1 -0
  64. package/templates/epms-app/frontend/src/assets/vite.svg +1 -0
  65. package/templates/epms-app/frontend/src/components/AppLayout.jsx +49 -0
  66. package/templates/epms-app/frontend/src/context/AuthContext.jsx +41 -0
  67. package/templates/epms-app/frontend/src/hooks/.gitkeep +0 -0
  68. package/templates/epms-app/frontend/src/index.css +2 -0
  69. package/templates/epms-app/frontend/src/main.jsx +16 -0
  70. package/templates/epms-app/frontend/src/pages/DepartmentPage.jsx +165 -0
  71. package/templates/epms-app/frontend/src/pages/DepartmentsPage.jsx +119 -0
  72. package/templates/epms-app/frontend/src/pages/EmployeePage.jsx +212 -0
  73. package/templates/epms-app/frontend/src/pages/EmployeesPage.jsx +217 -0
  74. package/templates/epms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
  75. package/templates/epms-app/frontend/src/pages/LoginPage.jsx +105 -0
  76. package/templates/epms-app/frontend/src/pages/RegisterPage.jsx +84 -0
  77. package/templates/epms-app/frontend/src/pages/ReportsPage.jsx +192 -0
  78. package/templates/epms-app/frontend/src/pages/ResetPasswordPage.jsx +83 -0
  79. package/templates/epms-app/frontend/src/pages/SalariesPage.jsx +274 -0
  80. package/templates/epms-app/frontend/src/pages/SalaryPage.jsx +254 -0
  81. package/templates/epms-app/frontend/vite.config.js +8 -0
  82. package/templates/lms-app/.env +9 -0
  83. package/templates/lms-app/README.md +89 -0
  84. package/templates/lms-app/backend-mongodb/.env +5 -0
  85. package/templates/lms-app/backend-mongodb/.env.example +5 -0
  86. package/templates/lms-app/backend-mongodb/package-lock.json +1583 -0
  87. package/templates/lms-app/backend-mongodb/package.json +26 -0
  88. package/templates/lms-app/backend-mongodb/src/config/db.js +10 -0
  89. package/templates/lms-app/backend-mongodb/src/config/env.js +28 -0
  90. package/templates/lms-app/backend-mongodb/src/controllers/authController.js +86 -0
  91. package/templates/lms-app/backend-mongodb/src/controllers/bookController.js +101 -0
  92. package/templates/lms-app/backend-mongodb/src/controllers/borrowController.js +106 -0
  93. package/templates/lms-app/backend-mongodb/src/controllers/dashboardController.js +40 -0
  94. package/templates/lms-app/backend-mongodb/src/controllers/reportController.js +47 -0
  95. package/templates/lms-app/backend-mongodb/src/controllers/studentController.js +92 -0
  96. package/templates/lms-app/backend-mongodb/src/ensureSeedData.js +72 -0
  97. package/templates/lms-app/backend-mongodb/src/middleware/auth.js +29 -0
  98. package/templates/lms-app/backend-mongodb/src/models/Book.js +14 -0
  99. package/templates/lms-app/backend-mongodb/src/models/Borrow.js +16 -0
  100. package/templates/lms-app/backend-mongodb/src/models/Student.js +14 -0
  101. package/templates/lms-app/backend-mongodb/src/models/User.js +13 -0
  102. package/templates/lms-app/backend-mongodb/src/routes/authRoutes.js +12 -0
  103. package/templates/lms-app/backend-mongodb/src/routes/bookRoutes.js +13 -0
  104. package/templates/lms-app/backend-mongodb/src/routes/borrowRoutes.js +11 -0
  105. package/templates/lms-app/backend-mongodb/src/routes/dashboardRoutes.js +9 -0
  106. package/templates/lms-app/backend-mongodb/src/routes/reportRoutes.js +12 -0
  107. package/templates/lms-app/backend-mongodb/src/routes/studentRoutes.js +13 -0
  108. package/templates/lms-app/backend-mongodb/src/seed.js +16 -0
  109. package/templates/lms-app/backend-mongodb/src/server.js +66 -0
  110. package/templates/lms-app/backend-mysql/.env +9 -0
  111. package/templates/lms-app/backend-mysql/.env.example +9 -0
  112. package/templates/lms-app/backend-mysql/database/schema.sql +45 -0
  113. package/templates/lms-app/backend-mysql/package-lock.json +1462 -0
  114. package/templates/lms-app/backend-mysql/package.json +23 -0
  115. package/templates/lms-app/backend-mysql/src/config/db.js +33 -0
  116. package/templates/lms-app/backend-mysql/src/config/env.js +21 -0
  117. package/templates/lms-app/backend-mysql/src/controllers/authController.js +87 -0
  118. package/templates/lms-app/backend-mysql/src/controllers/bookController.js +106 -0
  119. package/templates/lms-app/backend-mysql/src/controllers/borrowController.js +113 -0
  120. package/templates/lms-app/backend-mysql/src/controllers/dashboardController.js +33 -0
  121. package/templates/lms-app/backend-mysql/src/controllers/reportController.js +40 -0
  122. package/templates/lms-app/backend-mysql/src/controllers/studentController.js +95 -0
  123. package/templates/lms-app/backend-mysql/src/ensureSeedData.js +54 -0
  124. package/templates/lms-app/backend-mysql/src/middleware/auth.js +28 -0
  125. package/templates/lms-app/backend-mysql/src/routes/authRoutes.js +12 -0
  126. package/templates/lms-app/backend-mysql/src/routes/bookRoutes.js +13 -0
  127. package/templates/lms-app/backend-mysql/src/routes/borrowRoutes.js +11 -0
  128. package/templates/lms-app/backend-mysql/src/routes/dashboardRoutes.js +9 -0
  129. package/templates/lms-app/backend-mysql/src/routes/reportRoutes.js +12 -0
  130. package/templates/lms-app/backend-mysql/src/routes/studentRoutes.js +13 -0
  131. package/templates/lms-app/backend-mysql/src/server.js +69 -0
  132. package/templates/lms-app/backend-mysql/src/utils/mappers.js +73 -0
  133. package/templates/lms-app/frontend/.env.example +5 -0
  134. package/templates/lms-app/frontend/index.html +13 -0
  135. package/templates/lms-app/frontend/package-lock.json +1592 -0
  136. package/templates/lms-app/frontend/package.json +23 -0
  137. package/templates/lms-app/frontend/public/favicon.svg +4 -0
  138. package/templates/lms-app/frontend/src/App.jsx +107 -0
  139. package/templates/lms-app/frontend/src/api/authApi.js +5 -0
  140. package/templates/lms-app/frontend/src/api/booksApi.js +6 -0
  141. package/templates/lms-app/frontend/src/api/borrowsApi.js +5 -0
  142. package/templates/lms-app/frontend/src/api/client.js +8 -0
  143. package/templates/lms-app/frontend/src/api/dashboardApi.js +3 -0
  144. package/templates/lms-app/frontend/src/api/reportsApi.js +6 -0
  145. package/templates/lms-app/frontend/src/api/studentsApi.js +6 -0
  146. package/templates/lms-app/frontend/src/components/AppLayout.jsx +63 -0
  147. package/templates/lms-app/frontend/src/index.css +34 -0
  148. package/templates/lms-app/frontend/src/main.jsx +13 -0
  149. package/templates/lms-app/frontend/src/pages/BooksPage.jsx +206 -0
  150. package/templates/lms-app/frontend/src/pages/BorrowPage.jsx +134 -0
  151. package/templates/lms-app/frontend/src/pages/DashboardPage.jsx +42 -0
  152. package/templates/lms-app/frontend/src/pages/ForgotPassword.jsx +112 -0
  153. package/templates/lms-app/frontend/src/pages/LoginPage.jsx +71 -0
  154. package/templates/lms-app/frontend/src/pages/ReportsPage.jsx +176 -0
  155. package/templates/lms-app/frontend/src/pages/ReturnPage.jsx +75 -0
  156. package/templates/lms-app/frontend/src/pages/SearchPage.jsx +156 -0
  157. package/templates/lms-app/frontend/src/pages/StudentsPage.jsx +204 -0
  158. package/templates/lms-app/frontend/vite.config.js +26 -0
  159. package/templates/scms-app/.env +7 -0
  160. package/templates/scms-app/README.md +80 -0
  161. package/templates/scms-app/backend-mongodb/.env +3 -0
  162. package/templates/scms-app/backend-mongodb/.env.example +3 -0
  163. package/templates/scms-app/backend-mongodb/config/db.js +29 -0
  164. package/templates/scms-app/backend-mongodb/controllers/authController.js +93 -0
  165. package/templates/scms-app/backend-mongodb/controllers/deliveryController.js +65 -0
  166. package/templates/scms-app/backend-mongodb/controllers/reportController.js +51 -0
  167. package/templates/scms-app/backend-mongodb/controllers/shipmentController.js +65 -0
  168. package/templates/scms-app/backend-mongodb/controllers/supplierController.js +27 -0
  169. package/templates/scms-app/backend-mongodb/middleware/auth.js +16 -0
  170. package/templates/scms-app/backend-mongodb/models/Delivery.js +14 -0
  171. package/templates/scms-app/backend-mongodb/models/Shipment.js +14 -0
  172. package/templates/scms-app/backend-mongodb/models/Supplier.js +14 -0
  173. package/templates/scms-app/backend-mongodb/models/User.js +9 -0
  174. package/templates/scms-app/backend-mongodb/package-lock.json +1571 -0
  175. package/templates/scms-app/backend-mongodb/package.json +22 -0
  176. package/templates/scms-app/backend-mongodb/routes/authRoutes.js +8 -0
  177. package/templates/scms-app/backend-mongodb/routes/deliveryRoutes.js +8 -0
  178. package/templates/scms-app/backend-mongodb/routes/reportRoutes.js +5 -0
  179. package/templates/scms-app/backend-mongodb/routes/shipmentRoutes.js +8 -0
  180. package/templates/scms-app/backend-mongodb/routes/supplierRoutes.js +6 -0
  181. package/templates/scms-app/backend-mongodb/server.js +39 -0
  182. package/templates/scms-app/backend-mysql/.env +7 -0
  183. package/templates/scms-app/backend-mysql/.env.example +7 -0
  184. package/templates/scms-app/backend-mysql/config/db.js +33 -0
  185. package/templates/scms-app/backend-mysql/controllers/authController.js +98 -0
  186. package/templates/scms-app/backend-mysql/controllers/deliveryController.js +62 -0
  187. package/templates/scms-app/backend-mysql/controllers/reportController.js +39 -0
  188. package/templates/scms-app/backend-mysql/controllers/shipmentController.js +62 -0
  189. package/templates/scms-app/backend-mysql/controllers/supplierController.js +28 -0
  190. package/templates/scms-app/backend-mysql/database/schema.sql +7 -0
  191. package/templates/scms-app/backend-mysql/middleware/auth.js +16 -0
  192. package/templates/scms-app/backend-mysql/package-lock.json +1486 -0
  193. package/templates/scms-app/backend-mysql/package.json +23 -0
  194. package/templates/scms-app/backend-mysql/routes/authRoutes.js +8 -0
  195. package/templates/scms-app/backend-mysql/routes/deliveryRoutes.js +8 -0
  196. package/templates/scms-app/backend-mysql/routes/reportRoutes.js +5 -0
  197. package/templates/scms-app/backend-mysql/routes/shipmentRoutes.js +8 -0
  198. package/templates/scms-app/backend-mysql/routes/supplierRoutes.js +6 -0
  199. package/templates/scms-app/backend-mysql/server.js +39 -0
  200. package/templates/scms-app/frontend/index.html +12 -0
  201. package/templates/scms-app/frontend/package-lock.json +1634 -0
  202. package/templates/scms-app/frontend/package.json +23 -0
  203. package/templates/scms-app/frontend/src/App.jsx +31 -0
  204. package/templates/scms-app/frontend/src/api/client.js +11 -0
  205. package/templates/scms-app/frontend/src/components/AppLayout.jsx +49 -0
  206. package/templates/scms-app/frontend/src/context/AuthContext.jsx +41 -0
  207. package/templates/scms-app/frontend/src/hooks/.gitkeep +0 -0
  208. package/templates/scms-app/frontend/src/index.css +2 -0
  209. package/templates/scms-app/frontend/src/main.jsx +16 -0
  210. package/templates/scms-app/frontend/src/pages/DeliveriesPage.jsx +265 -0
  211. package/templates/scms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
  212. package/templates/scms-app/frontend/src/pages/LoginPage.jsx +105 -0
  213. package/templates/scms-app/frontend/src/pages/ReportsPage.jsx +192 -0
  214. package/templates/scms-app/frontend/src/pages/ShipmentsPage.jsx +259 -0
  215. package/templates/scms-app/frontend/src/pages/SuppliersPage.jsx +168 -0
  216. package/templates/scms-app/frontend/vite.config.js +8 -0
  217. package/templates/sfms-app/.env +7 -0
  218. package/templates/sfms-app/README.md +72 -0
  219. package/templates/sfms-app/backend-mongodb/.env +3 -0
  220. package/templates/sfms-app/backend-mongodb/.env.example +3 -0
  221. package/templates/sfms-app/backend-mongodb/package-lock.json +1580 -0
  222. package/templates/sfms-app/backend-mongodb/package.json +23 -0
  223. package/templates/sfms-app/backend-mongodb/src/config/database.js +7 -0
  224. package/templates/sfms-app/backend-mongodb/src/config/env.js +35 -0
  225. package/templates/sfms-app/backend-mongodb/src/middleware/authMiddleware.js +32 -0
  226. package/templates/sfms-app/backend-mongodb/src/models/Payment.js +12 -0
  227. package/templates/sfms-app/backend-mongodb/src/models/Student.js +12 -0
  228. package/templates/sfms-app/backend-mongodb/src/models/User.js +14 -0
  229. package/templates/sfms-app/backend-mongodb/src/routes/authRoutes.js +140 -0
  230. package/templates/sfms-app/backend-mongodb/src/routes/paymentRoutes.js +117 -0
  231. package/templates/sfms-app/backend-mongodb/src/routes/reportRoutes.js +59 -0
  232. package/templates/sfms-app/backend-mongodb/src/routes/studentRoutes.js +79 -0
  233. package/templates/sfms-app/backend-mongodb/src/server.js +34 -0
  234. package/templates/sfms-app/backend-mysql/.env +7 -0
  235. package/templates/sfms-app/backend-mysql/.env.example +7 -0
  236. package/templates/sfms-app/backend-mysql/database/schema.sql +29 -0
  237. package/templates/sfms-app/backend-mysql/package-lock.json +1467 -0
  238. package/templates/sfms-app/backend-mysql/package.json +24 -0
  239. package/templates/sfms-app/backend-mysql/src/config/.gitkeep +0 -0
  240. package/templates/sfms-app/backend-mysql/src/config/db.js +31 -0
  241. package/templates/sfms-app/backend-mysql/src/config/env.js +20 -0
  242. package/templates/sfms-app/backend-mysql/src/middleware/.gitkeep +0 -0
  243. package/templates/sfms-app/backend-mysql/src/middleware/authMiddleware.js +26 -0
  244. package/templates/sfms-app/backend-mysql/src/models/.gitkeep +0 -0
  245. package/templates/sfms-app/backend-mysql/src/routes/.gitkeep +0 -0
  246. package/templates/sfms-app/backend-mysql/src/routes/authRoutes.js +131 -0
  247. package/templates/sfms-app/backend-mysql/src/routes/paymentRoutes.js +92 -0
  248. package/templates/sfms-app/backend-mysql/src/routes/reportRoutes.js +41 -0
  249. package/templates/sfms-app/backend-mysql/src/routes/studentRoutes.js +75 -0
  250. package/templates/sfms-app/backend-mysql/src/server.js +39 -0
  251. package/templates/sfms-app/backend-mysql/src/utils/mappers.js +43 -0
  252. package/templates/sfms-app/frontend/.env.example +9 -0
  253. package/templates/sfms-app/frontend/index.html +19 -0
  254. package/templates/sfms-app/frontend/package-lock.json +2667 -0
  255. package/templates/sfms-app/frontend/package.json +23 -0
  256. package/templates/sfms-app/frontend/postcss.config.js +6 -0
  257. package/templates/sfms-app/frontend/public/favicon.svg +4 -0
  258. package/templates/sfms-app/frontend/src/App.jsx +38 -0
  259. package/templates/sfms-app/frontend/src/api/apiClient.js +54 -0
  260. package/templates/sfms-app/frontend/src/components/AppLayout.jsx +61 -0
  261. package/templates/sfms-app/frontend/src/context/AuthContext.jsx +87 -0
  262. package/templates/sfms-app/frontend/src/index.css +7 -0
  263. package/templates/sfms-app/frontend/src/main.jsx +16 -0
  264. package/templates/sfms-app/frontend/src/pages/DashboardPage.jsx +78 -0
  265. package/templates/sfms-app/frontend/src/pages/ForgotPassword.jsx +114 -0
  266. package/templates/sfms-app/frontend/src/pages/LoginPage.jsx +141 -0
  267. package/templates/sfms-app/frontend/src/pages/PaymentsPage.jsx +309 -0
  268. package/templates/sfms-app/frontend/src/pages/ReportsPage.jsx +123 -0
  269. package/templates/sfms-app/frontend/src/pages/StudentsPage.jsx +281 -0
  270. package/templates/sfms-app/frontend/tailwind.config.js +21 -0
  271. package/templates/sfms-app/frontend/vite.config.js +61 -0
  272. package/templates/sims-app/README.md +138 -0
  273. package/templates/sims-app/backend/.env +4 -0
  274. package/templates/sims-app/backend/.env.example +4 -0
  275. package/templates/sims-app/backend/package.json +22 -0
  276. package/templates/sims-app/backend/src/config/db.js +9 -0
  277. package/templates/sims-app/backend/src/controllers/authController.js +115 -0
  278. package/templates/sims-app/backend/src/controllers/simsReportController.js +94 -0
  279. package/templates/sims-app/backend/src/controllers/sparePartController.js +41 -0
  280. package/templates/sims-app/backend/src/controllers/stockInController.js +45 -0
  281. package/templates/sims-app/backend/src/controllers/stockOutController.js +123 -0
  282. package/templates/sims-app/backend/src/middleware/auth.js +8 -0
  283. package/templates/sims-app/backend/src/models/SparePart.js +17 -0
  284. package/templates/sims-app/backend/src/models/StockIn.js +16 -0
  285. package/templates/sims-app/backend/src/models/StockOut.js +18 -0
  286. package/templates/sims-app/backend/src/models/User.js +12 -0
  287. package/templates/sims-app/backend/src/routes/authRoutes.js +12 -0
  288. package/templates/sims-app/backend/src/routes/simsReportRoutes.js +8 -0
  289. package/templates/sims-app/backend/src/routes/sparePartRoutes.js +8 -0
  290. package/templates/sims-app/backend/src/routes/stockInRoutes.js +8 -0
  291. package/templates/sims-app/backend/src/routes/stockOutRoutes.js +10 -0
  292. package/templates/sims-app/backend/src/server.js +62 -0
  293. package/templates/sims-app/backend/src/utils/passwordPolicy.js +10 -0
  294. package/templates/sims-app/backend/src/utils/sparePartHelpers.js +5 -0
  295. package/templates/sims-app/frontend/index.html +13 -0
  296. package/templates/sims-app/frontend/package.json +31 -0
  297. package/templates/sims-app/frontend/src/App.jsx +110 -0
  298. package/templates/sims-app/frontend/src/api/authApi.js +7 -0
  299. package/templates/sims-app/frontend/src/api/client.js +8 -0
  300. package/templates/sims-app/frontend/src/api/simsReportApi.js +5 -0
  301. package/templates/sims-app/frontend/src/api/sparePartsApi.js +4 -0
  302. package/templates/sims-app/frontend/src/api/stockInApi.js +4 -0
  303. package/templates/sims-app/frontend/src/api/stockOutApi.js +6 -0
  304. package/templates/sims-app/frontend/src/api/usersApi.js +3 -0
  305. package/templates/sims-app/frontend/src/components/AppLayout.jsx +47 -0
  306. package/templates/sims-app/frontend/src/index.css +7 -0
  307. package/templates/sims-app/frontend/src/main.jsx +13 -0
  308. package/templates/sims-app/frontend/src/pages/ForgotPassword.jsx +111 -0
  309. package/templates/sims-app/frontend/src/pages/LoginPage.jsx +71 -0
  310. package/templates/sims-app/frontend/src/pages/RegisterPage.jsx +99 -0
  311. package/templates/sims-app/frontend/src/pages/ReportsPage.jsx +120 -0
  312. package/templates/sims-app/frontend/src/pages/SparePartPage.jsx +148 -0
  313. package/templates/sims-app/frontend/src/pages/StockInPage.jsx +122 -0
  314. package/templates/sims-app/frontend/src/pages/StockOutPage.jsx +252 -0
  315. package/templates/sims-app/frontend/src/utils/passwordPolicy.js +8 -0
  316. package/templates/sims-app/frontend/vite.config.js +8 -0
  317. package/templates/smartshop-app/README.md +61 -0
  318. package/templates/smartshop-app/backend/.env +7 -0
  319. package/templates/smartshop-app/backend/.env.example +7 -0
  320. package/templates/smartshop-app/backend/database/schema.sql +46 -0
  321. package/templates/smartshop-app/backend/package-lock.json +1487 -0
  322. package/templates/smartshop-app/backend/package.json +26 -0
  323. package/templates/smartshop-app/backend/src/app.js +57 -0
  324. package/templates/smartshop-app/backend/src/config/db.js +52 -0
  325. package/templates/smartshop-app/backend/src/controllers/authController.js +98 -0
  326. package/templates/smartshop-app/backend/src/controllers/customerController.js +26 -0
  327. package/templates/smartshop-app/backend/src/controllers/productController.js +21 -0
  328. package/templates/smartshop-app/backend/src/controllers/reportController.js +29 -0
  329. package/templates/smartshop-app/backend/src/controllers/saleController.js +11 -0
  330. package/templates/smartshop-app/backend/src/middleware/authMiddleware.js +22 -0
  331. package/templates/smartshop-app/backend/src/models/authModel.js +24 -0
  332. package/templates/smartshop-app/backend/src/models/customerModel.js +43 -0
  333. package/templates/smartshop-app/backend/src/models/productModel.js +37 -0
  334. package/templates/smartshop-app/backend/src/models/reportModel.js +56 -0
  335. package/templates/smartshop-app/backend/src/models/saleModel.js +54 -0
  336. package/templates/smartshop-app/backend/src/routes/authRoutes.js +10 -0
  337. package/templates/smartshop-app/backend/src/routes/customerRoutes.js +16 -0
  338. package/templates/smartshop-app/backend/src/routes/productRoutes.js +16 -0
  339. package/templates/smartshop-app/backend/src/routes/reportRoutes.js +18 -0
  340. package/templates/smartshop-app/backend/src/routes/saleRoutes.js +9 -0
  341. package/templates/smartshop-app/backend/src/server.js +19 -0
  342. package/templates/smartshop-app/frontend/README.md +18 -0
  343. package/templates/smartshop-app/frontend/eslint.config.js +21 -0
  344. package/templates/smartshop-app/frontend/index.html +13 -0
  345. package/templates/smartshop-app/frontend/package-lock.json +3415 -0
  346. package/templates/smartshop-app/frontend/package.json +34 -0
  347. package/templates/smartshop-app/frontend/public/favicon.svg +1 -0
  348. package/templates/smartshop-app/frontend/public/icons.svg +24 -0
  349. package/templates/smartshop-app/frontend/src/App.css +184 -0
  350. package/templates/smartshop-app/frontend/src/App.jsx +41 -0
  351. package/templates/smartshop-app/frontend/src/assets/hero.png +0 -0
  352. package/templates/smartshop-app/frontend/src/assets/react.svg +1 -0
  353. package/templates/smartshop-app/frontend/src/assets/vite.svg +1 -0
  354. package/templates/smartshop-app/frontend/src/components/AppLayout.jsx +71 -0
  355. package/templates/smartshop-app/frontend/src/components/FormCard.jsx +12 -0
  356. package/templates/smartshop-app/frontend/src/components/StatCard.jsx +10 -0
  357. package/templates/smartshop-app/frontend/src/index.css +28 -0
  358. package/templates/smartshop-app/frontend/src/main.jsx +13 -0
  359. package/templates/smartshop-app/frontend/src/pages/CustomersPage.jsx +175 -0
  360. package/templates/smartshop-app/frontend/src/pages/DashboardPage.jsx +30 -0
  361. package/templates/smartshop-app/frontend/src/pages/ForgotPassword.jsx +102 -0
  362. package/templates/smartshop-app/frontend/src/pages/LoginPage.jsx +142 -0
  363. package/templates/smartshop-app/frontend/src/pages/ProductsPage.jsx +165 -0
  364. package/templates/smartshop-app/frontend/src/pages/ReportsPage.jsx +204 -0
  365. package/templates/smartshop-app/frontend/src/pages/SalesPage.jsx +153 -0
  366. package/templates/smartshop-app/frontend/src/services/api.js +15 -0
  367. package/templates/smartshop-app/frontend/vite.config.js +13 -0
  368. package/templates/srms-app/.env +7 -0
  369. package/templates/srms-app/README.md +82 -0
  370. package/templates/srms-app/backend-mongodb/.env +3 -0
  371. package/templates/srms-app/backend-mongodb/.env.example +3 -0
  372. package/templates/srms-app/backend-mongodb/config/db.js +29 -0
  373. package/templates/srms-app/backend-mongodb/controllers/authController.js +93 -0
  374. package/templates/srms-app/backend-mongodb/controllers/customerController.js +27 -0
  375. package/templates/srms-app/backend-mongodb/controllers/productController.js +26 -0
  376. package/templates/srms-app/backend-mongodb/controllers/reportController.js +44 -0
  377. package/templates/srms-app/backend-mongodb/controllers/saleController.js +72 -0
  378. package/templates/srms-app/backend-mongodb/middleware/auth.js +16 -0
  379. package/templates/srms-app/backend-mongodb/models/Customer.js +14 -0
  380. package/templates/srms-app/backend-mongodb/models/Product.js +13 -0
  381. package/templates/srms-app/backend-mongodb/models/Sale.js +15 -0
  382. package/templates/srms-app/backend-mongodb/models/User.js +9 -0
  383. package/templates/srms-app/backend-mongodb/package-lock.json +1571 -0
  384. package/templates/srms-app/backend-mongodb/package.json +22 -0
  385. package/templates/srms-app/backend-mongodb/routes/authRoutes.js +8 -0
  386. package/templates/srms-app/backend-mongodb/routes/customerRoutes.js +6 -0
  387. package/templates/srms-app/backend-mongodb/routes/productRoutes.js +6 -0
  388. package/templates/srms-app/backend-mongodb/routes/reportRoutes.js +5 -0
  389. package/templates/srms-app/backend-mongodb/routes/saleRoutes.js +8 -0
  390. package/templates/srms-app/backend-mongodb/server.js +39 -0
  391. package/templates/srms-app/backend-mysql/.env +7 -0
  392. package/templates/srms-app/backend-mysql/.env.example +7 -0
  393. package/templates/srms-app/backend-mysql/config/db.js +33 -0
  394. package/templates/srms-app/backend-mysql/controllers/authController.js +98 -0
  395. package/templates/srms-app/backend-mysql/controllers/customerController.js +28 -0
  396. package/templates/srms-app/backend-mysql/controllers/productController.js +27 -0
  397. package/templates/srms-app/backend-mysql/controllers/reportController.js +29 -0
  398. package/templates/srms-app/backend-mysql/controllers/saleController.js +68 -0
  399. package/templates/srms-app/backend-mysql/database/schema.sql +7 -0
  400. package/templates/srms-app/backend-mysql/middleware/auth.js +16 -0
  401. package/templates/srms-app/backend-mysql/package-lock.json +1486 -0
  402. package/templates/srms-app/backend-mysql/package.json +23 -0
  403. package/templates/srms-app/backend-mysql/routes/authRoutes.js +8 -0
  404. package/templates/srms-app/backend-mysql/routes/customerRoutes.js +6 -0
  405. package/templates/srms-app/backend-mysql/routes/productRoutes.js +6 -0
  406. package/templates/srms-app/backend-mysql/routes/reportRoutes.js +5 -0
  407. package/templates/srms-app/backend-mysql/routes/saleRoutes.js +8 -0
  408. package/templates/srms-app/backend-mysql/server.js +39 -0
  409. package/templates/srms-app/frontend/index.html +12 -0
  410. package/templates/srms-app/frontend/package-lock.json +1634 -0
  411. package/templates/srms-app/frontend/package.json +23 -0
  412. package/templates/srms-app/frontend/src/App.jsx +31 -0
  413. package/templates/srms-app/frontend/src/api/client.js +11 -0
  414. package/templates/srms-app/frontend/src/components/AppLayout.jsx +40 -0
  415. package/templates/srms-app/frontend/src/context/AuthContext.jsx +41 -0
  416. package/templates/srms-app/frontend/src/hooks/.gitkeep +0 -0
  417. package/templates/srms-app/frontend/src/index.css +2 -0
  418. package/templates/srms-app/frontend/src/main.jsx +16 -0
  419. package/templates/srms-app/frontend/src/pages/CustomersPage.jsx +160 -0
  420. package/templates/srms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
  421. package/templates/srms-app/frontend/src/pages/LoginPage.jsx +105 -0
  422. package/templates/srms-app/frontend/src/pages/ProductsPage.jsx +158 -0
  423. package/templates/srms-app/frontend/src/pages/ReportsPage.jsx +192 -0
  424. package/templates/srms-app/frontend/src/pages/SalesPage.jsx +310 -0
  425. package/templates/srms-app/frontend/vite.config.js +8 -0
  426. package/templates/stockhub-sms-app/.env +7 -0
  427. package/templates/stockhub-sms-app/README.md +82 -0
  428. package/templates/stockhub-sms-app/backend-mongodb/.env +3 -0
  429. package/templates/stockhub-sms-app/backend-mongodb/.env.example +3 -0
  430. package/templates/stockhub-sms-app/backend-mongodb/config/db.js +29 -0
  431. package/templates/stockhub-sms-app/backend-mongodb/controllers/authController.js +93 -0
  432. package/templates/stockhub-sms-app/backend-mongodb/controllers/productController.js +29 -0
  433. package/templates/stockhub-sms-app/backend-mongodb/controllers/reportController.js +53 -0
  434. package/templates/stockhub-sms-app/backend-mongodb/controllers/transactionController.js +74 -0
  435. package/templates/stockhub-sms-app/backend-mongodb/controllers/warehouseController.js +25 -0
  436. package/templates/stockhub-sms-app/backend-mongodb/middleware/auth.js +16 -0
  437. package/templates/stockhub-sms-app/backend-mongodb/models/Counter.js +13 -0
  438. package/templates/stockhub-sms-app/backend-mongodb/models/Product.js +16 -0
  439. package/templates/stockhub-sms-app/backend-mongodb/models/StockTransaction.js +19 -0
  440. package/templates/stockhub-sms-app/backend-mongodb/models/User.js +9 -0
  441. package/templates/stockhub-sms-app/backend-mongodb/models/Warehouse.js +12 -0
  442. package/templates/stockhub-sms-app/backend-mongodb/package-lock.json +1571 -0
  443. package/templates/stockhub-sms-app/backend-mongodb/package.json +22 -0
  444. package/templates/stockhub-sms-app/backend-mongodb/routes/authRoutes.js +8 -0
  445. package/templates/stockhub-sms-app/backend-mongodb/routes/productRoutes.js +6 -0
  446. package/templates/stockhub-sms-app/backend-mongodb/routes/reportRoutes.js +5 -0
  447. package/templates/stockhub-sms-app/backend-mongodb/routes/transactionRoutes.js +8 -0
  448. package/templates/stockhub-sms-app/backend-mongodb/routes/warehouseRoutes.js +6 -0
  449. package/templates/stockhub-sms-app/backend-mongodb/server.js +39 -0
  450. package/templates/stockhub-sms-app/backend-mysql/.env +7 -0
  451. package/templates/stockhub-sms-app/backend-mysql/.env.example +7 -0
  452. package/templates/stockhub-sms-app/backend-mysql/config/db.js +33 -0
  453. package/templates/stockhub-sms-app/backend-mysql/controllers/authController.js +98 -0
  454. package/templates/stockhub-sms-app/backend-mysql/controllers/productController.js +30 -0
  455. package/templates/stockhub-sms-app/backend-mysql/controllers/reportController.js +53 -0
  456. package/templates/stockhub-sms-app/backend-mysql/controllers/transactionController.js +70 -0
  457. package/templates/stockhub-sms-app/backend-mysql/controllers/warehouseController.js +26 -0
  458. package/templates/stockhub-sms-app/backend-mysql/database/schema.sql +40 -0
  459. package/templates/stockhub-sms-app/backend-mysql/middleware/auth.js +16 -0
  460. package/templates/stockhub-sms-app/backend-mysql/package-lock.json +1486 -0
  461. package/templates/stockhub-sms-app/backend-mysql/package.json +23 -0
  462. package/templates/stockhub-sms-app/backend-mysql/routes/authRoutes.js +8 -0
  463. package/templates/stockhub-sms-app/backend-mysql/routes/productRoutes.js +6 -0
  464. package/templates/stockhub-sms-app/backend-mysql/routes/reportRoutes.js +5 -0
  465. package/templates/stockhub-sms-app/backend-mysql/routes/transactionRoutes.js +8 -0
  466. package/templates/stockhub-sms-app/backend-mysql/routes/warehouseRoutes.js +6 -0
  467. package/templates/stockhub-sms-app/backend-mysql/server.js +39 -0
  468. package/templates/stockhub-sms-app/frontend/index.html +12 -0
  469. package/templates/stockhub-sms-app/frontend/package-lock.json +1634 -0
  470. package/templates/stockhub-sms-app/frontend/package.json +23 -0
  471. package/templates/stockhub-sms-app/frontend/src/App.jsx +31 -0
  472. package/templates/stockhub-sms-app/frontend/src/api/client.js +11 -0
  473. package/templates/stockhub-sms-app/frontend/src/components/AppLayout.jsx +40 -0
  474. package/templates/stockhub-sms-app/frontend/src/context/AuthContext.jsx +41 -0
  475. package/templates/stockhub-sms-app/frontend/src/hooks/.gitkeep +0 -0
  476. package/templates/stockhub-sms-app/frontend/src/index.css +13 -0
  477. package/templates/stockhub-sms-app/frontend/src/main.jsx +16 -0
  478. package/templates/stockhub-sms-app/frontend/src/pages/ForgotPassword.jsx +103 -0
  479. package/templates/stockhub-sms-app/frontend/src/pages/LoginPage.jsx +105 -0
  480. package/templates/stockhub-sms-app/frontend/src/pages/ProductsPage.jsx +132 -0
  481. package/templates/stockhub-sms-app/frontend/src/pages/ReportsPage.jsx +177 -0
  482. package/templates/stockhub-sms-app/frontend/src/pages/TransactionsPage.jsx +270 -0
  483. package/templates/stockhub-sms-app/frontend/src/pages/WarehousesPage.jsx +116 -0
  484. package/templates/stockhub-sms-app/frontend/vite.config.js +8 -0
@@ -0,0 +1,281 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { apiRequest } from '../api/apiClient.js';
3
+
4
+ const inputClass =
5
+ 'border border-slate-200 rounded-lg px-3 py-2 w-full focus:ring-2 focus:ring-teal-500 outline-none';
6
+
7
+ export function StudentsPage() {
8
+ const [list, setList] = useState([]);
9
+ const [submitting, setSubmitting] = useState(false);
10
+ const [error, setError] = useState('');
11
+ /** null | 'new' | student row — drives add form vs edit modal */
12
+ const [formTarget, setFormTarget] = useState(null);
13
+
14
+ const [fullName, setFullName] = useState('');
15
+ const [className, setClassName] = useState('');
16
+ const [parentPhone, setParentPhone] = useState('');
17
+ const [fieldErrors, setFieldErrors] = useState({});
18
+
19
+ async function load() {
20
+ setError('');
21
+ try {
22
+ const data = await apiRequest('/api/students');
23
+ setList(data);
24
+ } catch (e) {
25
+ setError(e.message);
26
+ }
27
+ }
28
+
29
+ useEffect(() => {
30
+ load();
31
+ }, []);
32
+
33
+ function validate() {
34
+ const err = {};
35
+ if (!fullName.trim()) err.fullName = 'Full name is required.';
36
+ if (!className.trim()) err.className = 'Class is required.';
37
+ if (!parentPhone.trim()) err.parentPhone = 'Parent phone is required.';
38
+ else if (!/^[0-9+\-\s]{7,15}$/.test(parentPhone.trim())) {
39
+ err.parentPhone = 'Enter a valid phone number (7–15 digits).';
40
+ }
41
+ setFieldErrors(err);
42
+ return Object.keys(err).length === 0;
43
+ }
44
+
45
+ function openNew() {
46
+ setFormTarget('new');
47
+ setFullName('');
48
+ setClassName('');
49
+ setParentPhone('');
50
+ setFieldErrors({});
51
+ }
52
+
53
+ function openEdit(row) {
54
+ setFormTarget(row);
55
+ setFullName(row.full_name || '');
56
+ setClassName(row.class || '');
57
+ setParentPhone(row.parent_phone || '');
58
+ setFieldErrors({});
59
+ }
60
+
61
+ function closeForm() {
62
+ setFormTarget(null);
63
+ setFieldErrors({});
64
+ }
65
+
66
+ async function save(e) {
67
+ e.preventDefault();
68
+ if (!validate()) return;
69
+ setSubmitting(true);
70
+ setError('');
71
+ try {
72
+ const payload = {
73
+ full_name: fullName.trim(),
74
+ class: className.trim(),
75
+ parent_phone: parentPhone.trim(),
76
+ };
77
+ if (formTarget !== 'new' && formTarget?.id) {
78
+ await apiRequest(`/api/students/${formTarget.id}`, {
79
+ method: 'PUT',
80
+ body: JSON.stringify(payload),
81
+ });
82
+ } else {
83
+ await apiRequest('/api/students', { method: 'POST', body: JSON.stringify(payload) });
84
+ }
85
+ closeForm();
86
+ await load();
87
+ } catch (err) {
88
+ setError(err.message);
89
+ } finally {
90
+ setSubmitting(false);
91
+ }
92
+ }
93
+
94
+ async function remove(id) {
95
+ if (!window.confirm('Delete this student?')) return;
96
+ setError('');
97
+ try {
98
+ await apiRequest(`/api/students/${id}`, { method: 'DELETE' });
99
+ await load();
100
+ } catch (e) {
101
+ setError(e.message);
102
+ }
103
+ }
104
+
105
+ return (
106
+ <div>
107
+ <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
108
+ <div>
109
+ <h1 className="font-display text-2xl font-bold text-sfms-ink">Students</h1>
110
+ <p className="text-slate-600 text-sm mt-0.5">Create, update and remove student records.</p>
111
+ </div>
112
+ <button
113
+ type="button"
114
+ onClick={openNew}
115
+ className="text-sm font-medium text-teal-700 border border-teal-200 rounded-lg px-4 py-2 hover:bg-teal-50 w-fit"
116
+ >
117
+ + New student
118
+ </button>
119
+ </div>
120
+
121
+ {error && (
122
+ <div className="mb-4 text-sm text-red-600 bg-red-50 border border-red-100 rounded-lg px-3 py-2">
123
+ {error}
124
+ </div>
125
+ )}
126
+
127
+ {formTarget === 'new' && (
128
+ <form
129
+ onSubmit={save}
130
+ className="mb-8 p-5 bg-white rounded-xl border border-slate-100 shadow-sm space-y-3 max-w-xl"
131
+ >
132
+ <h2 className="font-semibold text-sfms-ink">New student</h2>
133
+ <div>
134
+ <label className="text-sm text-slate-600">Full name</label>
135
+ <input
136
+ className={inputClass + ' mt-1'}
137
+ value={fullName}
138
+ onChange={(e) => setFullName(e.target.value)}
139
+ />
140
+ {fieldErrors.fullName && (
141
+ <p className="text-xs text-red-600 mt-1">{fieldErrors.fullName}</p>
142
+ )}
143
+ </div>
144
+ <div>
145
+ <label className="text-sm text-slate-600">Class</label>
146
+ <input
147
+ className={inputClass + ' mt-1'}
148
+ value={className}
149
+ onChange={(e) => setClassName(e.target.value)}
150
+ />
151
+ {fieldErrors.className && (
152
+ <p className="text-xs text-red-600 mt-1">{fieldErrors.className}</p>
153
+ )}
154
+ </div>
155
+ <div>
156
+ <label className="text-sm text-slate-600">Parent phone</label>
157
+ <input
158
+ className={inputClass + ' mt-1'}
159
+ value={parentPhone}
160
+ onChange={(e) => setParentPhone(e.target.value)}
161
+ />
162
+ {fieldErrors.parentPhone && (
163
+ <p className="text-xs text-red-600 mt-1">{fieldErrors.parentPhone}</p>
164
+ )}
165
+ </div>
166
+ <div className="flex gap-2 pt-2">
167
+ <button
168
+ type="submit"
169
+ disabled={submitting}
170
+ className="px-4 py-2 rounded-lg bg-teal-600 text-white text-sm font-medium disabled:opacity-60"
171
+ >
172
+ {submitting ? 'Saving…' : 'Save'}
173
+ </button>
174
+ <button type="button" onClick={closeForm} className="px-4 py-2 rounded-lg border text-sm">
175
+ Cancel
176
+ </button>
177
+ </div>
178
+ </form>
179
+ )}
180
+
181
+ <div className="overflow-x-auto rounded-xl border border-slate-200 bg-white shadow-sm">
182
+ <table className="min-w-full text-sm">
183
+ <thead className="bg-slate-50 text-slate-600 text-left">
184
+ <tr>
185
+ <th className="px-4 py-3 font-medium">Name</th>
186
+ <th className="px-4 py-3 font-medium">Class</th>
187
+ <th className="px-4 py-3 font-medium">Parent phone</th>
188
+ <th className="px-4 py-3 font-medium w-36">Actions</th>
189
+ </tr>
190
+ </thead>
191
+ <tbody>
192
+ {list.map((u) => (
193
+ <tr key={u.id} className="border-t border-slate-100 hover:bg-slate-50/80">
194
+ <td className="px-4 py-3 font-medium text-sfms-ink">{u.full_name}</td>
195
+ <td className="px-4 py-3">{u.class}</td>
196
+ <td className="px-4 py-3">{u.parent_phone}</td>
197
+ <td className="px-4 py-3 space-x-2 whitespace-nowrap">
198
+ <button
199
+ type="button"
200
+ className="text-teal-700 font-medium"
201
+ onClick={() => openEdit(u)}
202
+ >
203
+ Edit
204
+ </button>
205
+ <button type="button" className="text-red-600 font-medium" onClick={() => remove(u.id)}>
206
+ Delete
207
+ </button>
208
+ </td>
209
+ </tr>
210
+ ))}
211
+ </tbody>
212
+ </table>
213
+ {list.length === 0 && <p className="p-6 text-center text-slate-500">No students yet.</p>}
214
+ </div>
215
+
216
+ {formTarget && formTarget !== 'new' && (
217
+ <div
218
+ className="fixed inset-0 bg-black/40 flex items-center justify-center p-4 z-50"
219
+ onClick={(e) => e.target === e.currentTarget && closeForm()}
220
+ role="presentation"
221
+ >
222
+ <div
223
+ className="bg-white rounded-xl p-6 max-w-md w-full shadow-xl space-y-3"
224
+ onClick={(e) => e.stopPropagation()}
225
+ role="dialog"
226
+ aria-modal="true"
227
+ >
228
+ <h2 className="font-semibold text-lg">Edit student</h2>
229
+ <form onSubmit={save} className="space-y-3">
230
+ <div>
231
+ <label className="text-sm text-slate-600">Name</label>
232
+ <input
233
+ className={inputClass + ' mt-1'}
234
+ value={fullName}
235
+ onChange={(e) => setFullName(e.target.value)}
236
+ />
237
+ {fieldErrors.fullName && (
238
+ <p className="text-xs text-red-600 mt-1">{fieldErrors.fullName}</p>
239
+ )}
240
+ </div>
241
+ <div>
242
+ <label className="text-sm text-slate-600">Class</label>
243
+ <input
244
+ className={inputClass + ' mt-1'}
245
+ value={className}
246
+ onChange={(e) => setClassName(e.target.value)}
247
+ />
248
+ {fieldErrors.className && (
249
+ <p className="text-xs text-red-600 mt-1">{fieldErrors.className}</p>
250
+ )}
251
+ </div>
252
+ <div>
253
+ <label className="text-sm text-slate-600">Parent phone</label>
254
+ <input
255
+ className={inputClass + ' mt-1'}
256
+ value={parentPhone}
257
+ onChange={(e) => setParentPhone(e.target.value)}
258
+ />
259
+ {fieldErrors.parentPhone && (
260
+ <p className="text-xs text-red-600 mt-1">{fieldErrors.parentPhone}</p>
261
+ )}
262
+ </div>
263
+ <div className="flex gap-2 pt-2">
264
+ <button
265
+ type="submit"
266
+ disabled={submitting}
267
+ className="flex-1 py-2 rounded-lg bg-teal-600 text-white text-sm font-medium disabled:opacity-60"
268
+ >
269
+ Save
270
+ </button>
271
+ <button type="button" onClick={closeForm} className="px-4 py-2 rounded-lg border text-sm">
272
+ Close
273
+ </button>
274
+ </div>
275
+ </form>
276
+ </div>
277
+ </div>
278
+ )}
279
+ </div>
280
+ );
281
+ }
@@ -0,0 +1,21 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ['./index.html', './src/**/*.{js,jsx}'],
4
+ theme: {
5
+ extend: {
6
+ fontFamily: {
7
+ sans: ['DM Sans', 'system-ui', 'sans-serif'],
8
+ display: ['Outfit', 'system-ui', 'sans-serif'],
9
+ },
10
+ colors: {
11
+ sfms: {
12
+ ink: '#0f172a',
13
+ mist: '#f1f5f9',
14
+ accent: '#0d9488',
15
+ accentDark: '#0f766e',
16
+ },
17
+ },
18
+ },
19
+ },
20
+ plugins: [],
21
+ };
@@ -0,0 +1,61 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { defineConfig, loadEnv } from 'vite';
5
+ import react from '@vitejs/plugin-react';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ const DEFAULT_DEV_PORT = 5173;
9
+ const DEFAULT_API_PORT = 5000;
10
+
11
+ /** Read PORT from backend-mysql or backend-mongodb .env */
12
+ function backendPortFromEnvFile() {
13
+ for (const dir of ['backend-mysql', 'backend-mongodb']) {
14
+ const envPath = path.join(__dirname, `../${dir}/.env`);
15
+ if (!fs.existsSync(envPath)) continue;
16
+ try {
17
+ const text = fs.readFileSync(envPath, 'utf8');
18
+ const portLine = text
19
+ .split('\n')
20
+ .map((line) => line.trim())
21
+ .find((line) => line.startsWith('PORT=') || line.startsWith('SFMS_BACKEND_PORT='));
22
+ if (!portLine) continue;
23
+ const n = Number(portLine.split('=')[1]?.trim());
24
+ if (Number.isFinite(n) && n > 0) return n;
25
+ } catch {
26
+ /* try next */
27
+ }
28
+ }
29
+ return null;
30
+ }
31
+
32
+ export default defineConfig(({ mode }) => {
33
+ const rootEnv = loadEnv(mode, process.cwd(), '');
34
+
35
+ const port =
36
+ Number(
37
+ rootEnv.VITE_DEV_SERVER_PORT ||
38
+ rootEnv.SFMS_FRONTEND_PORT ||
39
+ `${DEFAULT_DEV_PORT}`
40
+ ) || DEFAULT_DEV_PORT;
41
+
42
+ const fromBackendEnv = backendPortFromEnvFile();
43
+ const proxyTarget =
44
+ rootEnv.VITE_API_PROXY_TARGET ||
45
+ rootEnv.VITE_BACKEND_URL ||
46
+ (fromBackendEnv ? `http://localhost:${fromBackendEnv}` : `http://localhost:${DEFAULT_API_PORT}`);
47
+
48
+ return {
49
+ plugins: [react()],
50
+ server: {
51
+ port,
52
+ strictPort: true,
53
+ proxy: {
54
+ '/api': {
55
+ target: proxyTarget,
56
+ changeOrigin: true,
57
+ },
58
+ },
59
+ },
60
+ };
61
+ });
@@ -0,0 +1,138 @@
1
+ # SIMS — Stock Inventory Management System
2
+
3
+ [How this maps to the generic EPMS marking rubric (and what differs) → `EXAM_CHECKLIST_MARKING.md`](EXAM_CHECKLIST_MARKING.md)
4
+
5
+ ## ERD (Entity Relationship Diagram) — for your paper
6
+
7
+ Draw this on **plain paper** with standard symbols: **entities (rectangles)**, **relationships (diamonds or simple lines)**, **primary keys (PK)**, **foreign keys (FK)**, and **cardinalities (1, N)**.
8
+
9
+ ### 1) Entity: `User` (login / session)
10
+
11
+ | Field | Type | Key |
12
+ |----------------|---------|-----|
13
+ | `userId` | (PK) | PK |
14
+ | `username` | String | |
15
+ | `passwordHash` | String | |
16
+
17
+ - **No foreign keys.** Use this only for authentication (session). You can draw it **separate** from the stock model (no line to Spare part / stock tables), unless your assessor wants a line—usually **not required**.
18
+
19
+ ---
20
+
21
+ ### 2) Entity: `Spare_Part` (catalog + current stock)
22
+
23
+ | Field | Type | Key |
24
+ |-------------|---------|-----|
25
+ | `sparePartId` / `_id` | (id) | **PK** |
26
+ | `name` | String | |
27
+ | `category` | String | |
28
+ | `quantity` | Number | |
29
+ | `unitPrice` | Number | |
30
+ | `totalPrice`| Number | |
31
+
32
+ - One row = one part type (e.g. oil filter) with **current** quantity in stock and price fields as in the exam.
33
+
34
+ ---
35
+
36
+ ### 3) Entity: `Stock_In` (parts received into store)
37
+
38
+ | Field | Type | Key |
39
+ |------------------|--------|-----|
40
+ | `stockInId` / `_id` | (id) | **PK** |
41
+ | `sparePartId` | ref | **FK → `Spare_Part.sparePartId`** |
42
+ | `stockInQuantity`| Number | |
43
+ | `stockInDate` | Date | |
44
+
45
+ ---
46
+
47
+ ### 4) Entity: `Stock_Out` (parts taken from store)
48
+
49
+ | Field | Type | Key |
50
+ |------------------------|--------|-----|
51
+ | `stockOutId` / `_id` | (id) | **PK** |
52
+ | `sparePartId` | ref | **FK → `Spare_Part.sparePartId`** |
53
+ | `stockOutQuantity` | Number | |
54
+ | `stockOutUnitPrice` | Number | |
55
+ | `stockOutTotalPrice` | Number | |
56
+ | `stockOutDate` | Date | |
57
+
58
+ ---
59
+
60
+ ### Relationships and cardinality
61
+
62
+ | Relationship | From | To | Cardinality (typical) |
63
+ |--------------|------|-----|------------------------|
64
+ | **Supplies to stock in** | `Spare_Part` | `Stock_In` | **1 : N** (one part type, many stock-in rows over time) |
65
+ | **Supplies to stock out** | `Spare_Part` | `Stock_Out` | **1 : N** (one part type, many stock-out rows over time) |
66
+ | | `Stock_In` | `Spare_Part` | each row **N : 1** (many stock-in rows point to one part) |
67
+ | | `Stock_Out` | `Spare_Part` | each row **N : 1** (many stock-out rows point to one part) |
68
+
69
+ - **There is no direct relationship** between `Stock_In` and `Stock_Out` (no FK between them); they both only link to **`Spare_Part`**.
70
+
71
+ ### Small diagram (ASCII — for copy on paper)
72
+
73
+ ```
74
+ ┌──────────┐ 1 N ┌───────────┐
75
+ │ User │ (no FK to stock) │ Spare │
76
+ │ PK: id │ │ _Part │
77
+ └──────────┘ │ PK: id │
78
+ └─────┬─────┘
79
+ ┌──────────────────┼──────────────────┐
80
+ 1 │ N 1 │ N
81
+ ┌─────────▼──────┐ ┌───────▼──────────┐
82
+ │ Stock_In │ │ Stock_Out │
83
+ │ PK, FK→Spare │ │ PK, FK→Spare │
84
+ └────────────────┘ └────────────────┘
85
+ ```
86
+
87
+ **Summary sentence:** *One spare part can have many stock-in records and many stock-out records; each stock-in and stock-out row references exactly one spare part.*
88
+
89
+ ---
90
+
91
+ Practical exam project : full-stack app with **MongoDB**, **Express**, **React**, **Tailwind**, **session login**, **Axios**.
92
+
93
+ ## Exam rules implemented
94
+
95
+ | Requirement | How |
96
+ |-------------|-----|
97
+ | ERD: Spare_Part, Stock_In, Stock_Out (PK/FK) | On paper; backend uses `SparePart` with refs from `StockIn` / `StockOut` |
98
+ | DB name **SIMS** | `MONGO_URI` → database `sims` |
99
+ | Insert on Spare Part, Stock In, Stock Out | `POST` only (no update/delete) on spare parts and stock in |
100
+ | Update / delete / list only on **Stock Out** | `GET`, `PUT`, `DELETE` on `/api/stock-out/:id` |
101
+ | Menu: Spare Part, Stock In, Stock Out, **Reports**, **Logout** | `AppLayout.jsx` |
102
+ | Session login, **strong encrypted password** | Bcrypt; register requires 8+ chars, upper, lower, number |
103
+ | Tailwind, responsive, Axios | Vite + `@tailwindcss/vite` |
104
+ | Reports: **daily stock status** + **daily stock out** | `GET /api/reports/daily-stock-status?date=`, `GET /api/reports/daily-stockout?date=` |
105
+
106
+ ## Ports (avoids clash with EPMS on same machine)
107
+
108
+ - Backend: **5001** (configurable in `.env`)
109
+ - Frontend: **5174** (Vite)
110
+ - `FRONTEND_URL` in backend `.env` should match the Vite URL
111
+
112
+ ## Run
113
+
114
+ ```bash
115
+ cd sims/backend
116
+ cp .env.example .env
117
+ npm install
118
+ npm run dev
119
+ ```
120
+
121
+ ```bash
122
+ cd sims/frontend
123
+ npm install
124
+ npm run dev
125
+ ```
126
+
127
+ - API: [http://localhost:5001/api/health](http://localhost:5001/api/health)
128
+ - App: [http://localhost:5174](http://localhost:5174)
129
+
130
+ ## Project layout
131
+
132
+ ```
133
+ sims/
134
+ backend/ Node + Express + Mongoose
135
+ frontend/ React + Vite + Tailwind
136
+ README.md
137
+ ```
138
+
@@ -0,0 +1,4 @@
1
+ PORT=5001
2
+ MONGO_URI=mongodb://127.0.0.1:27017/sims
3
+ SESSION_SECRET=change-sims-secret
4
+ FRONTEND_URL=http://localhost:5174
@@ -0,0 +1,4 @@
1
+ PORT=5001
2
+ MONGO_URI=mongodb://127.0.0.1:27017/sims
3
+ SESSION_SECRET=change-sims-secret
4
+ FRONTEND_URL=http://localhost:5174
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "sims-backend",
3
+ "version": "1.0.0",
4
+ "main": "src/server.js",
5
+ "scripts": {
6
+ "dev": "nodemon src/server.js",
7
+ "start": "node src/server.js"
8
+ },
9
+ "license": "ISC",
10
+ "dependencies": {
11
+ "bcryptjs": "^3.0.3",
12
+ "connect-mongo": "^6.0.0",
13
+ "cors": "^2.8.6",
14
+ "dotenv": "^17.4.2",
15
+ "express": "^5.2.1",
16
+ "express-session": "^1.19.0",
17
+ "mongoose": "^9.5.0"
18
+ },
19
+ "devDependencies": {
20
+ "nodemon": "^3.1.14"
21
+ }
22
+ }
@@ -0,0 +1,9 @@
1
+ const mongoose = require("mongoose");
2
+
3
+ const connectDatabase = async () => {
4
+ const mongoUri = process.env.MONGO_URI || "mongodb://127.0.0.1:27017/sims";
5
+ await mongoose.connect(mongoUri);
6
+ console.log("MongoDB connected (SIMS database)");
7
+ };
8
+
9
+ module.exports = connectDatabase;
@@ -0,0 +1,115 @@
1
+ const bcrypt = require("bcryptjs");
2
+ const User = require("../models/User");
3
+ const { strongPasswordError } = require("../utils/passwordPolicy");
4
+
5
+ const normalize = (value) => String(value || "").trim();
6
+ const normalizeEmail = (email) => String(email || "").trim().toLowerCase();
7
+
8
+ const register = async (req, res) => {
9
+ try {
10
+ const username = normalize(req.body.username);
11
+ const email = normalizeEmail(req.body.email);
12
+ const password = String(req.body.password || "");
13
+ if (!username || !email || !password) {
14
+ return res.status(400).json({ message: "Username, email and password are required" });
15
+ }
16
+ if (username.length < 3) {
17
+ return res.status(400).json({ message: "Username must be at least 3 characters" });
18
+ }
19
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
20
+ return res.status(400).json({ message: "Enter a valid email address." });
21
+ }
22
+ const pwdErr = strongPasswordError(password);
23
+ if (pwdErr) {
24
+ return res.status(400).json({ message: pwdErr });
25
+ }
26
+ const existingUser = await User.findOne({ username });
27
+ if (existingUser) {
28
+ return res.status(409).json({ message: "Username already exists" });
29
+ }
30
+ const existingEmail = await User.findOne({ email });
31
+ if (existingEmail) {
32
+ return res.status(409).json({ message: "Email already registered" });
33
+ }
34
+ const passwordHash = await bcrypt.hash(password, 10);
35
+ await User.create({ username, email, passwordHash });
36
+ return res.status(201).json({ message: "User created successfully" });
37
+ } catch (error) {
38
+ return res.status(500).json({ message: error.message });
39
+ }
40
+ };
41
+
42
+ const login = async (req, res) => {
43
+ try {
44
+ const username = normalize(req.body.username);
45
+ const password = String(req.body.password || "");
46
+ if (!username || !password) {
47
+ return res.status(400).json({ message: "Username and password are required" });
48
+ }
49
+ const user = await User.findOne({ username });
50
+ if (!user) {
51
+ return res.status(401).json({ message: "Invalid credentials" });
52
+ }
53
+ const isValid = await bcrypt.compare(password, user.passwordHash);
54
+ if (!isValid) {
55
+ return res.status(401).json({ message: "Invalid credentials" });
56
+ }
57
+ req.session.userId = user._id;
58
+ req.session.username = user.username;
59
+ return res.json({ message: "Login successful", username: user.username });
60
+ } catch (error) {
61
+ return res.status(500).json({ message: error.message });
62
+ }
63
+ };
64
+
65
+ const currentUser = (req, res) => {
66
+ if (!req.session.userId) {
67
+ return res.status(401).json({ message: "Unauthorized" });
68
+ }
69
+ return res.json({ username: req.session.username });
70
+ };
71
+
72
+ const logout = (req, res) => {
73
+ req.session.destroy(() => {
74
+ res.clearCookie("connect.sid");
75
+ res.json({ message: "Logged out" });
76
+ });
77
+ };
78
+
79
+ const forgotPassword = async (req, res) => {
80
+ try {
81
+ const email = normalizeEmail(req.body.email);
82
+ const newPassword = String(req.body.newPassword || "");
83
+ const confirmPassword = String(req.body.confirmPassword || "");
84
+ if (!email) {
85
+ return res.status(400).json({ success: false, message: "Email is required." });
86
+ }
87
+ if (!newPassword) {
88
+ return res.status(400).json({ success: false, message: "New password is required." });
89
+ }
90
+ if (!confirmPassword) {
91
+ return res.status(400).json({ success: false, message: "Confirm password is required." });
92
+ }
93
+ if (newPassword !== confirmPassword) {
94
+ return res.status(400).json({
95
+ success: false,
96
+ message: "New password and confirm password must match.",
97
+ });
98
+ }
99
+ const pwdErr = strongPasswordError(newPassword);
100
+ if (pwdErr) {
101
+ return res.status(400).json({ success: false, message: pwdErr });
102
+ }
103
+ const user = await User.findOne({ email });
104
+ if (!user) {
105
+ return res.status(404).json({ success: false, message: "User not found" });
106
+ }
107
+ user.passwordHash = await bcrypt.hash(newPassword, 10);
108
+ await user.save();
109
+ return res.json({ success: true, message: "Password reset successfully" });
110
+ } catch (error) {
111
+ return res.status(500).json({ success: false, message: error.message });
112
+ }
113
+ };
114
+
115
+ module.exports = { register, login, currentUser, logout, forgotPassword };