nodejs-quickstart-structure 1.6.1 → 1.7.5

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 (29) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +9 -7
  3. package/bin/index.js +1 -0
  4. package/docs/generateCase.md +126 -76
  5. package/docs/generatorFlow.md +10 -2
  6. package/lib/generator.js +9 -2
  7. package/lib/modules/app-setup.js +7 -2
  8. package/lib/modules/caching-setup.js +56 -0
  9. package/lib/modules/config-files.js +26 -5
  10. package/lib/modules/database-setup.js +13 -1
  11. package/lib/prompts.js +9 -1
  12. package/package.json +1 -1
  13. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +1 -2
  14. package/templates/common/.env.example.ejs +39 -0
  15. package/templates/common/Jenkinsfile.ejs +41 -0
  16. package/templates/common/README.md.ejs +113 -106
  17. package/templates/common/caching/clean/js/CreateUser.js.ejs +25 -0
  18. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +33 -0
  19. package/templates/common/caching/clean/ts/createUser.ts.ejs +23 -0
  20. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +30 -0
  21. package/templates/common/caching/js/redisClient.js.ejs +71 -0
  22. package/templates/common/caching/ts/redisClient.ts.ejs +76 -0
  23. package/templates/common/docker-compose.yml.ejs +156 -139
  24. package/templates/common/package.json.ejs +4 -0
  25. package/templates/mvc/js/src/controllers/userController.js.ejs +22 -0
  26. package/templates/mvc/ts/src/config/swagger.ts.ejs +1 -2
  27. package/templates/mvc/ts/src/controllers/userController.ts.ejs +22 -0
  28. /package/templates/db/mysql/{V1__Initial_Setup.sql → V1__Initial_Setup.sql.ejs} +0 -0
  29. /package/templates/db/postgres/{V1__Initial_Setup.sql → V1__Initial_Setup.sql.ejs} +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.7.5] - 2026-02-17
9
+ > Happy Lunar New Year! This release coincides with Tet Vietnam. 🎆
10
+ ### Fixed
11
+ - Optimized `scripts/validate-windows.js` to use `--no-audit --no-fund --loglevel=error` during `npm install`, resolving intermittent CI failures on Windows.
12
+ - Fixed 7 failing test cases involving Kafka and Redis combinations.
13
+
14
+ ## [1.7.4] - 2026-02-17
15
+ ### Fixed
16
+ - Resolved `JSON.parse` error and incorrect Redis arguments in `getAllUsers` usecase for Clean Architecture templates.
17
+ - Fixed `SyntaxError` in `lib/modules/caching-setup.js` preventing project generation.
18
+
19
+ ### Added
20
+ - Implemented automatic cache invalidation in `createUser` usecase (Clean Architecture) to ensure data consistency.
21
+
22
+ ## [1.7.0]
23
+
24
+ ### Added
25
+ - Added support for Redis caching in both MVC and Clean Architecture.
26
+
8
27
  ## [1.6.1] - 2026-02-11
9
28
 
10
29
  ### Fixed
package/README.md CHANGED
@@ -13,7 +13,8 @@ A powerful CLI tool to scaffold production-ready Node.js microservices with buil
13
13
  - **Language Support**: Choose between **JavaScript** and **TypeScript**.
14
14
  - **Database Integration**: Pre-configured setup for **MySQL**, **PostgreSQL**, or **MongoDB**.
15
15
  - **Microservices Ready**: Optional **Kafka** integration for event-driven communication.
16
- - **Dockerized**: Automatically generates `docker-compose.yml` for DB, Kafka, and Zookeeper.
16
+ - **Caching Layer**: Optional **Redis** integration for high-performance data caching.
17
+ - **Dockerized**: Automatically generates `docker-compose.yml` for DB, Kafka, Redis, and Zookeeper.
17
18
  - **Database Migrations/Schemas**: Integrated **Flyway** for SQL migrations or **Mongoose** schemas for MongoDB.
18
19
  - **Professional Standards**: Generated projects come with highly professional, industry-standard tooling.
19
20
 
@@ -28,14 +29,14 @@ We don't just generate boilerplate; we generate **production-ready** foundations
28
29
  - **⚓ Git Hooks**: `Husky` and `Lint-Staged` to ensure no bad code is ever committed.
29
30
  - **🐳 DevOps**: Highly optimized **Multi-Stage Dockerfile** for small, secure production images.
30
31
 
31
- ## 🧩 64+ Project Combinations
32
+ ## 🧩 112+ Project Combinations
32
33
 
33
34
  The CLI supports a massive number of configurations to fit your exact needs:
34
35
 
35
- - **64 Core Combinations**:
36
- - **MVC Architecture**: 48 variants (Languages × View Engines × Databases × Communication Patterns)
37
- - **Clean Architecture**: 16 variants (Languages × Databases × Communication Patterns)
38
- - **128 Total Scenarios**:
36
+ - **112 Core Combinations**:
37
+ - **MVC Architecture**: 84 variants (Languages × View Engines × Databases × Communication Patterns × Caching)
38
+ - **Clean Architecture**: 28 variants (Languages × Databases × Communication Patterns × Caching)
39
+ - **224 Total Scenarios**:
39
40
  - Every combination can be generated with or without **GitHub Actions CI/CD**, doubling the possibilities.
