nodejs-quickstart-structure 2.0.0 → 2.1.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 (161) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +44 -40
  3. package/bin/index.js +6 -3
  4. package/lib/generator.js +10 -4
  5. package/lib/modules/app-setup.js +76 -6
  6. package/lib/modules/auth-setup.js +143 -0
  7. package/lib/modules/caching-setup.js +8 -1
  8. package/lib/modules/config-files.js +10 -0
  9. package/lib/modules/database-setup.js +2 -1
  10. package/lib/modules/project-setup.js +1 -0
  11. package/lib/prompts.js +40 -1
  12. package/package.json +5 -4
  13. package/templates/clean-architecture/js/src/domain/models/User.js +3 -1
  14. package/templates/clean-architecture/js/src/index.js.ejs +2 -0
  15. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +12 -3
  16. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +25 -2
  17. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +27 -0
  18. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +3 -0
  19. package/templates/clean-architecture/js/src/infrastructure/webserver/server.spec.js.ejs +49 -0
  20. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.spec.js.ejs +14 -0
  21. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +41 -4
  22. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +69 -4
  23. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -6
  24. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +38 -21
  25. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +10 -5
  26. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +32 -10
  27. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +1 -1
  28. package/templates/clean-architecture/js/src/interfaces/routes/api.js.ejs +15 -0
  29. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +4 -0
  30. package/templates/clean-architecture/js/src/usecases/CreateUser.js.ejs +34 -0
  31. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +3 -2
  32. package/templates/clean-architecture/js/src/usecases/DeleteUser.js.ejs +27 -0
  33. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js.ejs +36 -0
  34. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +14 -0
  35. package/templates/clean-architecture/js/src/usecases/GetUserById.js.ejs +36 -0
  36. package/templates/clean-architecture/js/src/usecases/GetUserById.spec.js.ejs +48 -0
  37. package/templates/clean-architecture/js/src/usecases/UpdateUser.js.ejs +28 -0
  38. package/templates/clean-architecture/js/src/utils/errorMessages.js +1 -0
  39. package/templates/clean-architecture/js/src/utils/httpCodes.js +2 -0
  40. package/templates/clean-architecture/ts/src/config/env.ts.ejs +12 -3
  41. package/templates/clean-architecture/ts/src/domain/user.ts +3 -1
  42. package/templates/clean-architecture/ts/src/index.ts.ejs +4 -0
  43. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +55 -9
  44. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +32 -3
  45. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +26 -6
  46. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +57 -15
  47. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +38 -23
  48. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +14 -8
  49. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +33 -10
  50. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +15 -5
  51. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +1 -1
  52. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +9 -1
  53. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts.ejs +16 -0
  54. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +3 -2
  55. package/templates/clean-architecture/ts/src/usecases/createUser.ts.ejs +35 -0
  56. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +1 -0
  57. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts.ejs +24 -0
  58. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts.ejs +21 -0
  59. package/templates/clean-architecture/ts/src/usecases/getUserById.spec.ts.ejs +47 -0
  60. package/templates/clean-architecture/ts/src/usecases/getUserById.ts.ejs +23 -0
  61. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +1 -0
  62. package/templates/clean-architecture/ts/src/usecases/updateUser.ts.ejs +25 -0
  63. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +1 -0
  64. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +1 -0
  65. package/templates/common/.cursorrules.ejs +9 -0
  66. package/templates/common/.env.example.ejs +17 -10
  67. package/templates/common/.gitlab-ci.yml.ejs +3 -1
  68. package/templates/common/Jenkinsfile.ejs +10 -1
  69. package/templates/common/README.md.ejs +64 -19
  70. package/templates/common/_circleci/config.yml.ejs +96 -0
  71. package/templates/common/_github/workflows/ci.yml.ejs +1 -1
  72. package/templates/common/auth/js/controllers/authController.js.ejs +168 -0
  73. package/templates/common/auth/js/controllers/authController.spec.js.ejs +148 -0
  74. package/templates/common/auth/js/middleware/authMiddleware.js.ejs +58 -0
  75. package/templates/common/auth/js/middleware/authMiddleware.spec.js.ejs +108 -0
  76. package/templates/common/auth/js/routes/authRoutes.js.ejs +16 -0
  77. package/templates/common/auth/js/services/jwtService.js.ejs +54 -0
  78. package/templates/common/auth/js/services/jwtService.spec.js.ejs +84 -0
  79. package/templates/common/auth/ts/controllers/authController.spec.ts.ejs +161 -0
  80. package/templates/common/auth/ts/controllers/authController.ts.ejs +165 -0
  81. package/templates/common/auth/ts/middleware/authMiddleware.spec.ts.ejs +128 -0
  82. package/templates/common/auth/ts/middleware/authMiddleware.ts.ejs +59 -0
  83. package/templates/common/auth/ts/routes/authRoutes.ts.ejs +20 -0
  84. package/templates/common/auth/ts/services/jwtService.spec.ts.ejs +89 -0
  85. package/templates/common/auth/ts/services/jwtService.ts.ejs +60 -0
  86. package/templates/common/bitbucket-pipelines.yml.ejs +60 -0
  87. package/templates/common/caching/clean/js/CreateUser.js.ejs +14 -5
  88. package/templates/common/caching/clean/js/DeleteUser.js.ejs +2 -1
  89. package/templates/common/caching/clean/js/GetUserById.js.ejs +39 -0
  90. package/templates/common/caching/clean/js/UpdateUser.js.ejs +2 -1
  91. package/templates/common/caching/clean/ts/createUser.ts.ejs +14 -6
  92. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +2 -1
  93. package/templates/common/caching/clean/ts/getUserById.ts.ejs +32 -0
  94. package/templates/common/caching/clean/ts/updateUser.ts.ejs +2 -2
  95. package/templates/common/database/js/models/User.js.ejs +14 -1
  96. package/templates/common/database/js/models/User.js.mongoose.ejs +7 -0
  97. package/templates/common/database/js/models/User.spec.js.ejs +12 -0
  98. package/templates/common/database/ts/models/User.spec.ts.ejs +10 -0
  99. package/templates/common/database/ts/models/User.ts.ejs +17 -0
  100. package/templates/common/database/ts/models/User.ts.mongoose.ejs +8 -0
  101. package/templates/common/docker-compose.yml.ejs +14 -0
  102. package/templates/common/ecosystem.config.js.ejs +9 -3
  103. package/templates/common/eslint.config.mjs.ejs +3 -0
  104. package/templates/common/jest.config.js.ejs +11 -9
  105. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +1 -1
  106. package/templates/common/kafka/js/services/kafkaService.js.ejs +1 -1
  107. package/templates/common/migrations/init.js.ejs +5 -4
  108. package/templates/common/package.json.ejs +10 -2
  109. package/templates/common/prompts/project-context.md.ejs +8 -1
  110. package/templates/common/scripts/run-e2e.js.ejs +26 -10
  111. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +149 -107
  112. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +88 -47
  113. package/templates/common/swagger.yml.ejs +148 -0
  114. package/templates/common/tsconfig.eslint.json +15 -0
  115. package/templates/common/tsconfig.json +2 -1
  116. package/templates/common/views/ejs/index.ejs +264 -30
  117. package/templates/common/views/ejs/login.ejs.ejs +244 -0
  118. package/templates/common/views/ejs/signup.ejs.ejs +282 -0
  119. package/templates/common/views/pug/index.pug +269 -38
  120. package/templates/common/views/pug/login.pug.ejs +195 -0
  121. package/templates/common/views/pug/signup.pug.ejs +241 -0
  122. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +6 -0
  123. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +6 -0
  124. package/templates/mvc/js/src/config/env.js.ejs +12 -3
  125. package/templates/mvc/js/src/controllers/userController.js.ejs +29 -5
  126. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +27 -12
  127. package/templates/mvc/js/src/graphql/context.js.ejs +14 -3
  128. package/templates/mvc/js/src/graphql/context.spec.js.ejs +36 -21
  129. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +10 -5
  130. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +32 -10
  131. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +1 -1
  132. package/templates/mvc/js/src/index.js.ejs +16 -3
  133. package/templates/mvc/js/src/routes/api.js.ejs +14 -0
  134. package/templates/mvc/js/src/routes/api.spec.js.ejs +3 -0
  135. package/templates/mvc/js/src/utils/errorMessages.js +1 -0
  136. package/templates/mvc/js/src/utils/httpCodes.js +1 -0
  137. package/templates/mvc/ts/src/config/env.ts.ejs +12 -3
  138. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +95 -7
  139. package/templates/mvc/ts/src/controllers/userController.ts.ejs +68 -11
  140. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +36 -23
  141. package/templates/mvc/ts/src/graphql/context.ts.ejs +15 -6
  142. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +32 -10
  143. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +15 -5
  144. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +1 -1
  145. package/templates/mvc/ts/src/index.ts.ejs +15 -3
  146. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +6 -0
  147. package/templates/mvc/ts/src/routes/api.ts.ejs +15 -0
  148. package/templates/mvc/ts/src/utils/errorMessages.ts +1 -0
  149. package/templates/mvc/ts/src/utils/httpCodes.ts +1 -0
  150. package/templates/clean-architecture/js/src/interfaces/routes/api.js +0 -12
  151. package/templates/clean-architecture/js/src/usecases/CreateUser.js +0 -14
  152. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +0 -11
  153. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +0 -12
  154. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +0 -11
  155. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +0 -13
  156. package/templates/clean-architecture/ts/src/usecases/createUser.ts +0 -13
  157. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +0 -9
  158. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +0 -10
  159. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +0 -9
  160. package/templates/mvc/js/src/routes/api.js +0 -10
  161. package/templates/mvc/ts/src/routes/api.ts +0 -12
