nodejs-quickstart-structure 1.18.1 → 1.19.1

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 (235) hide show
  1. package/CHANGELOG.md +309 -294
  2. package/LICENSE +15 -15
  3. package/README.md +2 -1
  4. package/lib/generator.js +139 -139
  5. package/lib/modules/app-setup.js +401 -401
  6. package/lib/modules/caching-setup.js +76 -73
  7. package/lib/modules/config-files.js +151 -151
  8. package/lib/modules/database-setup.js +116 -116
  9. package/lib/modules/kafka-setup.js +249 -191
  10. package/lib/modules/project-setup.js +32 -31
  11. package/lib/prompts.js +100 -100
  12. package/package.json +78 -67
  13. package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
  14. package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
  15. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  16. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  17. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  18. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  19. package/templates/clean-architecture/js/src/index.js.ejs +55 -55
  20. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
  21. package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
  22. package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
  23. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  24. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  25. package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
  26. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
  27. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
  28. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  29. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  30. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
  31. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
  32. package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
  33. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
  34. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  35. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  36. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
  37. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  38. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  39. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
  40. package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
  41. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
  42. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  43. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  44. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
  45. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
  46. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  47. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  48. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  49. package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
  50. package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
  51. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
  52. package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
  53. package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
  54. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  55. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  56. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  57. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  58. package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
  59. package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
  60. package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
  61. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  62. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  63. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  64. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  65. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
  66. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
  67. package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
  68. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
  69. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  70. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  71. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
  72. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  73. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
  74. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  75. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
  76. package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
  77. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  78. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  79. package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
  80. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
  81. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  82. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  83. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  84. package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  85. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
  86. package/templates/common/.cursorrules.ejs +60 -60
  87. package/templates/common/.dockerignore +12 -12
  88. package/templates/common/.env.example.ejs +41 -41
  89. package/templates/common/.gitattributes +46 -0
  90. package/templates/common/.gitlab-ci.yml.ejs +86 -86
  91. package/templates/common/.lintstagedrc +6 -6
  92. package/templates/common/.prettierrc +7 -7
  93. package/templates/common/Dockerfile +73 -73
  94. package/templates/common/Jenkinsfile.ejs +87 -87
  95. package/templates/common/README.md.ejs +294 -270
  96. package/templates/common/SECURITY.md +20 -20
  97. package/templates/common/_github/workflows/ci.yml.ejs +46 -46
  98. package/templates/common/_github/workflows/security.yml.ejs +36 -36
  99. package/templates/common/_gitignore +5 -5
  100. package/templates/common/_husky/pre-commit +4 -4
  101. package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
  102. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  103. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
  104. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  105. package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
  106. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  107. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
  108. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  109. package/templates/common/caching/js/memoryCache.js.ejs +60 -60
  110. package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
  111. package/templates/common/caching/js/redisClient.js.ejs +75 -75
  112. package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
  113. package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
  114. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  115. package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
  116. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  117. package/templates/common/database/js/database.js.ejs +19 -19
  118. package/templates/common/database/js/database.spec.js.ejs +56 -56
  119. package/templates/common/database/js/models/User.js.ejs +79 -53
  120. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  121. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  122. package/templates/common/database/js/mongoose.js.ejs +33 -33
  123. package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
  124. package/templates/common/database/ts/database.spec.ts.ejs +56 -56
  125. package/templates/common/database/ts/database.ts.ejs +21 -21
  126. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  127. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  128. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  129. package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
  130. package/templates/common/database/ts/mongoose.ts.ejs +28 -28
  131. package/templates/common/docker-compose.yml.ejs +159 -159
  132. package/templates/common/ecosystem.config.js.ejs +40 -40
  133. package/templates/common/eslint.config.mjs.ejs +77 -77
  134. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  135. package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
  136. package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
  137. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  138. package/templates/common/jest.config.js.ejs +32 -32
  139. package/templates/common/jest.e2e.config.js.ejs +8 -8
  140. package/templates/common/kafka/js/config/kafka.js +9 -9
  141. package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
  142. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  143. package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
  144. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  145. package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
  146. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  147. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  148. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  149. package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
  150. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  151. package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
  152. package/templates/common/kafka/ts/config/kafka.ts +7 -7
  153. package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
  154. package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
  155. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  156. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  157. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  158. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  159. package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
  160. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  161. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  162. package/templates/common/migrate-mongo-config.js.ejs +31 -31
  163. package/templates/common/migrations/init.js.ejs +23 -23
  164. package/templates/common/package.json.ejs +119 -118
  165. package/templates/common/prompts/add-feature.md.ejs +26 -26
  166. package/templates/common/prompts/project-context.md.ejs +43 -43
  167. package/templates/common/prompts/troubleshoot.md.ejs +28 -28
  168. package/templates/common/public/css/style.css +147 -147
  169. package/templates/common/scripts/run-e2e.js.ejs +63 -63
  170. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  171. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  172. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  173. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  174. package/templates/common/sonar-project.properties.ejs +27 -27
  175. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  176. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  177. package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
  178. package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
  179. package/templates/common/swagger.yml.ejs +118 -66
  180. package/templates/common/tsconfig.json +22 -22
  181. package/templates/common/views/ejs/index.ejs +55 -55
  182. package/templates/common/views/pug/index.pug +40 -40
  183. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  184. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  185. package/templates/mvc/js/src/config/env.js.ejs +46 -46
  186. package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
  187. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  188. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  189. package/templates/mvc/js/src/errors/ApiError.js +14 -14
  190. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  191. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  192. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  193. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  194. package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
  195. package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
  196. package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
  197. package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
  198. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  199. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  200. package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
  201. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  202. package/templates/mvc/js/src/index.js.ejs +136 -136
  203. package/templates/mvc/js/src/routes/api.js +10 -8
  204. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  205. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  206. package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
  207. package/templates/mvc/js/src/utils/httpCodes.js +9 -9
  208. package/templates/mvc/js/src/utils/logger.js +40 -40
  209. package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
  210. package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
  211. package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
  212. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  213. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  214. package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
  215. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  216. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  217. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  218. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  219. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
  220. package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
  221. package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
  222. package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
  223. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  224. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  225. package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
  226. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  227. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  228. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  229. package/templates/mvc/ts/src/routes/api.ts +12 -10
  230. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  231. package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  232. package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
  233. package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
  234. package/templates/mvc/ts/src/utils/logger.ts +36 -36
  235. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