40
41
 
41
42
  For a detailed list of all supported cases, check out [docs/generateCase.md](docs/generateCase.md).
@@ -66,7 +67,8 @@ The CLI will guide you through the following steps:
66
67
  4. **Database**: `MySQL`, `PostgreSQL`, or `MongoDB`.
67
68
  5. **Database Name**: The name of the initial database.
68
69
  6. **Communication**: `REST APIs` (default) or `Kafka`.
69
- 7. **CI/CD**: `GitHub Actions`, `Jenkins`, or `None`.
70
+ 7. **Caching**: `Redis` or `None`.
71
+ 8. **CI/CD**: `GitHub Actions`, `Jenkins`, or `None`.
70
72
 
71
73
  ## Generated Project Structure
72
74
 
package/bin/index.js CHANGED
@@ -33,6 +33,7 @@ program
33
33
  .option('--db-name <name>', 'Database name')
34
34
  .option('-c, --communication <communication>', 'Communication (REST APIs, Kafka)')
35
35
  .option('--ci-provider <provider>', 'CI/CD Provider (None, GitHub Actions, Jenkins)')
36
+ .option('--caching <type>', 'Caching Layer (None/Redis)')
36
37
  .action(async (options) => {
37
38
  // Fix for Commander camelCase conversion
38
39
  if (options.ciProvider) {
@@ -1,90 +1,140 @@
1
1
  # NodeJS Quickstart Generator - Test Cases
2
2
 
3
- This document lists the **48 possible project combinations** supported by the `nodejs-quickstart` CLI. These combinations cover all supported languages, architectures, databases (including MongoDB), and communication patterns.
3
+ This document lists the **112 possible project combinations** supported by the `nodejs-quickstart` CLI. These combinations cover all supported languages, architectures, databases, communication patterns, and caching options.
4
4
 
5
5
  ## Summary
6
- - **MVC Architecture**: 48 Combinations
7
- - (2 Languages × 3 View Engines × 4 Databases (incl. None) × 2 Patterns)
8
- - **Clean Architecture**: 16 Combinations
9
- - (2 Languages × 1 View Engine (None) × 4 Databases (incl. None) × 2 Patterns)
6
+ - **MVC Architecture**: 84 Combinations
7
+ - **With Database (36)**: 2 Lang × 3 View × 3 DB × 2 Comm = 36 * 2 (Caching: None/Redis) = 72
8
+ - **No Database (12)**: 2 Lang × 3 View × 1 DB × 2 Comm = 12 * 1 (Caching: None) = 12
9
+ - **Clean Architecture**: 28 Combinations
10
+ - **With Database (12)**: 2 Lang × 1 View (None) × 3 DB × 2 Comm = 12 * 2 (Caching: None/Redis) = 24
11
+ - **No Database (4)**: 2 Lang × 1 View (None) × 1 DB × 2 Comm = 4 * 1 (Caching: None) = 4
10
12
 
11
- **Total Core Combinations: 64**
13
+ **Total Core Combinations: 112**
12
14
 
13
- > **Note on CI/CD**: Each of these 48 combinations can be generated with or without the **GitHub Actions CI Workflow** (`--include-ci`). This effectively creates **96 possible project states**. The validation script currently defaults to *including* CI to verify the full "Professional Standards" feature set.
15
+ > **Note on CI/CD**: Each combination can be generated with or without CI/CD (`--ci-provider`), effectively doubling the state space.
14
16
 
15
17
  ---
16
18
 
17
- ## 1. MVC Architecture (36 Cases)
19
+ ## 1. MVC Architecture (84 Cases)
18
20
 
19
- | # | Language | Architecture | View Engine | Database | Communication |
20
- | :--- | :--- | :--- | :--- | :--- | :--- |
21
- | 1 | JavaScript | MVC | None | MySQL | REST APIs |
22
- | 2 | JavaScript | MVC | None | MySQL | Kafka |
23
- | 3 | JavaScript | MVC | None | PostgreSQL | REST APIs |
24
- | 4 | JavaScript | MVC | None | PostgreSQL | Kafka |
25
- | 5 | JavaScript | MVC | None | MongoDB | REST APIs |
26
- | 6 | JavaScript | MVC | None | MongoDB | Kafka |
27
- | 7 | JavaScript | MVC | EJS | MySQL | REST APIs |
28
- | 8 | JavaScript | MVC | EJS | MySQL | Kafka |
29
- | 9 | JavaScript | MVC | EJS | PostgreSQL | REST APIs |
30
- | 10 | JavaScript | MVC | EJS | PostgreSQL | Kafka |
31
- | 11 | JavaScript | MVC | EJS | MongoDB | REST APIs |
32
- | 12 | JavaScript | MVC | EJS | MongoDB | Kafka |
33
- | 13 | JavaScript | MVC | Pug | MySQL | REST APIs |
34
- | 14 | JavaScript | MVC | Pug | MySQL | Kafka |
35
- | 15 | JavaScript | MVC | Pug | PostgreSQL | REST APIs |
36
- | 16 | JavaScript | MVC | Pug | PostgreSQL | Kafka |
37
- | 17 | JavaScript | MVC | Pug | MongoDB | REST APIs |
38
- | 18 | JavaScript | MVC | Pug | MongoDB | Kafka |
39
- | 19 | TypeScript | MVC | None | MySQL | REST APIs |
40
- | 20 | TypeScript | MVC | None | MySQL | Kafka |
41
- | 21 | TypeScript | MVC | None | PostgreSQL | REST APIs |
42
- | 22 | TypeScript | MVC | None | PostgreSQL | Kafka |
43
- | 23 | TypeScript | MVC | None | MongoDB | REST APIs |
44
- | 24 | TypeScript | MVC | None | MongoDB | Kafka |
45
- | 25 | TypeScript | MVC | EJS | MySQL | REST APIs |
46
- | 26 | TypeScript | MVC | EJS | MySQL | Kafka |
47
- | 27 | TypeScript | MVC | EJS | PostgreSQL | REST APIs |
48
- | 28 | TypeScript | MVC | EJS | PostgreSQL | Kafka |
49
- | 29 | TypeScript | MVC | EJS | MongoDB | REST APIs |
50
- | 30 | TypeScript | MVC | EJS | MongoDB | Kafka |
51
- | 31 | TypeScript | MVC | Pug | MySQL | REST APIs |
52
- | 32 | TypeScript | MVC | Pug | MySQL | Kafka |
53
- | 33 | TypeScript | MVC | Pug | PostgreSQL | REST APIs |
54
- | 34 | TypeScript | MVC | Pug | PostgreSQL | Kafka |
55
- | 35 | TypeScript | MVC | Pug | MongoDB | REST APIs |
56
- | 36 | TypeScript | MVC | Pug | MongoDB | Kafka |
57
- | 37 | JavaScript | MVC | None | None | REST APIs |
58
- | 38 | JavaScript | MVC | None | None | Kafka |
59
- | 39 | JavaScript | MVC | EJS | None | REST APIs |
60
- | 40 | JavaScript | MVC | EJS | None | Kafka |
61
- | 41 | JavaScript | MVC | Pug | None | REST APIs |
62
- | 42 | JavaScript | MVC | Pug | None | Kafka |
63
- | 43 | TypeScript | MVC | None | None | REST APIs |
64
- | 44 | TypeScript | MVC | None | None | Kafka |
65
- | 45 | TypeScript | MVC | EJS | None | REST APIs |
66
- | 46 | TypeScript | MVC | EJS | None | Kafka |
67
- | 47 | TypeScript | MVC | Pug | None | REST APIs |
68
- | 48 | TypeScript | MVC | Pug | None | Kafka |
21
+ | # | Language | Architecture | View Engine | Database | Communication | Caching |
22
+ | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
23
+ | 1 | JavaScript | MVC | None | MySQL | REST APIs | None |
24
+ | 2 | JavaScript | MVC | None | MySQL | REST APIs | Redis |
25
+ | 3 | JavaScript | MVC | None | MySQL | Kafka | None |
26
+ | 4 | JavaScript | MVC | None | MySQL | Kafka | Redis |
27
+ | 5 | JavaScript | MVC | None | PostgreSQL | REST APIs | None |
28
+ | 6 | JavaScript | MVC | None | PostgreSQL | REST APIs | Redis |
29
+ | 7 | JavaScript | MVC | None | PostgreSQL | Kafka | None |
30
+ | 8 | JavaScript | MVC | None | PostgreSQL | Kafka | Redis |
31
+ | 9 | JavaScript | MVC | None | MongoDB | REST APIs | None |
32
+ | 10 | JavaScript | MVC | None | MongoDB | REST APIs | Redis |
33
+ | 11 | JavaScript | MVC | None | MongoDB | Kafka | None |
34
+ | 12 | JavaScript | MVC | None | MongoDB | Kafka | Redis |
35
+ | 13 | JavaScript | MVC | EJS | MySQL | REST APIs | None |
36
+ | 14 | JavaScript | MVC | EJS | MySQL | REST APIs | Redis |
37
+ | 15 | JavaScript | MVC | EJS | MySQL | Kafka | None |
38
+ | 16 | JavaScript | MVC | EJS | MySQL | Kafka | Redis |
39
+ | 17 | JavaScript | MVC | EJS | PostgreSQL | REST APIs | None |
40
+ | 18 | JavaScript | MVC | EJS | PostgreSQL | REST APIs | Redis |
41
+ | 19 | JavaScript | MVC | EJS | PostgreSQL | Kafka | None |
42
+ | 20 | JavaScript | MVC | EJS | PostgreSQL | Kafka | Redis |
43
+ | 21 | JavaScript | MVC | EJS | MongoDB | REST APIs | None |
44
+ | 22 | JavaScript | MVC | EJS | MongoDB | REST APIs | Redis |
45
+ | 23 | JavaScript | MVC | EJS | MongoDB | Kafka | None |
46
+ | 24 | JavaScript | MVC | EJS | MongoDB | Kafka | Redis |
47
+ | 25 | JavaScript | MVC | Pug | MySQL | REST APIs | None |
48
+ | 26 | JavaScript | MVC | Pug | MySQL | REST APIs | Redis |
49
+ | 27 | JavaScript | MVC | Pug | MySQL | Kafka | None |
50
+ | 28 | JavaScript | MVC | Pug | MySQL | Kafka | Redis |
51
+ | 29 | JavaScript | MVC | Pug | PostgreSQL | REST APIs | None |
52
+ | 30 | JavaScript | MVC | Pug | PostgreSQL | REST APIs | Redis |
53
+ | 31 | JavaScript | MVC | Pug | PostgreSQL | Kafka | None |
54
+ | 32 | JavaScript | MVC | Pug | PostgreSQL | Kafka | Redis |
55
+ | 33 | JavaScript | MVC | Pug | MongoDB | REST APIs | None |
56
+ | 34 | JavaScript | MVC | Pug | MongoDB | REST APIs | Redis |
57
+ | 35 | JavaScript | MVC | Pug | MongoDB | Kafka | None |
58
+ | 36 | JavaScript | MVC | Pug | MongoDB | Kafka | Redis |
59
+ | 37 | TypeScript | MVC | None | MySQL | REST APIs | None |
60
+ | 38 | TypeScript | MVC | None | MySQL | REST APIs | Redis |
61
+ | 39 | TypeScript | MVC | None | MySQL | Kafka | None |
62
+ | 40 | TypeScript | MVC | None | MySQL | Kafka | Redis |
63
+ | 41 | TypeScript | MVC | None | PostgreSQL | REST APIs | None |
64
+ | 42 | TypeScript | MVC | None | PostgreSQL | REST APIs | Redis |
65
+ | 43 | TypeScript | MVC | None | PostgreSQL | Kafka | None |
66
+ | 44 | TypeScript | MVC | None | PostgreSQL | Kafka | Redis |
67
+ | 45 | TypeScript | MVC | None | MongoDB | REST APIs | None |
68
+ | 46 | TypeScript | MVC | None | MongoDB | REST APIs | Redis |
69
+ | 47 | TypeScript | MVC | None | MongoDB | Kafka | None |
70
+ | 48 | TypeScript | MVC | None | MongoDB | Kafka | Redis |
71
+ | 49 | TypeScript | MVC | EJS | MySQL | REST APIs | None |
72
+ | 50 | TypeScript | MVC | EJS | MySQL | REST APIs | Redis |
73
+ | 51 | TypeScript | MVC | EJS | MySQL | Kafka | None |
74
+ | 52 | TypeScript | MVC | EJS | MySQL | Kafka | Redis |
75
+ | 53 | TypeScript | MVC | EJS | PostgreSQL | REST APIs | None |
76
+ | 54 | TypeScript | MVC | EJS | PostgreSQL | REST APIs | Redis |
77
+ | 55 | TypeScript | MVC | EJS | PostgreSQL | Kafka | None |
78
+ | 56 | TypeScript | MVC | EJS | PostgreSQL | Kafka | Redis |
79
+ | 57 | TypeScript | MVC | EJS | MongoDB | REST APIs | None |
80
+ | 58 | TypeScript | MVC | EJS | MongoDB | REST APIs | Redis |
81
+ | 59 | TypeScript | MVC | EJS | MongoDB | Kafka | None |
82
+ | 60 | TypeScript | MVC | EJS | MongoDB | Kafka | Redis |
83
+ | 61 | TypeScript | MVC | Pug | MySQL | REST APIs | None |
84
+ | 62 | TypeScript | MVC | Pug | MySQL | REST APIs | Redis |
85
+ | 63 | TypeScript | MVC | Pug | MySQL | Kafka | None |
86
+ | 64 | TypeScript | MVC | Pug | MySQL | Kafka | Redis |
87
+ | 65 | TypeScript | MVC | Pug | PostgreSQL | REST APIs | None |
88
+ | 66 | TypeScript | MVC | Pug | PostgreSQL | REST APIs | Redis |
89
+ | 67 | TypeScript | MVC | Pug | PostgreSQL | Kafka | None |
90
+ | 68 | TypeScript | MVC | Pug | PostgreSQL | Kafka | Redis |
91
+ | 69 | TypeScript | MVC | Pug | MongoDB | REST APIs | None |
92
+ | 70 | TypeScript | MVC | Pug | MongoDB | REST APIs | Redis |
93
+ | 71 | TypeScript | MVC | Pug | MongoDB | Kafka | None |
94
+ | 72 | TypeScript | MVC | Pug | MongoDB | Kafka | Redis |
95
+ | 73 | JavaScript | MVC | None | None | REST APIs | None |
96
+ | 74 | JavaScript | MVC | None | None | Kafka | None |
97
+ | 75 | JavaScript | MVC | EJS | None | REST APIs | None |
98
+ | 76 | JavaScript | MVC | EJS | None | Kafka | None |
99
+ | 77 | JavaScript | MVC | Pug | None | REST APIs | None |
100
+ | 78 | JavaScript | MVC | Pug | None | Kafka | None |
101
+ | 79 | TypeScript | MVC | None | None | REST APIs | None |
102
+ | 80 | TypeScript | MVC | None | None | Kafka | None |
103
+ | 81 | TypeScript | MVC | EJS | None | REST APIs | None |
104
+ | 82 | TypeScript | MVC | EJS | None | Kafka | None |
105
+ | 83 | TypeScript | MVC | Pug | None | REST APIs | None |
106
+ | 84 | TypeScript | MVC | Pug | None | Kafka | None |
69
107
 
70
108
  ## 2. Clean Architecture (16 Cases)
71
109
  *Note: Clean Architecture does not use server-side view engines (EJS/Pug).*
72
110
 
73
- | # | Language | Architecture | View Engine | Database | Communication |
74
- | :--- | :--- | :--- | :--- | :--- | :--- |
75
- | 1 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs |
76
- | 38 | JavaScript | Clean Architecture | N/A | MySQL | Kafka |
77
- | 39 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs |
78
- | 40 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka |
79
- | 41 | JavaScript | Clean Architecture | N/A | MongoDB | REST APIs |
80
- | 42 | JavaScript | Clean Architecture | N/A | MongoDB | Kafka |
81
- | 43 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs |
82
- | 44 | TypeScript | Clean Architecture | N/A | MySQL | Kafka |
83
- | 45 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs |
84
- | 46 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka |
85
- | 47 | TypeScript | Clean Architecture | N/A | MongoDB | REST APIs |
86
- | 48 | TypeScript | Clean Architecture | N/A | MongoDB | Kafka |
87
- | 49 | JavaScript | Clean Architecture | N/A | None | REST APIs |
88
- | 50 | JavaScript | Clean Architecture | N/A | None | Kafka |
89
- | 51 | TypeScript | Clean Architecture | N/A | None | REST APIs |
90
- | 52 | TypeScript | Clean Architecture | N/A | None | Kafka |
111
+ | # | Language | Architecture | View Engine | Database | Communication | Caching |
112
+ | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
113
+ | 85 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs | None |
114
+ | 86 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs | Redis |
115
+ | 87 | JavaScript | Clean Architecture | N/A | MySQL | Kafka | None |
116
+ | 88 | JavaScript | Clean Architecture | N/A | MySQL | Kafka | Redis |
117
+ | 89 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs | None |
118
+ | 90 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs | Redis |
119
+ | 91 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka | None |
120
+ | 92 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka | Redis |
121
+ | 93 | JavaScript | Clean Architecture | N/A | MongoDB | REST APIs | None |
122
+ | 94 | JavaScript | Clean Architecture | N/A | MongoDB | REST APIs | Redis |
123
+ | 95 | JavaScript | Clean Architecture | N/A | MongoDB | Kafka | None |
124
+ | 96 | JavaScript | Clean Architecture | N/A | MongoDB | Kafka | Redis |
125
+ | 97 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs | None |
126
+ | 98 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs | Redis |
127
+ | 99 | TypeScript | Clean Architecture | N/A | MySQL | Kafka | None |
128
+ | 100 | TypeScript | Clean Architecture | N/A | MySQL | Kafka | Redis |
129
+ | 101 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs | None |
130
+ | 102 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs | Redis |
131
+ | 103 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka | None |
132
+ | 104 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka | Redis |
133
+ | 105 | TypeScript | Clean Architecture | N/A | MongoDB | REST APIs | None |
134
+ | 106 | TypeScript | Clean Architecture | N/A | MongoDB | REST APIs | Redis |
135
+ | 107 | TypeScript | Clean Architecture | N/A | MongoDB | Kafka | None |
136
+ | 108 | TypeScript | Clean Architecture | N/A | MongoDB | Kafka | Redis |
137
+ | 109 | JavaScript | Clean Architecture | N/A | None | REST APIs | None |
138
+ | 110 | JavaScript | Clean Architecture | N/A | None | Kafka | None |
139
+ | 111 | TypeScript | Clean Architecture | N/A | None | REST APIs | None |
140
+ | 112 | TypeScript | Clean Architecture | N/A | None | Kafka | None |
@@ -26,6 +26,7 @@ The generator prompts the user for the following configurations. These determine
26
26
  | **Database** | `None`, `MySQL`, `PostgreSQL`, `MongoDB` | `None` | The primary database. |
27
27
  | **Database Name** | Input String | `demo` | The name of the database to use/create. |
28
28
  | **Communication**| `REST APIs`, `Kafka` | `REST APIs` | The primary communication method. |
29
+ | **Caching Layer**| `None`, `Redis` | `None` | (If DB selected) Caching solution. |
29
30
  | **CI/CD Provider**| `None`, `GitHub Actions`, `Jenkins`| `None` | Setup for Continuous Integration/Deployment. |
30
31
 
31
32
  ## 3. Main Generator Flow
@@ -67,7 +68,13 @@ The `generateProject` function in `lib/generator.js` executes the following step
67
68
  * **MongoDB**: Sets up `migrate-mongo-config.js` and initial migration script.
68
69
  * **SQL (MySQL/Postgres)**: Sets up `flyway/sql` directory and copies initial SQL migration files.
69
70
  * **None**: Skips migration setup.
70
- 11. **Database Connection Config**:
71
+ 11. **Caching Setup**:
72
+ * **Redis**:
73
+ * Injects `ioredis` dependency into `package.json`.
74
+ * Generates `redisClient.{js|ts}` config.
75
+ * **MVC**: Injects caching logic into `userController`.
76
+ * **Clean Architecture**: Overwrites `GetAllUsers` use case with caching-enabled version.
77
+ 12. **Database Connection Config**:
71
78
  * Renders `database.{js|ts}` or `mongoose.{js|ts}` based on DB selection.
72
79
  * Places it in `src/config` (MVC) or `src/infrastructure/database` (Clean Arch).
73
80
  * **None**: Skips this step.
@@ -109,7 +116,7 @@ Standard architecture for web APIs.
109
116
  ```text
110
117
  project-name/
111
118
  ├── src/
112
- │ ├── config/ # Database, Swagger, etc.
119
+ │ ├── config/ # Database, Redis, Swagger, etc.
113
120
  │ ├── controllers/ # Request handlers
114
121
  │ ├── models/ # Database models
115
122
  │ ├── routes/ # Express routes
@@ -149,6 +156,7 @@ project-name/
149
156
  │ │ └── routes/
150
157
  │ ├── infrastructure/ # Frameworks & Drivers
151
158
  │ │ ├── config/ # Environment config
159
+ │ │ ├── caching/ # Redis Client
152
160
  │ │ ├── database/ # DB connection & models
153
161
  │ │ ├── repositories/ # Data access implementation
154
162
  │ │ └── webserver/ # Express server setup
package/lib/generator.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import path from 'path';
2
2
  import { fileURLToPath } from 'url';
3
3
  import { setupProjectDirectory, copyBaseStructure, copyCommonFiles } from './modules/project-setup.js';
4
- import { renderPackageJson, renderDockerCompose, renderReadme, renderDockerfile, renderProfessionalConfig, setupCiCd, renderTestSample } from './modules/config-files.js';
4
+ import { renderPackageJson, renderDockerCompose, renderReadme, renderDockerfile, renderProfessionalConfig, setupCiCd, renderTestSample, renderEnvExample } from './modules/config-files.js';
5
5
  import { renderIndexFile, renderDynamicComponents, renderSwaggerConfig, setupViews as setupSrcViews } from './modules/app-setup.js';
6
6
  import { setupDatabase } from './modules/database-setup.js';
7
7
  import { setupKafka, setupViews } from './modules/kafka-setup.js';
8
+ import { setupCaching } from './modules/caching-setup.js';
8
9
 
9
10
  const __filename = fileURLToPath(import.meta.url);
10
11
  const __dirname = path.dirname(__filename);
@@ -48,6 +49,9 @@ export const generateProject = async (config) => {
48
49
  // In strict refactor, database-setup handles the content that was in the DB block.
49
50
  await setupDatabase(templatesDir, targetDir, config);
50
51
 
52
+ // 10a. Caching Setup
53
+ await setupCaching(templatesDir, targetDir, config);
54
+
51
55
  // 11. View Engine Public Assets (MVC)
52
56
  await setupViews(templatesDir, targetDir, config);
53
57
  // Copy src/views (MVC)
@@ -63,6 +67,9 @@ export const generateProject = async (config) => {
63
67
  // 14. CI/CD
64
68
  await setupCiCd(templatesDir, targetDir, config);
65
69
 
70
+ // 15. Env Example
71
+ await renderEnvExample(templatesDir, targetDir, config);
72
+
66
73
  console.log(`
67
74
  ====================================================
68
75
  Node.js Project Created Successfully!
@@ -72,7 +79,7 @@ export const generateProject = async (config) => {
72
79
  Architecture: ${architecture}
73
80
  Language: ${language}
74
81
  Database: ${config.database}
75
- Communication: ${config.communication}
82
+ Communication: ${config.communication}${config.caching && config.caching === 'Redis' ? `\n Caching: ${config.caching}` : ''}
76
83
 
77
84
  ----------------------------------------------------
78
85
  ✨ High-Quality Standards Applied:
@@ -23,7 +23,7 @@ export const renderIndexFile = async (templatePath, targetDir, config) => {
23
23
  };
24
24
 
25
25
  export const renderDynamicComponents = async (templatePath, targetDir, config) => {
26
- const { architecture, language, database } = config;
26
+ const { architecture, language, database, caching } = config;
27
27
 
28
28
  // MVC Controller
29
29
  if (architecture === 'MVC') {
@@ -32,7 +32,7 @@ export const renderDynamicComponents = async (templatePath, targetDir, config) =
32
32
  const userControllerTemplate = path.join(templatePath, 'src/controllers', `${userControllerName}.ejs`);
33
33
 
34
34
  if (await fs.pathExists(userControllerTemplate)) {
35
- const content = ejs.render(await fs.readFile(userControllerTemplate, 'utf-8'), { database });
35
+ const content = ejs.render(await fs.readFile(userControllerTemplate, 'utf-8'), { database, caching });
36
36
  await fs.writeFile(userControllerPath, content);
37
37
  await fs.remove(path.join(targetDir, 'src/controllers', `${userControllerName}.ejs`));
38
38
  }
@@ -68,9 +68,14 @@ export const renderSwaggerConfig = async (targetDir, config) => {
68
68
 
69
69
  // Check for Swagger config template (typically in src/config/swagger.ts.ejs)
70
70
  // This path is common for both MVC and Clean Arch TS templates based on current structure
71
+ // Check for Swagger config template (typically in src/config/swagger.ts.ejs)
71
72
  const swaggerTsTemplate = path.join(targetDir, 'src', 'config', 'swagger.ts.ejs');
72
73
 
74
+ // Ensure config directory exists
75
+ await fs.ensureDir(path.join(targetDir, 'src', 'config'));
76
+
73
77
  if (await fs.pathExists(swaggerTsTemplate)) {
78
+ // Render if REST APIs
74
79
  if (communication === 'REST APIs') {
75
80
  const content = ejs.render(await fs.readFile(swaggerTsTemplate, 'utf-8'), { communication });
76
81
  await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.ts'), content);
@@ -0,0 +1,56 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import ejs from 'ejs';
4
+
5
+ export const setupCaching = async (templatesDir, targetDir, config) => {
6
+ const { caching, language, architecture } = config;
7
+ if (!caching || caching === 'None') return;
8
+
9
+ if (caching === 'Redis') {
10
+ const langExt = language === 'TypeScript' ? 'ts' : 'js';
11
+ const redisClientObj = language === 'TypeScript' ? 'redisClient.ts' : 'redisClient.js';
12
+ const redisSource = path.join(templatesDir, 'common', 'caching', langExt, `${redisClientObj}.ejs`);
13
+
14
+ let redisTarget;
15
+ let loggerPath;
16
+
17
+ if (architecture === 'MVC') {
18
+ await fs.ensureDir(path.join(targetDir, 'src/config'));
19
+ redisTarget = path.join(targetDir, 'src/config', redisClientObj);
20
+ loggerPath = language === 'TypeScript' ? '@/utils/logger' : '../utils/logger';
21
+ } else {
22
+ // Clean Architecture
23
+ await fs.ensureDir(path.join(targetDir, 'src/infrastructure/caching'));
24
+ redisTarget = path.join(targetDir, 'src/infrastructure/caching', redisClientObj);
25
+ loggerPath = language === 'TypeScript' ? '@/infrastructure/log/logger' : '../log/logger';
26
+
27
+ // Overwrite UseCase with Caching Enabled
28
+ const useCaseName = language === 'TypeScript' ? 'getAllUsers.ts' : 'GetAllUsers.js';
29
+ const useCaseSource = path.join(templatesDir, 'common', 'caching', 'clean', langExt, `${useCaseName}.ejs`);
30
+
31
+ // Both TS and JS templates use 'usecases' directory
32
+ const useCaseTargetDir = path.join(targetDir, 'src/usecases');
33
+ await fs.ensureDir(useCaseTargetDir);
34
+
35
+ if (await fs.pathExists(useCaseSource)) {
36
+ const ucContent = await fs.readFile(useCaseSource, 'utf-8');
37
+ await fs.writeFile(path.join(useCaseTargetDir, useCaseName), ucContent);
38
+ }
39
+
40
+ // Also Overwrite CreateUser with Caching (Invalidation) Enabled
41
+ const createUserParams = language === 'TypeScript' ? { name: 'createUser.ts', src: 'createUser.ts.ejs' } : { name: 'CreateUser.js', src: 'CreateUser.js.ejs' };
42
+ const createUserSource = path.join(templatesDir, 'common', 'caching', 'clean', langExt, createUserParams.src);
43
+
44
+ if (await fs.pathExists(createUserSource)) {
45
+ const createUserContent = await fs.readFile(createUserSource, 'utf-8');
46
+ await fs.writeFile(path.join(useCaseTargetDir, createUserParams.name), createUserContent);
47
+ }
48
+ }
49
+
50
+ if (await fs.pathExists(redisSource)) {
51
+ const redisTemplate = await fs.readFile(redisSource, 'utf-8');
52
+ const content = ejs.render(redisTemplate, { loggerPath });
53
+ await fs.writeFile(redisTarget, content);
54
+ }
55
+ }
56
+ };
@@ -3,7 +3,7 @@ import path from 'path';
3
3
  import ejs from 'ejs';
4
4
 
5
5
  export const renderPackageJson = async (templatesDir, targetDir, config) => {
6
- const { projectName, database, communication, language, viewEngine } = config;
6
+ const { projectName, database, communication, language, viewEngine, caching } = config;
7
7
  const packageJsonPath = path.join(targetDir, 'package.json');
8
8
  const packageTemplate = await fs.readFile(path.join(templatesDir, 'common', 'package.json.ejs'), 'utf-8');
9
9
  const packageContent = ejs.render(packageTemplate, {
@@ -11,26 +11,30 @@ export const renderPackageJson = async (templatesDir, targetDir, config) => {
11
11
  database,
12
12
  communication,
13
13
  language,
14
- viewEngine
14
+ communication,
15
+ language,
16
+ viewEngine,
17
+ caching
15
18
  });
16
19
  await fs.writeFile(packageJsonPath, packageContent);
17
20
  };
18
21
 
19
22
  export const renderDockerCompose = async (templatesDir, targetDir, config) => {
20
- const { projectName, database, dbName, communication } = config;
23
+ const { projectName, database, dbName, communication, caching } = config;
21
24
  const dockerComposePath = path.join(targetDir, 'docker-compose.yml');
22
25
  const dockerTemplate = await fs.readFile(path.join(templatesDir, 'common', 'docker-compose.yml.ejs'), 'utf-8');
23
26
  const dockerContent = ejs.render(dockerTemplate, {
24
27
  projectName,
25
28
  database,
26
29
  dbName,
27
- communication
30
+ communication,
31
+ caching
28
32
  });
29
33
  await fs.writeFile(dockerComposePath, dockerContent);
30
34
  };
31
35
 
32
36
  export const renderReadme = async (templatesDir, targetDir, config) => {
33
- const { projectName, architecture, database, communication, language, ciProvider } = config;
37
+ const { projectName, architecture, database, communication, language, ciProvider, caching } = config;
34
38
  const readmePath = path.join(targetDir, 'README.md');
35
39
  const readmeTemplate = await fs.readFile(path.join(templatesDir, 'common', 'README.md.ejs'), 'utf-8');
36
40
  const readmeContent = ejs.render(readmeTemplate, {
@@ -38,6 +42,7 @@ export const renderReadme = async (templatesDir, targetDir, config) => {
38
42
  architecture,
39
43
  database,
40
44
  communication,
45
+ caching,
41
46
  language,
42
47
  ciProvider
43
48
  });
@@ -86,3 +91,19 @@ export const renderTestSample = async (templatesDir, targetDir, language) => {
86
91
  const testFileName = language === 'TypeScript' ? 'health.test.ts' : 'health.test.js';
87
92
  await fs.writeFile(path.join(targetDir, 'tests', testFileName), healthTestContent);
88
93
  };
94
+
95
+ export const renderEnvExample = async (templatesDir, targetDir, config) => {
96
+ const { database, dbName, communication, projectName, caching } = config;
97
+ const envPath = path.join(targetDir, '.env.example');
98
+ const envTemplate = await fs.readFile(path.join(templatesDir, 'common', '.env.example.ejs'), 'utf-8');
99
+
100
+ const envContent = ejs.render(envTemplate, {
101
+ database,
102
+ dbName,
103
+ communication,
104
+ projectName,
105
+ caching
106
+ });
107
+
108
+ await fs.writeFile(envPath, envContent);
109
+ };
@@ -25,7 +25,19 @@ export const setupDatabase = async (templatesDir, targetDir, config) => {
25
25
  // Flyway for SQL
26
26
  await fs.ensureDir(path.join(targetDir, 'flyway/sql'));
27
27
  const dbType = database === 'PostgreSQL' ? 'postgres' : 'mysql';
28
- await fs.copy(path.join(templatesDir, 'db', dbType), path.join(targetDir, 'flyway/sql'));
28
+ const sourceDir = path.join(templatesDir, 'db', dbType);
29
+
30
+ const files = await fs.readdir(sourceDir);
31
+ for (const file of files) {
32
+ if (file.endsWith('.ejs')) {
33
+ const template = await fs.readFile(path.join(sourceDir, file), 'utf-8');
34
+ const content = ejs.render(template, { ...config });
35
+ const targetFileName = file.replace('.ejs', '');
36
+ await fs.writeFile(path.join(targetDir, 'flyway/sql', targetFileName), content);
37
+ } else {
38
+ await fs.copy(path.join(sourceDir, file), path.join(targetDir, 'flyway/sql', file));
39
+ }
40
+ }
29
41
  }
30
42
 
31
43
  // 2. Database Config
package/lib/prompts.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import inquirer from 'inquirer';
2
2
 
3
3
  const validateName = (name) => {
4
- return /^[a-zA-Z0-9-_]+$/.test(name) ? true : 'Project name may only include letters, numbers, underscores and hashes.';
4
+ return /^[a-zA-Z0-9-_]+$/.test(name) ? true : 'Project name may only include letters, numbers, underscores and dashes.';
5
5
  };
6
6
 
7
7
  export const getProjectDetails = async (options = {}) => {
@@ -62,6 +62,14 @@ export const getProjectDetails = async (options = {}) => {
62
62
  default: 'REST APIs',
63
63
  when: !options.communication
64
64
  },
65
+ {
66
+ type: 'list',
67
+ name: 'caching',
68
+ message: 'Caching Layer:',
69
+ choices: ['None', 'Redis'],
70
+ default: 'None',
71
+ when: (answers) => !options.caching && (options.database || answers.database) !== 'None'
72
+ },
65
73
  {
66
74
  type: 'list',
67
75
  name: 'ciProvider',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-quickstart-structure",
3
- "version": "1.6.1",
3
+ "version": "1.7.5",
4
4
  "type": "module",
5
5
  "description": "A CLI to scaffold Node.js microservices with MVC or Clean Architecture",
6
6
  "main": "bin/index.js",
@@ -1,5 +1,4 @@
1
- <% if (communication === 'REST APIs') { %>
2
- import swaggerJsdoc from 'swagger-jsdoc';
1
+ <% if (communication === 'REST APIs') { %>import swaggerJsdoc from 'swagger-jsdoc';
3
2
 
4
3
  const options = {
5
4
  definition: {