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
package/lib/prompts.js CHANGED
@@ -1,100 +1,100 @@
1
- import inquirer from 'inquirer';
2
-
3
- const validateName = (name) => {
4
- return /^[a-zA-Z0-9-_]+$/.test(name) ? true : 'Project name may only include letters, numbers, underscores and dashes.';
5
- };
6
-
7
- export const getProjectDetails = async (options = {}) => {
8
- const questions = [
9
- {
10
- type: 'input',
11
- name: 'projectName',
12
- message: 'Project name:',
13
- default: 'nodejs-service',
14
- validate: validateName,
15
- when: !options.projectName
16
- },
17
- {
18
- type: 'select',
19
- name: 'language',
20
- message: 'Select Language:',
21
- choices: ['JavaScript', 'TypeScript'],
22
- default: 'TypeScript',
23
- when: !options.language
24
- },
25
- {
26
- type: 'select',
27
- name: 'architecture',
28
- message: 'Select Architecture:',
29
- choices: ['MVC', 'Clean Architecture'],
30
- default: 'MVC',
31
- when: !options.architecture
32
- },
33
- {
34
- type: 'select',
35
- name: 'viewEngine',
36
- message: 'Select View Engine:',
37
- choices: ['None', 'EJS', 'Pug'],
38
- when: (answers) => (options.architecture || answers.architecture) === 'MVC' && !options.viewEngine,
39
- default: 'None'
40
- },
41
- {
42
- type: 'select',
43
- name: 'database',
44
- message: 'Select Database:',
45
- choices: ['None', 'MySQL', 'PostgreSQL', 'MongoDB'],
46
- default: 'None',
47
- when: !options.database
48
- },
49
- {
50
- type: 'input',
51
- name: 'dbName',
52
- message: 'Database Name:',
53
- default: 'demo',
54
- validate: validateName,
55
- when: (answers) => !options.dbName && (options.database || answers.database) !== 'None'
56
- },
57
- {
58
- type: 'select',
59
- name: 'communication',
60
- message: 'Microservices Communication:',
61
- choices: ['REST APIs', 'GraphQL', 'Kafka'],
62
- default: 'REST APIs',
63
- when: !options.communication
64
- },
65
- {
66
- type: 'select',
67
- name: 'caching',
68
- message: 'Caching Layer:',
69
- choices: ['None', 'Redis', 'Memory Cache'],
70
- default: 'None',
71
- when: (answers) => !options.caching && (options.database || answers.database) !== 'None'
72
- },
73
- {
74
- type: 'select',
75
- name: 'ciProvider',
76
- message: 'Select CI/CD Provider:',
77
- choices: ['None', 'GitHub Actions', 'Jenkins', 'GitLab CI'],
78
- default: 'None',
79
- when: !options.ciProvider
80
- },
81
- {
82
- type: 'select',
83
- name: 'includeSecurity',
84
- message: 'Include Enterprise Security Hardening (Big Tech Standard: Snyk, SonarQube)?',
85
- choices: ['No', 'Yes'],
86
- default: "No",
87
- when: (answers) => !options.includeSecurity && (options.ciProvider || answers.ciProvider) !== 'None'
88
- }
89
- ];
90
-
91
- const answers = await inquirer.prompt(questions);
92
- const result = { ...options, ...answers };
93
-
94
- // Normalize includeSecurity to boolean if it's a string from the select prompt
95
- if (typeof result.includeSecurity === 'string') {
96
- result.includeSecurity = result.includeSecurity === 'Yes';
97
- }
98
-
99
- return result;
100
- };
1
+ import inquirer from 'inquirer';
2
+
3
+ const validateName = (name) => {
4
+ return /^[a-zA-Z0-9-_]+$/.test(name) ? true : 'Project name may only include letters, numbers, underscores and dashes.';
5
+ };
6
+
7
+ export const getProjectDetails = async (options = {}) => {
8
+ const questions = [
9
+ {
10
+ type: 'input',
11
+ name: 'projectName',
12
+ message: 'Project name:',
13
+ default: 'nodejs-service',
14
+ validate: validateName,
15
+ when: !options.projectName
16
+ },
17
+ {
18
+ type: 'select',
19
+ name: 'language',
20
+ message: 'Select Language:',
21
+ choices: ['JavaScript', 'TypeScript'],
22
+ default: 'TypeScript',
23
+ when: !options.language
24
+ },
25
+ {
26
+ type: 'select',
27
+ name: 'architecture',
28
+ message: 'Select Architecture:',
29
+ choices: ['MVC', 'Clean Architecture'],
30
+ default: 'MVC',
31
+ when: !options.architecture
32
+ },
33
+ {
34
+ type: 'select',
35
+ name: 'viewEngine',
36
+ message: 'Select View Engine:',
37
+ choices: ['None', 'EJS', 'Pug'],
38
+ when: (answers) => (options.architecture || answers.architecture) === 'MVC' && !options.viewEngine,
39
+ default: 'None'
40
+ },
41
+ {
42
+ type: 'select',
43
+ name: 'database',
44
+ message: 'Select Database:',
45
+ choices: ['None', 'MySQL', 'PostgreSQL', 'MongoDB'],
46
+ default: 'None',
47
+ when: !options.database
48
+ },
49
+ {
50
+ type: 'input',
51
+ name: 'dbName',
52
+ message: 'Database Name:',
53
+ default: 'demo',
54
+ validate: validateName,
55
+ when: (answers) => !options.dbName && (options.database || answers.database) !== 'None'
56
+ },
57
+ {
58
+ type: 'select',
59
+ name: 'communication',
60
+ message: 'Microservices Communication:',
61
+ choices: ['REST APIs', 'GraphQL', 'Kafka'],
62
+ default: 'REST APIs',
63
+ when: !options.communication
64
+ },
65
+ {
66
+ type: 'select',
67
+ name: 'caching',
68
+ message: 'Caching Layer:',
69
+ choices: ['None', 'Redis', 'Memory Cache'],
70
+ default: 'None',
71
+ when: (answers) => !options.caching && (options.database || answers.database) !== 'None'
72
+ },
73
+ {
74
+ type: 'select',
75
+ name: 'ciProvider',
76
+ message: 'Select CI/CD Provider:',
77
+ choices: ['None', 'GitHub Actions', 'Jenkins', 'GitLab CI'],
78
+ default: 'None',
79
+ when: !options.ciProvider
80
+ },
81
+ {
82
+ type: 'select',
83
+ name: 'includeSecurity',
84
+ message: 'Include Enterprise Security Hardening (Big Tech Standard: Snyk, SonarQube)?',
85
+ choices: ['No', 'Yes'],
86
+ default: "No",
87
+ when: (answers) => !options.includeSecurity && (options.ciProvider || answers.ciProvider) !== 'None'
88
+ }
89
+ ];
90
+
91
+ const answers = await inquirer.prompt(questions);
92
+ const result = { ...options, ...answers };
93
+
94
+ // Normalize includeSecurity to boolean if it's a string from the select prompt
95
+ if (typeof result.includeSecurity === 'string') {
96
+ result.includeSecurity = result.includeSecurity === 'Yes';
97
+ }
98
+
99
+ return result;
100
+ };
package/package.json CHANGED
@@ -1,67 +1,78 @@
1
- {
2
- "name": "nodejs-quickstart-structure",
3
- "version": "1.18.1",
4
- "type": "module",
5
- "description": "The ultimate nodejs quickstart structure CLI to scaffold Node.js microservices with MVC or Clean Architecture",
6
- "main": "bin/index.js",
7
- "bin": {
8
- "nodejs-quickstart": "./bin/index.js"
9
- },
10
- "scripts": {
11
- "test": "echo \"Error: no test specified\" && exit 1",
12
- "test:e2e": "npm run test:e2e:windows",
13
- "test:e2e:windows": "node scripts/validate-windows.js",
14
- "test:e2e:linux": "node scripts/validate-linux.js",
15
- "test:verify:mongo": "node scripts/verify-migration.js",
16
- "docs:dev": "vitepress dev docs",
17
- "docs:build": "vitepress build docs",
18
- "docs:preview": "vitepress preview docs",
19
- "security:check": "npm audit && npm run snyk:test",
20
- "snyk:test": "snyk test"
21
- },
22
- "keywords": [
23
- "nodejs",
24
- "node",
25
- "quickstart",
26
- "structure",
27
- "cli",
28
- "scaffold",
29
- "mvc",
30
- "clean-architecture",
31
- "microservices",
32
- "backend",
33
- "generator",
34
- "boilerplate"
35
- ],
36
- "author": "Pau Dang <[EMAIL_ADDRESS]>",
37
- "repository": {
38
- "type": "git",
39
- "url": "git+https://github.com/paudang/nodejs-quickstart-structure.git"
40
- },
41
- "bugs": {
42
- "url": "https://github.com/paudang/nodejs-quickstart-structure/issues"
43
- },
44
- "homepage": "https://github.com/paudang/nodejs-quickstart-structure#readme",
45
- "license": "ISC",
46
- "dependencies": {
47
- "chalk": "^5.4.1",
48
- "commander": "^14.0.3",
49
- "ejs": "^5.0.1",
50
- "fs-extra": "^11.3.0",
51
- "inquirer": "^13.3.2"
52
- },
53
- "overrides": {
54
- "esbuild": "^0.25.0"
55
- },
56
- "devDependencies": {
57
- "snyk": "^1.1303.2",
58
- "vitepress": "^1.0.0-rc.45"
59
- },
60
- "files": [
61
- "bin",
62
- "lib",
63
- "templates",
64
- "README.md",
65
- "CHANGELOG.md"
66
- ]
67
- }
1
+ {
2
+ "name": "nodejs-quickstart-structure",
3
+ "version": "1.19.1",
4
+ "type": "module",
5
+ "description": "The ultimate nodejs quickstart structure CLI to scaffold Node.js microservices with MVC or Clean Architecture",
6
+ "main": "bin/index.js",
7
+ "bin": {
8
+ "nodejs-quickstart": "./bin/index.js"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1",
12
+ "test:e2e": "npm run test:e2e:windows",
13
+ "test:e2e:windows": "node scripts/validate-windows.js",
14
+ "test:e2e:linux": "node scripts/validate-linux.js",
15
+ "test:verify:mongo": "node scripts/verify-migration.js",
16
+ "docs:dev": "vitepress dev docs",
17
+ "docs:build": "vitepress build docs",
18
+ "docs:preview": "vitepress preview docs",
19
+ "security:check": "npm audit && npm run snyk:test",
20
+ "snyk:test": "snyk test"
21
+ },
22
+ "keywords": [
23
+ "nodejs",
24
+ "node",
25
+ "quickstart",
26
+ "structure",
27
+ "cli",
28
+ "scaffold",
29
+ "mvc",
30
+ "clean-architecture",
31
+ "microservices",
32
+ "backend",
33
+ "generator",
34
+ "boilerplate"
35
+ ],
36
+ "author": "Pau Dang <[phucdangb1400718@gmail.com]>",
37
+ "contributors": [
38
+ {
39
+ "name": "Pau Dang",
40
+ "url": "https://github.com/paudang"
41
+ },
42
+ {
43
+ "name": "Gemini AI",
44
+ "url": "https://deepmind.google/technologies/gemini/",
45
+ "role": "AI Architectural Assistant"
46
+ }
47
+ ],
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/paudang/nodejs-quickstart-structure.git"
51
+ },
52
+ "bugs": {
53
+ "url": "https://github.com/paudang/nodejs-quickstart-structure/issues"
54
+ },
55
+ "homepage": "https://github.com/paudang/nodejs-quickstart-structure#readme",
56
+ "license": "ISC",
57
+ "dependencies": {
58
+ "chalk": "^5.4.1",
59
+ "commander": "^14.0.3",
60
+ "ejs": "^5.0.1",
61
+ "fs-extra": "^11.3.0",
62
+ "inquirer": "^13.3.2"
63
+ },
64
+ "overrides": {
65
+ "esbuild": "^0.25.0"
66
+ },
67
+ "devDependencies": {
68
+ "snyk": "^1.1303.2",
69
+ "vitepress": "^1.0.0-rc.45"
70
+ },
71
+ "files": [
72
+ "bin",
73
+ "lib",
74
+ "templates",
75
+ "README.md",
76
+ "CHANGELOG.md"
77
+ ]
78
+ }
@@ -1,9 +1,9 @@
1
- class User {
2
- constructor(id, name, email) {
3
- this.id = id;
4
- this.name = name;
5
- this.email = email;
6
- }
7
- }
8
-
9
- module.exports = User;
1
+ class User {
2
+ constructor(id, name, email) {
3
+ this.id = id;
4
+ this.name = name;
5
+ this.email = email;
6
+ }
7
+ }
8
+
9
+ module.exports = User;
@@ -1,14 +1,14 @@
1
- class ApiError extends Error {
2
- constructor(statusCode, message, isOperational = true, stack = '') {
3
- super(message);
4
- this.statusCode = statusCode;
5
- this.isOperational = isOperational;
6
- if (stack) {
7
- this.stack = stack;
8
- } else {
9
- Error.captureStackTrace(this, this.constructor);
10
- }
11
- }
12
- }
13
-
14
- module.exports = { ApiError };
1
+ class ApiError extends Error {
2
+ constructor(statusCode, message, isOperational = true, stack = '') {
3
+ super(message);
4
+ this.statusCode = statusCode;
5
+ this.isOperational = isOperational;
6
+ if (stack) {
7
+ this.stack = stack;
8
+ } else {
9
+ Error.captureStackTrace(this, this.constructor);
10
+ }
11
+ }
12
+ }
13
+
14
+ module.exports = { ApiError };
@@ -1,10 +1,11 @@
1
- const { ApiError } = require('./ApiError');
2
- const HTTP_STATUS = require('../utils/httpCodes');
3
-
4
- class BadRequestError extends ApiError {
5
- constructor(message = 'Bad request') {
6
- super(HTTP_STATUS.BAD_REQUEST, message);
7
- }
8
- }
9
-
10
- module.exports = { BadRequestError };
1
+ const { ApiError } = require('./ApiError');
2
+ const HTTP_STATUS = require('../utils/httpCodes');
3
+ const ERROR_MESSAGES = require('../utils/errorMessages');
4
+
5
+ class BadRequestError extends ApiError {
6
+ constructor(message = ERROR_MESSAGES.BAD_REQUEST) {
7
+ super(HTTP_STATUS.BAD_REQUEST, message);
8
+ }
9
+ }
10
+
11
+ module.exports = { BadRequestError };
@@ -1,21 +1,22 @@
1
- const { BadRequestError } = require('@/errors/BadRequestError');
2
- const { ApiError } = require('@/errors/ApiError');
3
- const HTTP_STATUS = require('@/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
+ const { BadRequestError } = require('@/errors/BadRequestError');
2
+ const { ApiError } = require('@/errors/ApiError');
3
+ const HTTP_STATUS = require('@/utils/httpCodes');
4
+ const ERROR_MESSAGES = require('@/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,10 +1,11 @@
1
- const { ApiError } = require('./ApiError');
2
- const HTTP_STATUS = require('../utils/httpCodes');
3
-
4
- class NotFoundError extends ApiError {
5
- constructor(message = 'Resource not found') {
6
- super(HTTP_STATUS.NOT_FOUND, message);
7
- }
8
- }
9
-
10
- module.exports = { NotFoundError };
1
+ const { ApiError } = require('./ApiError');
2
+ const HTTP_STATUS = require('../utils/httpCodes');
3
+ const ERROR_MESSAGES = require('../utils/errorMessages');
4
+
5
+ class NotFoundError extends ApiError {
6
+ constructor(message = ERROR_MESSAGES.RESOURCE_NOT_FOUND) {
7
+ super(HTTP_STATUS.NOT_FOUND, message);
8
+ }
9
+ }
10
+
11
+ module.exports = { NotFoundError };
@@ -1,21 +1,22 @@
1
- const { NotFoundError } = require('@/errors/NotFoundError');
2
- const { ApiError } = require('@/errors/ApiError');
3
- const HTTP_STATUS = require('@/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
+ const { NotFoundError } = require('@/errors/NotFoundError');
2
+ const { ApiError } = require('@/errors/ApiError');
3
+ const HTTP_STATUS = require('@/utils/httpCodes');
4
+ const ERROR_MESSAGES = require('@/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,56 +1,56 @@
1
- const startServer = require('./infrastructure/webserver/server');
2
- const logger = require('./infrastructure/log/logger');
3
- <% if (communication === 'Kafka') { -%>
4
- const { connectKafka } = require('./infrastructure/messaging/kafkaClient');
5
- <% } -%>
6
- <%_ if (database !== 'None') { -%>
7
- // Database Sync
8
- <%_ if (database !== 'None') { -%>
9
- <%_ if (database === 'MongoDB') { -%>
10
- const connectDB = require('./infrastructure/database/database');
11
- <%_ } else { -%>
12
- const sequelize = require('./infrastructure/database/database');
13
- <%_ } -%>
14
- <%_ } -%>
15
-
16
- const syncDatabase = async () => {
17
- let retries = 30;
18
- while (retries) {
19
- try {
20
- <%_ if (database === 'MongoDB') { -%>
21
- await connectDB();
22
- <%_ } else { -%>
23
- await sequelize.sync();
24
- <%_ } -%>
25
- logger.info('Database synced');
26
- // Start the web server after DB sync
27
- startServer();
28
- <%_ if (communication === 'Kafka') { -%>
29
- // Connect Kafka
30
- connectKafka().then(async () => {
31
- logger.info('Kafka connected');
32
- }).catch(err => {
33
- logger.error('Failed to connect to Kafka:', err);
34
- });
35
- <%_ } -%>
36
- break;
37
- } catch (error) {
38
- logger.error('Error syncing database:', error);
39
- retries -= 1;
40
- logger.info(`Retries left: ${retries}`);
41
- await new Promise(res => setTimeout(res, 5000));
42
- }
43
- }
44
- };
45
- syncDatabase();
46
- <%_ } else { -%>
47
- startServer();
48
- <%_ if (communication === 'Kafka') { -%>
49
- // Connect Kafka
50
- connectKafka().then(async () => {
51
- logger.info('Kafka connected');
52
- }).catch(err => {
53
- logger.error('Failed to connect to Kafka:', err);
54
- });
55
- <%_ } -%>
1
+ const startServer = require('./infrastructure/webserver/server');
2
+ const logger = require('./infrastructure/log/logger');
3
+ <% if (communication === 'Kafka') { -%>
4
+ const { connectKafka } = require('./infrastructure/messaging/kafkaClient');
5
+ <% } -%>
6
+ <%_ if (database !== 'None') { -%>
7
+ // Database Sync
8
+ <%_ if (database !== 'None') { -%>
9
+ <%_ if (database === 'MongoDB') { -%>
10
+ const connectDB = require('./infrastructure/database/database');
11
+ <%_ } else { -%>
12
+ const sequelize = require('./infrastructure/database/database');
13
+ <%_ } -%>
14
+ <%_ } -%>
15
+
16
+ const syncDatabase = async () => {
17
+ let retries = 30;
18
+ while (retries) {
19
+ try {
20
+ <%_ if (database === 'MongoDB') { -%>
21
+ await connectDB();
22
+ <%_ } else { -%>
23
+ await sequelize.sync();
24
+ <%_ } -%>
25
+ logger.info('Database synced');
26
+ // Start the web server after DB sync
27
+ startServer();
28
+ <%_ if (communication === 'Kafka') { -%>
29
+ // Connect Kafka
30
+ connectKafka().then(async () => {
31
+ logger.info('Kafka connected');
32
+ }).catch(err => {
33
+ logger.error('Failed to connect to Kafka:', err);
34
+ });
35
+ <%_ } -%>
36
+ break;
37
+ } catch (error) {
38
+ logger.error('Error syncing database:', error);
39
+ retries -= 1;
40
+ logger.info(`Retries left: ${retries}`);
41
+ await new Promise(res => setTimeout(res, 5000));
42
+ }
43
+ }
44
+ };
45
+ syncDatabase();
46
+ <%_ } else { -%>
47
+ startServer();
48
+ <%_ if (communication === 'Kafka') { -%>
49
+ // Connect Kafka
50
+ connectKafka().then(async () => {
51
+ logger.info('Kafka connected');
52
+ }).catch(err => {
53
+ logger.error('Failed to connect to Kafka:', err);
54
+ });
55
+ <%_ } -%>
56
56
  <%_ } -%>