package/CHANGELOG.md CHANGED
@@ -1,4 +1,30 @@
1
1
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2
+
3
+ ## [2.1.0] - 2026-04-20
4
+
5
+ ### Added
6
+ - **Pluggable JWT Authentication**: Introduced a robust, production-ready authentication system.
7
+ - Supports **Access & Refresh Token Rotation** for enhanced security.
8
+ - Integrated **Token Revocation (Blacklisting)** via Redis or Memory Cache.
9
+ - Secure logout flows and theft detection for refresh tokens.
10
+ - Seamless integration with both REST and GraphQL protocols across all architectures.
11
+ - **VitePress Documentation Upgrade**: Detailed [Authentication Blueprint](https://paudang.github.io/nodejs-quickstart-structure/blueprints/authentication) and cross-feature documentation updates.
12
+ - **Security Hardening**: Resolved moderate vulnerabilities in `vite` and `vitepress` by implementing version overrides and dependency upgrades (VitePress v1.6.4+).
13
+ - **Interactive README 2.0**: Completely redesigned the project landing page with a "Choose Your Journey" dual-workflow (Web UI vs CLI) and visual action previews.
14
+
15
+ ---
16
+
17
+ ## [2.0.1] - 2026-04-07
18
+
19
+ ### Added
20
+ - **Universal CI/CD Support (Phase 8)**: Expanded the generator's CI/CD capabilities to include out-of-the-box support for **Bitbucket Pipelines** and **CircleCI**.
21
+ - **Modernized Pipe & Orb Integration**:
22
+ - Bitbucket templates now utilize official Atlassian Pipes for automated Snyk security scans and SonarCloud analysis.
23
+ - CircleCI configurations (v2.1) are optimized with official Orbs (`circleci/node`, `snyk/snyk`) for advanced dependency caching and security execution.
24
+ - **Project Blueprints (CI/CD Guide)**: Launched a comprehensive "CI/CD Setup Guide" in the VitePress documentation, providing step-by-step configuration workflows for all 5 supported platforms (GitHub, GitLab, Jenkins, Bitbucket, CircleCI).
25
+ - **CLI Ecosystem Sync**: Updated the interactive prompts and command-line flags to seamlessly integrate the new CI/CD choices while maintaining 100% backward compatibility.
26
+ - **Enterprise Readness Documentation**: Updated the generated `README.md` templates to officially include Bitbucket and CircleCI in the supported feature set.
27
+
2
28
 
3
29
  ## [2.0.0] - 2026-04-02
4
30
 
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Node.js Quickstart Generator
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/nodejs-quickstart-structure.svg?style=flat-square)](https://www.npmjs.com/package/nodejs-quickstart-structure)
4
+ ![Total Clones](https://img.shields.io/badge/dynamic/json?color=brightgreen&label=total%20clones&query=total_clones&url=https%3A%2F%2Fraw.githubusercontent.com%2Fpaudang%2Fnodejs-quickstart-structure%2Foutput%2Ftotal_stats.json&style=flat-square)
4
5
  [![npm total downloads](https://img.shields.io/npm/dt/nodejs-quickstart-structure?style=flat-square&color=emerald&label=Downloads)](https://www.npmjs.com/package/nodejs-quickstart-structure)
5
6
  [![npm monthly downloads](https://img.shields.io/npm/dm/nodejs-quickstart-structure.svg?style=flat-square)](https://www.npmjs.com/package/nodejs-quickstart-structure)
6
7
  [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg?style=flat-square)](https://opensource.org/licenses/ISC)
@@ -9,57 +10,44 @@
9
10
  | **Metric** | **Insight** |
10
11
  | :--- | :--- |
11
12
  | 🔥 **4,000+** | Downloads on npm |
12
- | 🚀 **1,200+** | Recent GitHub Clones |
13
+ | 🚀 **1,500+** | Recent GitHub Clones |
13
14
  | 🌍 **Trusted by** | Devs from **Google**, **Viblo**, and global tech teams |
14
15
 
15
16
  ---
16
17
 
17
- A powerful CLI tool to scaffold production-ready Node.js microservices with built-in best practices. Choose between **MVC** or **Clean Architecture**, **JavaScript** or **TypeScript**, and your preferred tech stack in seconds.
18
-
19
- 🎯 **[Try the Next-Gen Web UI Configurator!](https://paudang.github.io/nodejs-quickstart-structure/)**
20
- *Generate your exact architecture in the browser with real-time folder simulation.*
21
-
22
- ![Demo](docs/demo.gif)
23
-
24
- ---
25
-
26
- ## 🆕 What's New in v2.0.0
27
-
28
- The v2.0.0 release is a major leap forward, turning the generator into a **Community Standard** for Node.js development:
29
-
30
- - **Next-Gen Web UI Configurator**: A modern, browser-based visual project simulator. Click your stack and copy the generated zero-prompt CLI command instantly! [Try it here](https://paudang.github.io/nodejs-quickstart-structure/).
31
- - **🦾 AI-Native Foundation**: Built-in `.cursorrules` and Agent skills optimized for **Cursor** & AI coding assistants.
32
- - **🏗️ Enterprise Clean Architecture**: High-fidelity structure for professional Microservices (TS/JS).
33
- - **🛡️ Hardened Security**: Integrated Snyk & SonarCloud logic in the core templates.
34
- - **⚡ Zero-Prompt Workflow**: Generate projects with a single CLI command—no more answering prompts manually.
35
-
36
- ---
18
+ A powerful ecosystem to scaffold production-ready Node.js microservices with built-in best practices. Choose between **MVC** or **Clean Architecture**, **JavaScript** or **TypeScript**, and your preferred tech stack in seconds.
37
19
 
38
20
  ## 📌 Table of Contents
39
21
 
40
- - [🚀 Quick Start](#-quick-start)
22
+ - [🚀 Quick Start](#-choose-your-journey)
23
+ - [🆕 What's New](#-whats-new-in-v21-the-authentication-release)
41
24
  - [✨ Key Features](#-key-features)
42
25
  - [🛡️ Professional Standards](#-professional-standards)
43
- - [🧩 1,680+ Project Combinations](#-1680-project-combinations)
26
+ - [🧩 5,280+ Project Combinations](#-5280-project-combinations)
44
27
  - [⚙️ Configuration Options](#-configuration-options)
45
28
  - [🏗️ Generated Project Structure](#-generated-project-structure)
46
29
  - [📖 Documentation](#-documentation)
47
30
  - [🗺️ Support & Roadmap](#️-roadmap--support)
48
31
 
49
- ---
32
+ ## 🚀 Choose Your Journey
33
+
34
+ | **Path A: Next-Gen Web UI** (Recommended ⭐️) | **Path B: Interactive CLI** |
35
+ | :--- | :--- |
36
+ | <a href="https://paudang.github.io/nodejs-quickstart-structure/#configurator"><img src="docs/public/v2-preview.png" width="100%" alt="UI Preview"></a> | <img src="docs/demo.gif" width="100%" alt="CLI Demo"> |
37
+ | [Try Visual Configurator →](https://paudang.github.io/nodejs-quickstart-structure/#configurator) | [See CLI Commands ↓](#-path-b-interactive-cli) |
38
+ | ✨ **Visual Preview**: Real-time folder simulation. | ⚡ **Fast & Direct**: Quickly scaffold in terminal. |
39
+ | 🛠️ **Zero-Prompt**: Paste a tailored command. | 🦾 **AI-Ready**: Generates `.cursorrules`. |
50
40
 
51
- ## 🚀 Quick Start
41
+ ---
52
42
 
53
- Generate your professional Node.js project in seconds without installing anything globally:
43
+ ### 🦾 Path B: Interactive CLI
44
+ **Scaffold your project directly from your terminal in seconds.**
54
45
 
55
46
  ```bash
56
47
  npx nodejs-quickstart-structure@latest init
57
48
  ```
58
49
 
59
- ### Installation (Optional)
60
-
61
- If you prefer to install it globally:
62
-
50
+ *Or install globally:*
63
51
  ```bash
64
52
  npm install -g nodejs-quickstart-structure
65
53
  # Then run:
@@ -68,6 +56,20 @@ nodejs-quickstart init
68
56
 
69
57
  ---
70
58
 
59
+ ## 🆕 What's New in v2.1 (The Authentication Release)
60
+
61
+ The v2.1.0 release is a major leap forward, turning the generator into a **Community Standard**:
62
+
63
+ - **🔐 Pluggable JWT Authentication**: Production-ready access & refresh token patterns with automatic PM2/Environment configuration.
64
+ - **🦾 AI-Native Foundation**: Built-in `.cursorrules` optimized for **Cursor** & AI agents—projects are "Born to be Autonomously Coded."
65
+ - **🖼️ Next-Gen Web UI**: A browser-based visual project simulator with real-time folder previews.
66
+ - **🏗️ Enterprise Clean Architecture**: High-fidelity structure for professional Microservices (TS/JS).
67
+ - **🛡️ Hardened Security**: Integrated Snyk & SonarCloud logic in core templates.
68
+ - **⚡ Zero-Prompt Workflow**: Generate projects with a single CLI command.
69
+
70
+ ---
71
+
72
+
71
73
  ## ✨ Key Features
72
74
 
73
75
  - **Interactive CLI**: Smooth, guided configuration process.
@@ -76,6 +78,7 @@ nodejs-quickstart init
76
78
  - **Database Ready**: Pre-configured for **MySQL**, **PostgreSQL**, or **MongoDB**.
77
79
  - **Communication Patterns**: Supports **REST**, **GraphQL** (Apollo), and **Kafka** (Event-driven).
78
80
  - **Multi-layer Caching**: Integrated **Redis** or built-in **Memory Cache**.
81
+ - **Pluggable Authentication**: Built-in **JWT** support (Refresh/Access tokens).
79
82
  - **AI-Native Optimized**: specifically designed for **Cursor** and AI agents, including built-in `.cursorrules` and Agent Skill prompts. 🚀
80
83
 
81
84
  ---
@@ -88,20 +91,20 @@ We don't just generate boilerplate; we generate **production-ready** foundations
88
91
  - **🛡️ Enterprise Security**: Integrated **Snyk (SCA)**, **SonarCloud (SAST)**, `Helmet`, `HPP`, and Rate-Limiting.
89
92
  - **🚨 Robust Error Handling**: Centralized global error middleware with custom error classes (`ApiError`, `NotFoundError`, etc.) — consistent across REST & GraphQL.
90
93
  - **🧪 Testing Excellence**: Integrated `Jest` and `Supertest` with **>80% Unit Test coverage** out of the box.
91
- - **🔄 DevOps & CI/CD**: Optimized **Multi-Stage Dockerfiles**, health checks, infrastructure retry logic, and workflows for **GitHub Actions**, **Jenkins**, and **GitLab CI**.
94
+ - **🔄 DevOps & CI/CD**: Optimized **Multi-Stage Dockerfiles**, health checks, infrastructure retry logic, and workflows for **GitHub Actions**, **Jenkins**, **GitLab CI**, **CircleCI**, and **Bitbucket Pipelines**.
92
95
  - **🚀 Scalable Deployment**: Integrated **PM2 Ecosystem** config for zero-downtime reloads.
93
96
 
94
97
  ---
95
98
 
96
- ## 🧩 1,680+ Project Combinations
99
+ ## 🧩 5,280+ Project Combinations
97
100
 
98
101
  The CLI supports a massive number of configurations to fit your exact needs:
99
102
 
100
- - **240 Core Combinations**:
101
- - **MVC Architecture**: 180 variants (Languages × View Engines × Databases × Communication Patterns × Caching)
102
- - **Clean Architecture**: 60 variants (Languages × Databases × Communication Patterns × Caching)
103
- - **1,680+ Total Scenarios**:
104
- - Every combination can be generated across 3 CI/CD providers.
103
+ - **480 Core Combinations**:
104
+ - **MVC Architecture**: 360 variants (Languages × View Engines × Databases × Communication Patterns × Caching × Auth)
105
+ - **Clean Architecture**: 120 variants (Languages × Databases × Communication Patterns × Caching × Auth)
106
+ - **5,280+ Total Scenarios**:
107
+ - Every combination can be generated across 5 CI/CD providers.
105
108
  - Optional **Enterprise-Grade Security Hardening** doubles the scenarios.
106
109
  - Every single scenario is verified to be compatible with our **80% Coverage Threshold** policy.
107
110
 
@@ -117,8 +120,9 @@ The CLI will guide you through:
117
120
  5. **Database**: `MySQL` | `PostgreSQL` | `MongoDB`
118
121
  6. **Communication**: `REST` | `GraphQL` | `Kafka`
119
122
  7. **Caching**: `None` | `Redis` | `Memory Cache`
120
- 8. **CI/CD**: `GitHub Actions` | `Jenkins` | `GitLab CI`
121
- 9. **Security**: (Optional) Snyk & SonarCloud Hardening
123
+ 8. **Auth**: `None` | `JWT`
124
+ 9. **CI/CD**: `GitHub Actions` | `Jenkins` | `GitLab CI` | `CircleCI` | `Bitbucket Pipelines`
125
+ 10. **Security**: (Optional) Snyk & SonarCloud Hardening
122
126
 
123
127
  ---
124
128
 
@@ -146,7 +150,7 @@ Depending on your choices, the structure adapts. Here is a **TypeScript + Clean
146
150
 
147
151
  ## 📖 Documentation
148
152
 
149
- For full guides, architecture deep-dives, and feature references, visit our **[Official Documentation Site](https://paudang.github.io/nodejs-quickstart-structure/)**.
153
+ For full guides, architecture deep-dives, and feature references, visit our **[Official Documentation Site](https://paudang.github.io/nodejs-quickstart-structure/guide/getting-started.html)**.
150
154
 
151
155
  ---
152
156
 
package/bin/index.js CHANGED
@@ -15,7 +15,7 @@ const program = new Command();
15
15
 
16
16
  program
17
17
  .name('nodejs-quickstart')
18
- .description('🚀 CLI to scaffold production-ready Node.js microservices.\n\nGenerates projects with:\n- MVC or Clean Architecture\n- REST or Kafka\n- MySQL, PostgreSQL, or MongoDB\n- Docker, Flyway & Mongoose support')
18
+ .description('🚀 CLI to scaffold production-ready Node.js microservices.\n\nGenerates projects with:\n- MVC or Clean Architecture\n- REST, GraphQL or Kafka\n- MySQL, PostgreSQL, or MongoDB\n- Auth (None, JWT)\n- Docker, Flyway & Mongoose support')
19
19
  .version(pkg.version, '-v, --version', 'Output the current version')
20
20
  .addHelpText('after', `\n${chalk.yellow('Example:')}\n $ nodejs-quickstart init ${chalk.gray('# Start the interactive setup')}\n`);
21
21
 
@@ -29,10 +29,13 @@ program
29
29
  .option('-d, --database <database>', 'Database (MySQL, PostgreSQL)')
30
30
  .option('--db-name <name>', 'Database name')
31
31
  .option('-c, --communication <communication>', 'Communication (REST APIs, GraphQL, Kafka)')
32
- .option('--ci-provider <provider>', 'CI/CD Provider (None, GitHub Actions, Jenkins, GitLab CI)')
32
+ .option('--ci-provider <provider>', 'CI/CD Provider (None, GitHub Actions, Jenkins, GitLab CI, Bitbucket Pipelines, CircleCI)')
33
33
  .option('--include-security', 'Include Enterprise Security Hardening')
34
34
  .option('--no-include-security', 'Exclude Enterprise Security Hardening')
35
- .option('--caching <type>', 'Caching Layer (None/Redis)')
35
+ .option('--caching <type>', 'Caching Layer (None/Redis/Memory Cache)')
36
+ .option('--auth <modes...>', 'Authentication Modes (None, JWT)')
37
+ .option('--advanced-options', 'Enable Advanced Options')
38
+ .option('--no-advanced-options', 'Disable Advanced Options')
36
39
  .action(async (options) => {
37
40
  // Fix for Commander camelCase conversion
38
41
  if (options.ciProvider) {
package/lib/generator.js CHANGED
@@ -10,6 +10,8 @@ import { setupCaching } from './modules/caching-setup.js';
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
12
 
13
+ import { setupAuth } from './modules/auth-setup.js';
14
+
13
15
  export const generateProject = async (config) => {
14
16
  // 0. Normalize configuration with defaults
15
17
  config = {
@@ -20,9 +22,11 @@ export const generateProject = async (config) => {
20
22
  communication: 'REST APIs',
21
23
  database: 'None',
22
24
  includeSecurity: false,
25
+ auth: ['None'],
23
26
  ...config
24
27
  };
25
28
 
29
+
26
30
  const { projectName, architecture, language } = config;
27
31
  const targetDir = path.resolve(process.cwd(), projectName);
28
32
  const templatesDir = path.join(__dirname, '../templates');
@@ -62,14 +66,15 @@ export const generateProject = async (config) => {
62
66
  await renderDockerfile(templatesDir, targetDir, config);
63
67
 
64
68
  // 10. Database Setup (Migrations, Config, Models)
65
- // Note: logic for detailed view copying is also handled nicely if we ensure setupDatabase checks correctly,
66
- // or we can move strict view logic to setupViews.
67
- // In strict refactor, database-setup handles the content that was in the DB block.
68
69
  await setupDatabase(templatesDir, targetDir, config);
69
70
 
71
+ // 10.1 Auth Setup
72
+ await setupAuth(templatesDir, targetDir, config);
73
+
70
74
  // 10a. Caching Setup
71
75
  await setupCaching(templatesDir, targetDir, config);
72
76
 
77
+
73
78
  // 11. View Engine Public Assets (MVC)
74
79
  await setupViews(templatesDir, targetDir, config);
75
80
  // Copy src/views (MVC)
@@ -106,7 +111,8 @@ export const generateProject = async (config) => {
106
111
  Architecture: ${architecture}
107
112
  Language: ${language}
108
113
  Database: ${config.database}
109
- Communication: ${config.communication}${config.caching && config.caching === 'Redis' ? `\n Caching: ${config.caching}` : ''}
114
+ Communication: ${config.communication}${config.caching && config.caching !== 'None' ? `\n Caching: ${config.caching}` : ''}
115
+ Authentication: ${config.auth.join(', ')}
110
116
 
111
117
  ----------------------------------------------------
112
118
  ✨ High-Quality Standards Applied:
@@ -104,9 +104,21 @@ export const renderDynamicComponents = async (templatePath, targetDir, config) =
104
104
  await fs.ensureDir(path.join(targetDir, 'tests/unit/controllers'));
105
105
  const content = ejs.render(await fs.readFile(userControllerSpecTemplate, 'utf-8'), { ...config });
106
106
  await fs.writeFile(userControllerSpecPath, content);
107
- await fs.remove(path.join(targetDir, 'src/controllers', `${userControllerSpecName}.ejs`));
107
+ await fs.remove(path.join(targetDir, 'tests/unit/controllers', `${userControllerSpecName}.ejs`));
108
+ }
109
+
110
+ // MVC Routes
111
+ const routeName = language === 'TypeScript' ? 'api.ts' : 'api.js';
112
+ const routePath = path.join(targetDir, 'src/routes', routeName);
113
+ const routeTemplate = path.join(templatePath, 'src/routes', `${routeName}.ejs`);
114
+
115
+ if (await fs.pathExists(routeTemplate)) {
116
+ const content = ejs.render(await fs.readFile(routeTemplate, 'utf-8'), { ...config });
117
+ await fs.writeFile(routePath, content);
118
+ await fs.remove(path.join(targetDir, 'src/routes', `${routeName}.ejs`));
108
119
  }
109
120
  }
121
+
110
122
  // Clean Architecture Repo
111
123
  else if (architecture === 'Clean Architecture') {
112
124
  const repoName = language === 'TypeScript' ? 'UserRepository.ts' : 'UserRepository.js';
@@ -151,7 +163,36 @@ export const renderDynamicComponents = async (templatePath, targetDir, config) =
151
163
  await fs.writeFile(controllerSpecPath, content);
152
164
  await fs.remove(path.join(targetDir, 'src/interfaces/controllers', `${controllerSpecName}.ejs`));
153
165
  }
166
+
167
+ // CA Routes
168
+ const routeName = language === 'TypeScript' ? 'userRoutes.ts' : 'api.js';
169
+ const routePath = path.join(targetDir, 'src/interfaces/routes', routeName);
170
+ const routeTemplate = path.join(templatePath, 'src/interfaces/routes', `${routeName}.ejs`);
171
+
172
+ if (await fs.pathExists(routeTemplate)) {
173
+ const content = ejs.render(await fs.readFile(routeTemplate, 'utf-8'), { ...config });
174
+ await fs.writeFile(routePath, content);
175
+ await fs.remove(path.join(targetDir, 'src/interfaces/routes', `${routeName}.ejs`));
176
+ }
177
+
178
+ // --- Render All Use Cases ---
179
+ const useCaseDir = path.join(targetDir, 'src/usecases');
180
+ if (await fs.pathExists(useCaseDir)) {
181
+ const useCaseFiles = await fs.readdir(useCaseDir);
182
+ for (const file of useCaseFiles) {
183
+ if (file.endsWith('.ejs')) {
184
+ const templatePathObj = path.join(useCaseDir, file);
185
+ const destPathObj = path.join(useCaseDir, file.replace('.ejs', ''));
186
+
187
+ const template = await fs.readFile(templatePathObj, 'utf-8');
188
+ const content = ejs.render(template, { ...config });
189
+ await fs.writeFile(destPathObj, content);
190
+ await fs.remove(templatePathObj);
191
+ }
192
+ }
193
+ }
154
194
  }
195
+
155
196
  // Render Server (Clean Arch JS only)
156
197
  if (architecture === 'Clean Architecture' && language === 'JavaScript') {
157
198
  const serverName = 'server.js';
@@ -270,7 +311,7 @@ export const renderDynamicComponents = async (templatePath, targetDir, config) =
270
311
  if (stat.isDirectory()) {
271
312
  await renderEjsDir(srcPath, destPath);
272
313
  } else if (item.endsWith('.ejs')) {
273
- const content = ejs.render(await fs.readFile(srcPath, 'utf-8'), { language, architecture, database, caching });
314
+ const content = ejs.render(await fs.readFile(srcPath, 'utf-8'), { ...config });
274
315
  // Remove .ejs extension
275
316
  const finalDestPath = destPath.slice(0, -4);
276
317
  await fs.writeFile(finalDestPath, content);
@@ -310,10 +351,11 @@ export const renderSwaggerConfig = async (templatesDir, targetDir, config) => {
310
351
  if (communication === 'REST APIs' || communication === 'Kafka') {
311
352
  const swaggerYmlTemplateSource = path.join(templatesDir, 'common', 'swagger.yml.ejs');
312
353
  if (await fs.pathExists(swaggerYmlTemplateSource)) {
313
- const ymlContent = ejs.render(await fs.readFile(swaggerYmlTemplateSource, 'utf-8'), { projectName });
354
+ const ymlContent = ejs.render(await fs.readFile(swaggerYmlTemplateSource, 'utf-8'), { ...config });
314
355
  await fs.writeFile(path.join(configDir, 'swagger.yml'), ymlContent);
315
356
  }
316
357
 
358
+
317
359
  if (await fs.pathExists(swaggerTsTemplate)) {
318
360
  const content = ejs.render(await fs.readFile(swaggerTsTemplate, 'utf-8'), { communication });
319
361
  await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.ts'), content);
@@ -347,9 +389,35 @@ export const renderSwaggerConfig = async (templatesDir, targetDir, config) => {
347
389
  export const setupViews = async (templatesDir, targetDir, config) => {
348
390
  const { architecture, viewEngine } = config;
349
391
  if (architecture === 'MVC' && viewEngine && viewEngine !== 'None') {
350
- const viewsSource = path.join(templatesDir, 'common', 'views', viewEngine.toLowerCase());
392
+ const engine = viewEngine.toLowerCase();
393
+ const viewsSource = path.join(templatesDir, 'common', 'views', engine);
394
+ const destDir = path.join(targetDir, 'src/views');
395
+
351
396
  if (await fs.pathExists(viewsSource)) {
352
- await fs.copy(viewsSource, path.join(targetDir, 'src/views'));
397
+ await fs.ensureDir(destDir);
398
+ const items = await fs.readdir(viewsSource);
399
+ for (const item of items) {
400
+ // Skip auth views here; they are handled by auth-setup.js
401
+ if (item.startsWith('login.') || item.startsWith('signup.')) continue;
402
+
403
+ const srcPath = path.join(viewsSource, item);
404
+ const isTemplate = item.endsWith('.ejs');
405
+
406
+ // Determine target name: remove .ejs only if it's a double extension (e.g., .ejs.ejs or .pug.ejs)
407
+ // Otherwise keep the original name (e.g., index.ejs should remain index.ejs)
408
+ let targetName = item;
409
+ if (item.endsWith('.ejs.ejs') || item.endsWith('.pug.ejs')) {
410
+ targetName = item.slice(0, -4);
411
+ }
412
+ const destPath = path.join(destDir, targetName);
413
+
414
+ if (isTemplate) {
415
+ const content = ejs.render(await fs.readFile(srcPath, 'utf-8'), config);
416
+ await fs.writeFile(destPath, content);
417
+ } else {
418
+ await fs.copy(srcPath, destPath);
419
+ }
420
+ }
353
421
  }
354
422
  }
355
423
  };
@@ -392,7 +460,9 @@ export const processAllTests = async (targetDir, config) => {
392
460
  const template = await fs.readFile(itemPath, 'utf-8');
393
461
  const content = ejs.render(template, config);
394
462
 
395
- await fs.writeFile(targetTestPath, content);
463
+ if (content.trim()) {
464
+ await fs.writeFile(targetTestPath, content);
465
+ }
396
466
  await fs.remove(itemPath);
397
467
  }
398
468
  }
@@ -0,0 +1,143 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import ejs from 'ejs';
4
+
5
+ export const setupAuth = async (templatesDir, targetDir, config) => {
6
+ const { auth, architecture, language, communication, viewEngine } = config;
7
+ if (!auth || auth.includes('None') || !auth.includes('JWT')) return;
8
+
9
+ const langExt = language === 'TypeScript' ? 'ts' : 'js';
10
+ const authSource = path.join(templatesDir, 'common', 'auth', langExt);
11
+ const viewsSource = path.join(templatesDir, 'common', 'views');
12
+
13
+ // 1. JWT Service
14
+ await renderAuthComponent(authSource, targetDir, 'services', `jwtService.${langExt}`, config);
15
+
16
+ // 2. Auth Middleware
17
+ await renderAuthComponent(authSource, targetDir, 'middleware', `authMiddleware.${langExt}`, config);
18
+
19
+ // 3. Auth Controller (Login only)
20
+ await renderAuthComponent(authSource, targetDir, 'controllers', `authController.${langExt}`, config);
21
+
22
+ // 4. Auth Routes
23
+ await renderAuthComponent(authSource, targetDir, 'routes', `authRoutes.${langExt}`, config);
24
+
25
+ // 5. MVC Views (if applicable)
26
+ if (architecture === 'MVC' && viewEngine && viewEngine !== 'None') {
27
+ const engine = viewEngine.toLowerCase();
28
+ const views = ['login', 'signup'];
29
+ for (const view of views) {
30
+ const viewTemplate = path.join(viewsSource, engine, `${view}.${engine}.ejs`);
31
+ if (await fs.pathExists(viewTemplate)) {
32
+ const content = ejs.render(await fs.readFile(viewTemplate, 'utf-8'), config);
33
+ const destPath = path.join(targetDir, 'src', 'views', `${view}.${engine}`);
34
+ await fs.ensureDir(path.dirname(destPath));
35
+ await fs.writeFile(destPath, content);
36
+ }
37
+ }
38
+ }
39
+
40
+ // 6. Restructuring for Clean Architecture
41
+ if (architecture === 'Clean Architecture') {
42
+ await restructureAuthForCleanArch(targetDir, langExt);
43
+ }
44
+ };
45
+
46
+ async function renderAuthComponent(authSource, targetDir, subDir, fileName, config) {
47
+ const templatePath = path.join(authSource, subDir, `${fileName}.ejs`);
48
+ if (await fs.pathExists(templatePath)) {
49
+ const content = ejs.render(await fs.readFile(templatePath, 'utf-8'), config);
50
+ const destPath = path.join(targetDir, 'src', subDir, fileName);
51
+ await fs.ensureDir(path.dirname(destPath));
52
+ await fs.writeFile(destPath, content);
53
+
54
+ // Render Spec
55
+ const specName = fileName.replace(`.${config.language === 'TypeScript' ? 'ts' : 'js'}`, `.spec.${config.language === 'TypeScript' ? 'ts' : 'js'}`);
56
+ const specTemplate = path.join(authSource, subDir, `${specName}.ejs`);
57
+ if (await fs.pathExists(specTemplate)) {
58
+ const specContent = ejs.render(await fs.readFile(specTemplate, 'utf-8'), config);
59
+ const testDir = path.join(targetDir, 'tests', 'unit', subDir);
60
+ await fs.ensureDir(testDir);
61
+ await fs.writeFile(path.join(testDir, specName), specContent);
62
+ }
63
+ }
64
+ }
65
+
66
+ async function restructureAuthForCleanArch(targetDir, ext) {
67
+ // Services -> Infrastructure/Auth
68
+ await fs.ensureDir(path.join(targetDir, 'src/infrastructure/auth'));
69
+ await fs.ensureDir(path.join(targetDir, 'tests/unit/infrastructure/auth'));
70
+ if (await fs.pathExists(path.join(targetDir, `src/services/jwtService.${ext}`))) {
71
+ await fs.move(
72
+ path.join(targetDir, `src/services/jwtService.${ext}`),
73
+ path.join(targetDir, `src/infrastructure/auth/jwtService.${ext}`),
74
+ { overwrite: true }
75
+ );
76
+ if (await fs.pathExists(path.join(targetDir, `tests/unit/services/jwtService.spec.${ext}`))) {
77
+ await fs.move(
78
+ path.join(targetDir, `tests/unit/services/jwtService.spec.${ext}`),
79
+ path.join(targetDir, `tests/unit/infrastructure/auth/jwtService.spec.${ext}`),
80
+ { overwrite: true }
81
+ );
82
+ }
83
+ }
84
+
85
+ // Controllers -> Interfaces/Controllers/auth
86
+ await fs.ensureDir(path.join(targetDir, 'src/interfaces/controllers/auth'));
87
+ await fs.ensureDir(path.join(targetDir, 'tests/unit/interfaces/controllers/auth'));
88
+ if (await fs.pathExists(path.join(targetDir, `src/controllers/authController.${ext}`))) {
89
+ await fs.move(
90
+ path.join(targetDir, `src/controllers/authController.${ext}`),
91
+ path.join(targetDir, `src/interfaces/controllers/auth/authController.${ext}`),
92
+ { overwrite: true }
93
+ );
94
+ if (await fs.pathExists(path.join(targetDir, `tests/unit/controllers/authController.spec.${ext}`))) {
95
+ await fs.move(
96
+ path.join(targetDir, `tests/unit/controllers/authController.spec.${ext}`),
97
+ path.join(targetDir, `tests/unit/interfaces/controllers/auth/authController.spec.${ext}`),
98
+ { overwrite: true }
99
+ );
100
+ }
101
+ }
102
+
103
+ // Middleware -> Infrastructure/Webserver/Middleware
104
+ await fs.ensureDir(path.join(targetDir, 'src/infrastructure/webserver/middleware'));
105
+ await fs.ensureDir(path.join(targetDir, 'tests/unit/infrastructure/webserver/middleware'));
106
+ if (await fs.pathExists(path.join(targetDir, `src/middleware/authMiddleware.${ext}`))) {
107
+ await fs.move(
108
+ path.join(targetDir, `src/middleware/authMiddleware.${ext}`),
109
+ path.join(targetDir, `src/infrastructure/webserver/middleware/authMiddleware.${ext}`),
110
+ { overwrite: true }
111
+ );
112
+ if (await fs.pathExists(path.join(targetDir, `tests/unit/middleware/authMiddleware.spec.${ext}`))) {
113
+ await fs.move(
114
+ path.join(targetDir, `tests/unit/middleware/authMiddleware.spec.${ext}`),
115
+ path.join(targetDir, `tests/unit/infrastructure/webserver/middleware/authMiddleware.spec.${ext}`),
116
+ { overwrite: true }
117
+ );
118
+ }
119
+ }
120
+
121
+ // Routes -> Interfaces/Routes (No unit tests for routes normally, but move if exists)
122
+ await fs.ensureDir(path.join(targetDir, 'src/interfaces/routes'));
123
+ if (await fs.pathExists(path.join(targetDir, `src/routes/authRoutes.${ext}`))) {
124
+ await fs.move(
125
+ path.join(targetDir, `src/routes/authRoutes.${ext}`),
126
+ path.join(targetDir, `src/interfaces/routes/authRoutes.${ext}`),
127
+ { overwrite: true }
128
+ );
129
+ }
130
+
131
+ // Cleanup empty dirs in src and tests/unit
132
+ const dirsToCleanup = [
133
+ 'src/services', 'src/controllers', 'src/middleware', 'src/routes',
134
+ 'tests/unit/services', 'tests/unit/controllers', 'tests/unit/middleware'
135
+ ];
136
+ for (const dir of dirsToCleanup) {
137
+ const fullDir = path.join(targetDir, dir);
138
+ if (await fs.pathExists(fullDir) && (await fs.readdir(fullDir)).length === 0) {
139
+ await fs.remove(fullDir);
140
+ }
141
+ }
142
+ }
143
+
@@ -30,12 +30,14 @@ export const setupCaching = async (templatesDir, targetDir, config) => {
30
30
  const useCases = language === 'TypeScript'
31
31
  ? [
32
32
  { name: 'getAllUsers.ts', src: 'getAllUsers.ts.ejs' },
33
+ { name: 'getUserById.ts', src: 'getUserById.ts.ejs' },
33
34
  { name: 'createUser.ts', src: 'createUser.ts.ejs' },
34
35
  { name: 'updateUser.ts', src: 'updateUser.ts.ejs' },
35
36
  { name: 'deleteUser.ts', src: 'deleteUser.ts.ejs' }
36
37
  ]
37
38
  : [
38
39
  { name: 'GetAllUsers.js', src: 'GetAllUsers.js.ejs' },
40
+ { name: 'GetUserById.js', src: 'GetUserById.js.ejs' },
39
41
  { name: 'CreateUser.js', src: 'CreateUser.js.ejs' },
40
42
  { name: 'UpdateUser.js', src: 'UpdateUser.js.ejs' },
41
43
  { name: 'DeleteUser.js', src: 'DeleteUser.js.ejs' }
@@ -48,8 +50,13 @@ export const setupCaching = async (templatesDir, targetDir, config) => {
48
50
  const useCaseSource = path.join(templatesDir, 'common', 'caching', 'clean', langExt, uc.src);
49
51
  if (await fs.pathExists(useCaseSource)) {
50
52
  const ucContent = await fs.readFile(useCaseSource, 'utf-8');
51
- const renderedUc = ejs.render(ucContent, { caching });
53
+ const renderedUc = ejs.render(ucContent, { ...config });
52
54
  await fs.writeFile(path.join(useCaseTargetDir, uc.name), renderedUc);
55
+ // Cleanup the template in target dir
56
+ const templateInTarget = path.join(useCaseTargetDir, uc.src);
57
+ if (await fs.pathExists(templateInTarget)) {
58
+ await fs.remove(templateInTarget);
59
+ }
53
60
  }
54
61
  }
55
62
  }
@@ -120,6 +120,16 @@ export const setupCiCd = async (templatesDir, targetDir, config) => {
120
120
  const gitlabTemplate = await fs.readFile(path.join(templatesDir, 'common', '.gitlab-ci.yml.ejs'), 'utf-8');
121
121
  const gitlabContent = ejs.render(gitlabTemplate, { ...config });
122
122
  await fs.writeFile(path.join(targetDir, '.gitlab-ci.yml'), gitlabContent);
123
+ } else if (ciProvider === 'Bitbucket Pipelines') {
124
+ const bitbucketTemplate = await fs.readFile(path.join(templatesDir, 'common', 'bitbucket-pipelines.yml.ejs'), 'utf-8');
125
+ const bitbucketContent = ejs.render(bitbucketTemplate, { ...config });
126
+ await fs.writeFile(path.join(targetDir, 'bitbucket-pipelines.yml'), bitbucketContent);
127
+ } else if (ciProvider === 'CircleCI') {
128
+ const circleCiDir = path.join(targetDir, '.circleci');
129
+ await fs.ensureDir(circleCiDir);
130
+ const circleCiTemplate = await fs.readFile(path.join(templatesDir, 'common', '_circleci/config.yml.ejs'), 'utf-8');
131
+ const circleCiContent = ejs.render(circleCiTemplate, { ...config });
132
+ await fs.writeFile(path.join(circleCiDir, 'config.yml'), circleCiContent);
123
133
  }
124
134
  };
125
135
 
@@ -19,7 +19,8 @@ export const setupDatabase = async (templatesDir, targetDir, config) => {
19
19
  // Create initial migration file with timestamp
20
20
  const timestamp = new Date().toISOString().replace(/[-T:.Z]/g, '').slice(0, 14); // YYYYMMDDHHMMSS
21
21
  const migrationTemplate = await fs.readFile(path.join(templatesDir, 'common', 'migrations', 'init.js.ejs'), 'utf-8');
22
- await fs.writeFile(path.join(targetDir, 'migrations', `${timestamp}-initial-setup.js`), migrationTemplate);
22
+ const migrationContent = ejs.render(migrationTemplate, { ...config });
23
+ await fs.writeFile(path.join(targetDir, 'migrations', `${timestamp}-initial-setup.js`), migrationContent);
23
24
 
24
25
  } else if (database !== 'None') {
25
26
  // Flyway for SQL
@@ -28,5 +28,6 @@ export const copyCommonFiles = async (templatesDir, targetDir, language) => {
28
28
 
29
29
  if (language === 'TypeScript') {
30
30
  await fs.copy(path.join(templatesDir, 'common', 'tsconfig.json'), path.join(targetDir, 'tsconfig.json'));
31
+ await fs.copy(path.join(templatesDir, 'common', 'tsconfig.eslint.json'), path.join(targetDir, 'tsconfig.eslint.json'));
31
32
  }
32
33
  };