@@ -0,0 +1,48 @@
1
+ const UpdateUser = require('@/usecases/UpdateUser');
2
+ const UserRepository = require('@/infrastructure/repositories/UserRepository');
3
+ <%_ if (caching !== 'None') { -%>
4
+ const cacheService = require('<% if (caching === "Redis") { %>@/infrastructure/caching/redisClient<% } else { %>@/infrastructure/caching/memoryCache<% } %>');
5
+ <%_ } -%>
6
+
7
+ jest.mock('@/infrastructure/repositories/UserRepository');
8
+ <%_ if (caching !== 'None') { -%>
9
+ jest.mock('<% if (caching === "Redis") { %>@/infrastructure/caching/redisClient<% } else { %>@/infrastructure/caching/memoryCache<% } %>', () => ({
10
+ get: jest.fn(),
11
+ set: jest.fn(),
12
+ del: jest.fn()
13
+ }));
14
+ <%_ } -%>
15
+
16
+ describe('UpdateUser UseCase', () => {
17
+ let updateUser;
18
+ let mockUserRepository;
19
+
20
+ beforeEach(() => {
21
+ mockUserRepository = new UserRepository();
22
+ updateUser = new UpdateUser(mockUserRepository);
23
+ jest.clearAllMocks();
24
+ });
25
+
26
+ it('should update and return the user', async () => {
27
+ const id = 1;
28
+ const data = { name: 'Updated Name' };
29
+ const expectedUser = { id, name: 'Updated Name', email: 'test@test.com' };
30
+
31
+ mockUserRepository.update.mockResolvedValue(expectedUser);
32
+
33
+ const result = await updateUser.execute(id, data);
34
+
35
+ expect(mockUserRepository.update).toHaveBeenCalledWith(id, data);
36
+ expect(result).toEqual(expectedUser);
37
+ <%_ if (caching !== 'None') { -%>
38
+ expect(cacheService.del).toHaveBeenCalledWith('users:all');
39
+ <%_ } %>
40
+ });
41
+
42
+ it('should throw an error if repository fails', async () => {
43
+ const error = new Error('Database error');
44
+ mockUserRepository.update.mockRejectedValue(error);
45
+
46
+ await expect(updateUser.execute(1, { name: 'Test' })).rejects.toThrow(error);
47
+ });
48
+ });
@@ -0,0 +1,14 @@
1
+ const ERROR_MESSAGES = {
2
+ USER_NOT_FOUND: 'User not found',
3
+ RESOURCE_NOT_FOUND: 'Resource not found',
4
+ INVALID_USER_DATA: 'Invalid user event data',
5
+ INTERNAL_SERVER_ERROR: 'Internal Server Error',
6
+ BAD_REQUEST: 'Bad Request',
7
+ FETCH_USERS_ERROR: 'Error fetching users',
8
+ CREATE_USER_ERROR: 'Error creating user',
9
+ UPDATE_USER_ERROR: 'Error updating user',
10
+ DELETE_USER_ERROR: 'Error deleting user',
11
+ DATABASE_PING_FAILED: 'Health Check Database Ping Failed',
12
+ };
13
+
14
+ module.exports = ERROR_MESSAGES;
@@ -1,9 +1,9 @@
1
- const HTTP_STATUS = {
2
- OK: 200,
3
- CREATED: 201,
4
- BAD_REQUEST: 400,
5
- NOT_FOUND: 404,
6
- INTERNAL_SERVER_ERROR: 500
7
- };
8
-
9
- module.exports = HTTP_STATUS;
1
+ const HTTP_STATUS = {
2
+ OK: 200,
3
+ CREATED: 201,
4
+ BAD_REQUEST: 400,
5
+ NOT_FOUND: 404,
6
+ INTERNAL_SERVER_ERROR: 500
7
+ };
8
+
9
+ module.exports = HTTP_STATUS;
@@ -1,46 +1,46 @@
1
- import dotenv from 'dotenv';
2
- import { z } from 'zod';
3
- import logger from '@/infrastructure/log/logger';
4
-
5
- if (process.env.NODE_ENV !== 'production') {
6
- dotenv.config();
7
- }
8
-
9
- const envSchema = z.object({
10
- NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
11
- PORT: z.string().transform(Number).default('3000'),
12
- <%_ if (database !== 'None') { -%>
13
- DB_HOST: z.string(),
14
- <%_ if (database === 'MySQL') { -%>
15
- DB_USER: z.string(),
16
- DB_PASSWORD: z.string(),
17
- DB_NAME: z.string(),
18
- DB_PORT: z.string().transform(Number),
19
- <%_ } else if (database === 'PostgreSQL') { -%>
20
- DB_USER: z.string(),
21
- DB_PASSWORD: z.string(),
22
- DB_NAME: z.string(),
23
- DB_PORT: z.string().transform(Number),
24
- <%_ } else if (database === 'MongoDB') { -%>
25
- DB_NAME: z.string(),
26
- DB_PORT: z.string().transform(Number),
27
- <%_ } -%>
28
- <%_ } -%>
29
- <%_ if (caching === 'Redis') { -%>
30
- REDIS_HOST: z.string(),
31
- REDIS_PORT: z.string().transform(Number),
32
- REDIS_PASSWORD: z.string().optional(),
33
- <%_ } -%>
34
- <%_ if (communication === 'Kafka') { -%>
35
- KAFKA_BROKER: z.string(),
36
- <%_ } -%>
37
- });
38
-
39
- const _env = envSchema.safeParse(process.env);
40
-
41
- if (!_env.success) {
42
- logger.error('❌ Invalid environment variables:', _env.error.format());
43
- process.exit(1);
44
- }
45
-
46
- export const env = _env.data;
1
+ import dotenv from 'dotenv';
2
+ import { z } from 'zod';
3
+ import logger from '@/infrastructure/log/logger';
4
+
5
+ if (process.env.NODE_ENV !== 'production') {
6
+ dotenv.config();
7
+ }
8
+
9
+ const envSchema = z.object({
10
+ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
11
+ PORT: z.string().transform(Number).default('3000'),
12
+ <%_ if (database !== 'None') { -%>
13
+ DB_HOST: z.string(),
14
+ <%_ if (database === 'MySQL') { -%>
15
+ DB_USER: z.string(),
16
+ DB_PASSWORD: z.string(),
17
+ DB_NAME: z.string(),
18
+ DB_PORT: z.string().transform(Number),
19
+ <%_ } else if (database === 'PostgreSQL') { -%>
20
+ DB_USER: z.string(),
21
+ DB_PASSWORD: z.string(),
22
+ DB_NAME: z.string(),
23
+ DB_PORT: z.string().transform(Number),
24
+ <%_ } else if (database === 'MongoDB') { -%>
25
+ DB_NAME: z.string(),
26
+ DB_PORT: z.string().transform(Number),
27
+ <%_ } -%>
28
+ <%_ } -%>
29
+ <%_ if (caching === 'Redis') { -%>
30
+ REDIS_HOST: z.string(),
31
+ REDIS_PORT: z.string().transform(Number),
32
+ REDIS_PASSWORD: z.string().optional(),
33
+ <%_ } -%>
34
+ <%_ if (communication === 'Kafka') { -%>
35
+ KAFKA_BROKER: z.string(),
36
+ <%_ } -%>
37
+ });
38
+
39
+ const _env = envSchema.safeParse(process.env);
40
+
41
+ if (!_env.success) {
42
+ logger.error('❌ Invalid environment variables:', _env.error.format());
43
+ process.exit(1);
44
+ }
45
+
46
+ export const env = _env.data;
@@ -1,6 +1,6 @@
1
- <% if (communication === 'REST APIs' || communication === 'Kafka') { %>import path from 'path';
2
- import YAML from 'yamljs';
3
-
4
- const swaggerDocument = YAML.load(path.join(__dirname, 'swagger.yml'));
5
-
6
- export default swaggerDocument;<% } %>
1
+ <% if (communication === 'REST APIs' || communication === 'Kafka') { %>import path from 'path';
2
+ import YAML from 'yamljs';
3
+
4
+ const swaggerDocument = YAML.load(path.join(__dirname, 'swagger.yml'));
5
+
6
+ export default swaggerDocument;<% } %>
@@ -1,7 +1,7 @@
1
- export class User {
2
- constructor(
3
- public id: number | string | null,
4
- public name: string,
5
- public email: string
6
- ) { }
7
- }
1
+ export class User {
2
+ constructor(
3
+ public id: number | string | null,
4
+ public name: string,
5
+ public email: string
6
+ ) { }
7
+ }
@@ -1,15 +1,15 @@
1
- export class ApiError extends Error {
2
- statusCode: number;
3
- isOperational: boolean;
4
-
5
- constructor(statusCode: number, message: string, isOperational = true, stack = '') {
6
- super(message);
7
- this.statusCode = statusCode;
8
- this.isOperational = isOperational;
9
- if (stack) {
10
- this.stack = stack;
11
- } else {
12
- Error.captureStackTrace(this, this.constructor);
13
- }
14
- }
15
- }
1
+ export class ApiError extends Error {
2
+ statusCode: number;
3
+ isOperational: boolean;
4
+
5
+ constructor(statusCode: number, message: string, isOperational = true, stack = '') {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ this.isOperational = isOperational;
9
+ if (stack) {
10
+ this.stack = stack;
11
+ } else {
12
+ Error.captureStackTrace(this, this.constructor);
13
+ }
14
+ }
15
+ }
@@ -1,21 +1,22 @@
1
- import { BadRequestError } from '@/errors/BadRequestError';
2
- import { ApiError } from '@/errors/ApiError';
3
- import { HTTP_STATUS } from '@/utils/httpCodes';
4
-
5
- describe('BadRequestError', () => {
6
- it('should extend ApiError', () => {
7
- const error = new BadRequestError();
8
- expect(error).toBeInstanceOf(ApiError);
9
- });
10
-
11
- it('should have default message "Bad request"', () => {
12
- const error = new BadRequestError();
13
- expect(error.message).toBe('Bad request');
14
- expect(error.statusCode).toBe(HTTP_STATUS.BAD_REQUEST);
15
- });
16
-
17
- it('should accept a custom message', () => {
18
- const error = new BadRequestError('Custom bad request');
19
- expect(error.message).toBe('Custom bad request');
20
- });
21
- });
1
+ import { BadRequestError } from '@/errors/BadRequestError';
2
+ import { ApiError } from '@/errors/ApiError';
3
+ import { HTTP_STATUS } from '@/utils/httpCodes';
4
+ import { ERROR_MESSAGES } from '@/utils/errorMessages';
5
+
6
+ describe('BadRequestError', () => {
7
+ it('should extend ApiError', () => {
8
+ const error = new BadRequestError();
9
+ expect(error).toBeInstanceOf(ApiError);
10
+ });
11
+
12
+ it('should have default message "Bad Request"', () => {
13
+ const error = new BadRequestError();
14
+ expect(error.message).toBe(ERROR_MESSAGES.BAD_REQUEST);
15
+ expect(error.statusCode).toBe(HTTP_STATUS.BAD_REQUEST);
16
+ });
17
+
18
+ it('should accept a custom message', () => {
19
+ const error = new BadRequestError('Custom bad request');
20
+ expect(error.message).toBe('Custom bad request');
21
+ });
22
+ });
@@ -1,8 +1,9 @@
1
- import { ApiError } from '@/errors/ApiError';
2
- import { HTTP_STATUS } from '@/utils/httpCodes';
3
-
4
- export class BadRequestError extends ApiError {
5
- constructor(message = 'Bad request') {
6
- super(HTTP_STATUS.BAD_REQUEST, message);
7
- }
8
- }
1
+ import { ApiError } from '@/errors/ApiError';
2
+ import { HTTP_STATUS } from '@/utils/httpCodes';
3
+ import { ERROR_MESSAGES } from '@/utils/errorMessages';
4
+
5
+ export class BadRequestError extends ApiError {
6
+ constructor(message: string = ERROR_MESSAGES.BAD_REQUEST) {
7
+ super(HTTP_STATUS.BAD_REQUEST, message);
8
+ }
9
+ }
@@ -1,21 +1,22 @@
1
- import { NotFoundError } from '@/errors/NotFoundError';
2
- import { ApiError } from '@/errors/ApiError';
3
- import { HTTP_STATUS } from '@/utils/httpCodes';
4
-
5
- describe('NotFoundError', () => {
6
- it('should extend ApiError', () => {
7
- const error = new NotFoundError();
8
- expect(error).toBeInstanceOf(ApiError);
9
- });
10
-
11
- it('should have default message "Resource not found"', () => {
12
- const error = new NotFoundError();
13
- expect(error.message).toBe('Resource not found');
14
- expect(error.statusCode).toBe(HTTP_STATUS.NOT_FOUND);
15
- });
16
-
17
- it('should accept a custom message', () => {
18
- const error = new NotFoundError('User not found');
19
- expect(error.message).toBe('User not found');
20
- });
21
- });
1
+ import { NotFoundError } from '@/errors/NotFoundError';
2
+ import { ApiError } from '@/errors/ApiError';
3
+ import { HTTP_STATUS } from '@/utils/httpCodes';
4
+ import { ERROR_MESSAGES } from '@/utils/errorMessages';
5
+
6
+ describe('NotFoundError', () => {
7
+ it('should extend ApiError', () => {
8
+ const error = new NotFoundError();
9
+ expect(error).toBeInstanceOf(ApiError);
10
+ });
11
+
12
+ it('should have default message "Resource not found"', () => {
13
+ const error = new NotFoundError();
14
+ expect(error.message).toBe(ERROR_MESSAGES.RESOURCE_NOT_FOUND);
15
+ expect(error.statusCode).toBe(HTTP_STATUS.NOT_FOUND);
16
+ });
17
+
18
+ it('should accept a custom message', () => {
19
+ const error = new NotFoundError(ERROR_MESSAGES.USER_NOT_FOUND);
20
+ expect(error.message).toBe(ERROR_MESSAGES.USER_NOT_FOUND);
21
+ });
22
+ });
@@ -1,8 +1,9 @@
1
- import { ApiError } from '@/errors/ApiError';
2
- import { HTTP_STATUS } from '@/utils/httpCodes';
3
-
4
- export class NotFoundError extends ApiError {
5
- constructor(message = 'Resource not found') {
6
- super(HTTP_STATUS.NOT_FOUND, message);
7
- }
8
- }
1
+ import { ApiError } from '@/errors/ApiError';
2
+ import { HTTP_STATUS } from '@/utils/httpCodes';
3
+ import { ERROR_MESSAGES } from '@/utils/errorMessages';
4
+
5
+ export class NotFoundError extends ApiError {
6
+ constructor(message: string = ERROR_MESSAGES.RESOURCE_NOT_FOUND) {
7
+ super(HTTP_STATUS.NOT_FOUND, message);
8
+ }
9
+ }
@@ -1,140 +1,140 @@
1
- import { env } from '@/config/env';
2
- import express from 'express';
3
- import cors from 'cors';
4
- import helmet from 'helmet';
5
- import hpp from 'hpp';
6
- import rateLimit from 'express-rate-limit';
7
- import logger from '@/infrastructure/log/logger';
8
- import morgan from 'morgan';
9
- import { errorMiddleware } from '@/utils/errorMiddleware';
10
- import { setupGracefulShutdown } from '@/utils/gracefulShutdown';
11
- import healthRoutes from '@/interfaces/routes/healthRoute';
12
- <% if (communication === 'REST APIs' || communication === 'Kafka') { -%>
13
- import userRoutes from '@/interfaces/routes/userRoutes';
14
- import swaggerUi from 'swagger-ui-express';
15
- import swaggerSpecs from '@/config/swagger';<% } %>
16
- <%_ if (communication === 'Kafka') { -%>import { kafkaService } from '@/infrastructure/messaging/kafkaClient';<%_ } -%>
17
- <%_ if (communication === 'GraphQL') { -%>
18
- import { ApolloServer } from '@apollo/server';
19
- import { expressMiddleware } from '@as-integrations/express4';
20
- import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
21
- import { unwrapResolverError } from '@apollo/server/errors';
22
- import { ApiError } from '@/errors/ApiError';
23
- import { typeDefs, resolvers } from '@/interfaces/graphql';
24
- import { gqlContext, MyContext } from '@/interfaces/graphql/context';
25
- <%_ } -%>
26
-
27
- const app = express();
28
- const port = env.PORT;
29
-
30
- // Security Middleware
31
- <%_ if (communication === 'GraphQL') { -%>
32
- app.use(helmet({
33
- crossOriginEmbedderPolicy: false,
34
- contentSecurityPolicy: {
35
- directives: {
36
- imgSrc: [`'self'`, 'data:', 'apollo-server-landing-page.cdn.apollographql.com'],
37
- scriptSrc: [`'self'`, `https: 'unsafe-inline'`],
38
- manifestSrc: [`'self'`, 'apollo-server-landing-page.cdn.apollographql.com'],
39
- frameSrc: [`'self'`, 'sandbox.embed.apollographql.com'],
40
- },
41
- },
42
- }));
43
- <%_ } else { -%>
44
- app.use(helmet());
45
- <%_ } -%>
46
- app.use(hpp());
47
- app.use(cors({ origin: '*', methods: ['GET', 'POST', 'PUT', 'DELETE'] }));
48
- const limiter = rateLimit({ windowMs: 10 * 60 * 1000, max: 100 });
49
- app.use(limiter);
50
-
51
- app.use(express.json());
52
- app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
53
-
54
- <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
55
- app.use('/api/users', userRoutes);
56
- <%_ } -%>
57
- <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
58
- app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
59
- <%_ } -%>
60
- app.use('/health', healthRoutes);
61
-
62
- // Start Server Logic
63
- const startServer = async () => {
64
- <%_ if (communication === 'GraphQL') { -%>
65
- // GraphQL Setup
66
- const apolloServer = new ApolloServer<MyContext>({
67
- typeDefs,
68
- resolvers,
69
- plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
70
- formatError: (formattedError, error) => {
71
- const originalError = unwrapResolverError(error);
72
- if (originalError instanceof ApiError) {
73
- return {
74
- ...formattedError,
75
- message: originalError.message,
76
- extensions: {
77
- ...formattedError.extensions,
78
- code: originalError.statusCode.toString(),
79
- }
80
- };
81
- }
82
-
83
- logger.error(`GraphQL Error: ${formattedError.message}`);
84
- if (originalError instanceof Error && originalError.stack && process.env.NODE_ENV === 'development') {
85
- logger.error(originalError.stack);
86
- }
87
- return formattedError;
88
- },
89
- });
90
- await apolloServer.start();
91
- app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
92
- <%_ } -%>
93
- app.use(errorMiddleware);
94
- const server = app.listen(port, () => {
95
- logger.info(`Server running on port ${port}`);
96
- <%_ if (communication === 'Kafka') { -%>
97
- kafkaService.connect()
98
- .then(async () => {
99
- logger.info('Kafka connected');
100
- })
101
- .catch(err => {
102
- logger.error('Failed to connect to Kafka after retries:', (err as Error).message);
103
- });
104
- <%_ } -%>
105
- });
106
-
107
- setupGracefulShutdown(server<% if(communication === 'Kafka') { %>, kafkaService<% } %>);
108
- };
109
-
110
- <%_ if (database !== 'None') { -%>
111
- // Database Sync
112
- <%_ if (database !== 'None') { -%>
113
- import <% if (database === 'MongoDB') { %>connectDB<% } else { %>sequelize<% } %> from '@/infrastructure/database/database';
114
- <%_ } -%>
115
-
116
- const syncDatabase = async () => {
117
- let retries = 30;
118
- while (retries) {
119
- try {
120
- <%_ if (database === 'MongoDB') { -%>
121
- await connectDB();
122
- <%_ } else { -%>
123
- await sequelize.sync();
124
- <%_ } -%>
125
- logger.info('Database synced');
126
- await startServer();
127
- break;
128
- } catch (error) {
129
- logger.error('Error syncing database:', error);
130
- retries -= 1;
131
- logger.info(`Retries left: ${retries}`);
132
- await new Promise(res => setTimeout(res, 5000));
133
- }
134
- }
135
- };
136
-
137
- syncDatabase();
138
- <%_ } else { -%>
139
- startServer();
1
+ import { env } from '@/config/env';
2
+ import express from 'express';
3
+ import cors from 'cors';
4
+ import helmet from 'helmet';
5
+ import hpp from 'hpp';
6
+ import rateLimit from 'express-rate-limit';
7
+ import logger from '@/infrastructure/log/logger';
8
+ import morgan from 'morgan';
9
+ import { errorMiddleware } from '@/utils/errorMiddleware';
10
+ import { setupGracefulShutdown } from '@/utils/gracefulShutdown';
11
+ import healthRoutes from '@/interfaces/routes/healthRoute';
12
+ <% if (communication === 'REST APIs' || communication === 'Kafka') { -%>
13
+ import userRoutes from '@/interfaces/routes/userRoutes';
14
+ import swaggerUi from 'swagger-ui-express';
15
+ import swaggerSpecs from '@/config/swagger';<% } %>
16
+ <%_ if (communication === 'Kafka') { -%>import { kafkaService } from '@/infrastructure/messaging/kafkaClient';<%_ } -%>
17
+ <%_ if (communication === 'GraphQL') { -%>
18
+ import { ApolloServer } from '@apollo/server';
19
+ import { expressMiddleware } from '@as-integrations/express4';
20
+ import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
21
+ import { unwrapResolverError } from '@apollo/server/errors';
22
+ import { ApiError } from '@/errors/ApiError';
23
+ import { typeDefs, resolvers } from '@/interfaces/graphql';
24
+ import { gqlContext, MyContext } from '@/interfaces/graphql/context';
25
+ <%_ } -%>
26
+
27
+ const app = express();
28
+ const port = env.PORT;
29
+
30
+ // Security Middleware
31
+ <%_ if (communication === 'GraphQL') { -%>
32
+ app.use(helmet({
33
+ crossOriginEmbedderPolicy: false,
34
+ contentSecurityPolicy: {
35
+ directives: {
36
+ imgSrc: [`'self'`, 'data:', 'apollo-server-landing-page.cdn.apollographql.com'],
37
+ scriptSrc: [`'self'`, `https: 'unsafe-inline'`],
38
+ manifestSrc: [`'self'`, 'apollo-server-landing-page.cdn.apollographql.com'],
39
+ frameSrc: [`'self'`, 'sandbox.embed.apollographql.com'],
40
+ },
41
+ },
42
+ }));
43
+ <%_ } else { -%>
44
+ app.use(helmet());
45
+ <%_ } -%>
46
+ app.use(hpp());
47
+ app.use(cors({ origin: '*', methods: ['GET', 'POST', 'PUT', 'DELETE'] }));
48
+ const limiter = rateLimit({ windowMs: 10 * 60 * 1000, max: 100 });
49
+ app.use(limiter);
50
+
51
+ app.use(express.json());
52
+ app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
53
+
54
+ <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
55
+ app.use('/api/users', userRoutes);
56
+ <%_ } -%>
57
+ <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
58
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
59
+ <%_ } -%>
60
+ app.use('/health', healthRoutes);
61
+
62
+ // Start Server Logic
63
+ const startServer = async () => {
64
+ <%_ if (communication === 'GraphQL') { -%>
65
+ // GraphQL Setup
66
+ const apolloServer = new ApolloServer<MyContext>({
67
+ typeDefs,
68
+ resolvers,
69
+ plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
70
+ formatError: (formattedError, error) => {
71
+ const originalError = unwrapResolverError(error);
72
+ if (originalError instanceof ApiError) {
73
+ return {
74
+ ...formattedError,
75
+ message: originalError.message,
76
+ extensions: {
77
+ ...formattedError.extensions,
78
+ code: originalError.statusCode.toString(),
79
+ }
80
+ };
81
+ }
82
+
83
+ logger.error(`GraphQL Error: ${formattedError.message}`);
84
+ if (originalError instanceof Error && originalError.stack && process.env.NODE_ENV === 'development') {
85
+ logger.error(originalError.stack);
86
+ }
87
+ return formattedError;
88
+ },
89
+ });
90
+ await apolloServer.start();
91
+ app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
92
+ <%_ } -%>
93
+ app.use(errorMiddleware);
94
+ const server = app.listen(port, () => {
95
+ logger.info(`Server running on port ${port}`);
96
+ <%_ if (communication === 'Kafka') { -%>
97
+ kafkaService.connect()
98
+ .then(async () => {
99
+ logger.info('Kafka connected');
100
+ })
101
+ .catch(err => {
102
+ logger.error('Failed to connect to Kafka after retries:', (err as Error).message);
103
+ });
104
+ <%_ } -%>
105
+ });
106
+
107
+ setupGracefulShutdown(server<% if(communication === 'Kafka') { %>, kafkaService<% } %>);
108
+ };
109
+
110
+ <%_ if (database !== 'None') { -%>
111
+ // Database Sync
112
+ <%_ if (database !== 'None') { -%>
113
+ import <% if (database === 'MongoDB') { %>connectDB<% } else { %>sequelize<% } %> from '@/infrastructure/database/database';
114
+ <%_ } -%>
115
+
116
+ const syncDatabase = async () => {
117
+ let retries = 30;
118
+ while (retries) {
119
+ try {
120
+ <%_ if (database === 'MongoDB') { -%>
121
+ await connectDB();
122
+ <%_ } else { -%>
123
+ await sequelize.sync();
124
+ <%_ } -%>
125
+ logger.info('Database synced');
126
+ await startServer();
127
+ break;
128
+ } catch (error) {
129
+ logger.error('Error syncing database:', error);
130
+ retries -= 1;
131
+ logger.info(`Retries left: ${retries}`);
132
+ await new Promise(res => setTimeout(res, 5000));
133
+ }
134
+ }
135
+ };
136
+
137
+ syncDatabase();
138
+ <%_ } else { -%>
139
+ startServer();
140
140
  <%_ } -%>