nodejs-quickstart-structure 1.3.5 → 1.4.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 (37) hide show
  1. package/README.md +4 -4
  2. package/docs/generateCase.md +54 -38
  3. package/docs/generatorFlow.md +171 -0
  4. package/lib/generator.js +46 -18
  5. package/lib/prompts.js +1 -1
  6. package/package.json +4 -3
  7. package/templates/clean-architecture/js/src/index.js.ejs +5 -0
  8. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +11 -2
  9. package/templates/clean-architecture/ts/src/domain/user.ts +1 -1
  10. package/templates/clean-architecture/ts/src/index.ts.ejs +10 -5
  11. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +13 -4
  12. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts +5 -5
  13. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +1 -1
  14. package/templates/clean-architecture/ts/src/usecases/createUser.ts +2 -2
  15. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +1 -1
  16. package/templates/common/Dockerfile +1 -0
  17. package/templates/common/README.md.ejs +1 -1
  18. package/templates/common/database/js/models/User.js.mongoose.ejs +19 -0
  19. package/templates/common/database/js/mongoose.js.ejs +32 -0
  20. package/templates/common/database/ts/models/User.ts.ejs +1 -1
  21. package/templates/common/database/ts/models/User.ts.mongoose.ejs +25 -0
  22. package/templates/common/database/ts/mongoose.ts.ejs +27 -0
  23. package/templates/common/docker-compose.yml.ejs +31 -8
  24. package/templates/common/jest.config.js.ejs +4 -1
  25. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +1 -1
  26. package/templates/common/migrate-mongo-config.js.ejs +31 -0
  27. package/templates/common/migrations/init.js.ejs +23 -0
  28. package/templates/common/package.json.ejs +12 -6
  29. package/templates/common/public/css/style.css +147 -0
  30. package/templates/common/tsconfig.json +5 -1
  31. package/templates/common/views/ejs/index.ejs +44 -20
  32. package/templates/common/views/pug/index.pug +32 -18
  33. package/templates/mvc/js/src/controllers/userController.js.ejs +3 -1
  34. package/templates/mvc/js/src/index.js.ejs +6 -1
  35. package/templates/mvc/ts/src/controllers/userController.ts.ejs +6 -4
  36. package/templates/mvc/ts/src/index.ts.ejs +11 -7
  37. package/templates/mvc/ts/src/routes/api.ts +1 -1
package/README.md CHANGED
@@ -9,10 +9,10 @@ A powerful CLI tool to scaffold production-ready Node.js microservices with buil
9
9
  - **Interactive CLI**: Easy-to-use prompts to configure your project.
10
10
  - **Multiple Architectures**: Supports both **MVC** (Model-View-Controller) and **Clean Architecture**.
11
11
  - **Language Support**: Choose between **JavaScript** and **TypeScript**.
12
- - **Database Integration**: Pre-configured setup for **MySQL** or **PostgreSQL**.
12
+ - **Database Integration**: Pre-configured setup for **MySQL**, **PostgreSQL**, or **MongoDB**.
13
13
  - **Microservices Ready**: Optional **Kafka** integration for event-driven communication.
14
14
  - **Dockerized**: Automatically generates `docker-compose.yml` for DB, Kafka, and Zookeeper.
15
- - **Database Migrations**: Integrated **Flyway** support for SQL migrations.
15
+ - **Database Migrations/Schemas**: Integrated **Flyway** for SQL migrations or **Mongoose** schemas for MongoDB.
16
16
  - **Professional Standards**: Generated projects come with highly professional, industry-standard tooling.
17
17
 
18
18
  ## 🏆 Professional Standards (New)
@@ -67,7 +67,7 @@ The CLI will guide you through the following steps:
67
67
  1. **Project Name**: The name of the folder to create.
68
68
  2. **Language**: `JavaScript` or `TypeScript`.
69
69
  3. **Architecture**: `MVC` or `Clean Architecture`.
70
- 4. **Database**: `MySQL` or `PostgreSQL`.
70
+ 4. **Database**: `MySQL`, `PostgreSQL`, or `MongoDB`.
71
71
  5. **Database Name**: The name of the initial database.
72
72
  6. **Communication**: `REST APIs` (default) or `Kafka`.
73
73
  7. **CI/CD**: `GitHub Actions`, `Jenkins`, or `None`.
@@ -77,7 +77,7 @@ The CLI will guide you through the following steps:
77
77
  The generated project will include:
78
78
 
79
79
  - `src/`: Source code (controllers, routes, services/use-cases).
80
- - `flyway/sql/`: SQL migration scripts.
80
+ - `flyway/sql/`: SQL migration scripts (if SQL database selected).
81
81
  - `docker-compose.yml`: Services configuration for DB, Flyway, and Kafka.
82
82
  - `package.json`: Dependencies and scripts (`start`, `dev`, `build`).
83
83
  - `tsconfig.json`: (If TypeScript is selected) Type checking configuration.
@@ -1,20 +1,20 @@
1
1
  # NodeJS Quickstart Generator - Test Cases
2
2
 
3
- This document lists the **32 possible project combinations** supported by the `nodejs-quickstart` CLI. These combinations cover all supported languages, architectures, databases, and communication patterns.
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.
4
4
 
5
5
  ## Summary
6
- - **MVC Architecture**: 24 Combinations
7
- - (2 Languages × 3 View Engines × 2 Databases × 2 Patterns)
8
- - **Clean Architecture**: 8 Combinations
9
- - (2 Languages × 1 View Engine (None) × 2 Databases × 2 Patterns)
6
+ - **MVC Architecture**: 36 Combinations
7
+ - (2 Languages × 3 View Engines × 3 Databases × 2 Patterns)
8
+ - **Clean Architecture**: 12 Combinations
9
+ - (2 Languages × 1 View Engine (None) × 3 Databases × 2 Patterns)
10
10
 
11
- **Total Core Combinations: 32**
11
+ **Total Core Combinations: 48**
12
12
 
13
- > **Note on CI/CD**: Each of these 32 combinations can be generated with or without the **GitHub Actions CI Workflow** (`--include-ci`). This effectively creates **64 possible project states**. The validation script currently defaults to *including* CI to verify the full "Professional Standards" feature set.
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.
14
14
 
15
15
  ---
16
16
 
17
- ## 1. MVC Architecture (24 Cases)
17
+ ## 1. MVC Architecture (36 Cases)
18
18
 
19
19
  | # | Language | Architecture | View Engine | Database | Communication |
20
20
  | :--- | :--- | :--- | :--- | :--- | :--- |
@@ -22,37 +22,53 @@ This document lists the **32 possible project combinations** supported by the `n
22
22
  | 2 | JavaScript | MVC | None | MySQL | Kafka |
23
23
  | 3 | JavaScript | MVC | None | PostgreSQL | REST APIs |
24
24
  | 4 | JavaScript | MVC | None | PostgreSQL | Kafka |
25
- | 5 | JavaScript | MVC | EJS | MySQL | REST APIs |
26
- | 6 | JavaScript | MVC | EJS | MySQL | Kafka |
27
- | 7 | JavaScript | MVC | EJS | PostgreSQL | REST APIs |
28
- | 8 | JavaScript | MVC | EJS | PostgreSQL | Kafka |
29
- | 9 | JavaScript | MVC | Pug | MySQL | REST APIs |
30
- | 10 | JavaScript | MVC | Pug | MySQL | Kafka |
31
- | 11 | JavaScript | MVC | Pug | PostgreSQL | REST APIs |
32
- | 12 | JavaScript | MVC | Pug | PostgreSQL | Kafka |
33
- | 13 | TypeScript | MVC | None | MySQL | REST APIs |
34
- | 14 | TypeScript | MVC | None | MySQL | Kafka |
35
- | 15 | TypeScript | MVC | None | PostgreSQL | REST APIs |
36
- | 16 | TypeScript | MVC | None | PostgreSQL | Kafka |
37
- | 17 | TypeScript | MVC | EJS | MySQL | REST APIs |
38
- | 18 | TypeScript | MVC | EJS | MySQL | Kafka |
39
- | 19 | TypeScript | MVC | EJS | PostgreSQL | REST APIs |
40
- | 20 | TypeScript | MVC | EJS | PostgreSQL | Kafka |
41
- | 21 | TypeScript | MVC | Pug | MySQL | REST APIs |
42
- | 22 | TypeScript | MVC | Pug | MySQL | Kafka |
43
- | 23 | TypeScript | MVC | Pug | PostgreSQL | REST APIs |
44
- | 24 | TypeScript | MVC | Pug | PostgreSQL | Kafka |
45
-
46
- ## 2. Clean Architecture (8 Cases)
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
+
58
+ ## 2. Clean Architecture (12 Cases)
47
59
  *Note: Clean Architecture does not use server-side view engines (EJS/Pug).*
48
60
 
49
61
  | # | Language | Architecture | View Engine | Database | Communication |
50
62
  | :--- | :--- | :--- | :--- | :--- | :--- |
51
- | 25 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs |
52
- | 26 | JavaScript | Clean Architecture | N/A | MySQL | Kafka |
53
- | 27 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs |
54
- | 28 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka |
55
- | 29 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs |
56
- | 30 | TypeScript | Clean Architecture | N/A | MySQL | Kafka |
57
- | 31 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs |
58
- | 32 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka |
63
+ | 37 | JavaScript | Clean Architecture | N/A | MySQL | REST APIs |
64
+ | 38 | JavaScript | Clean Architecture | N/A | MySQL | Kafka |
65
+ | 39 | JavaScript | Clean Architecture | N/A | PostgreSQL | REST APIs |
66
+ | 40 | JavaScript | Clean Architecture | N/A | PostgreSQL | Kafka |
67
+ | 41 | JavaScript | Clean Architecture | N/A | MongoDB | REST APIs |
68
+ | 42 | JavaScript | Clean Architecture | N/A | MongoDB | Kafka |
69
+ | 43 | TypeScript | Clean Architecture | N/A | MySQL | REST APIs |
70
+ | 44 | TypeScript | Clean Architecture | N/A | MySQL | Kafka |
71
+ | 45 | TypeScript | Clean Architecture | N/A | PostgreSQL | REST APIs |
72
+ | 46 | TypeScript | Clean Architecture | N/A | PostgreSQL | Kafka |
73
+ | 47 | TypeScript | Clean Architecture | N/A | MongoDB | REST APIs |
74
+ | 48 | TypeScript | Clean Architecture | N/A | MongoDB | Kafka |
@@ -0,0 +1,171 @@
1
+ # Generator Flow Documentation
2
+
3
+ This document outlines the internal flow of the `nodejs-quickstart-structure` generator, including user options, the step-by-step generation process, and the resulting codebase structures.
4
+
5
+ ## 1. Technologies Used
6
+
7
+ The `nodejs-quickstart-structure` CLI is built using the following key technologies:
8
+
9
+ * **[Node.js](https://nodejs.org/)**: The runtime environment.
10
+ * **[Commander.js](https://github.com/tj/commander.js)** (`^13.1.0`): For parsing command-line arguments and options.
11
+ * **[Inquirer.js](https://github.com/SBoudrias/Inquirer.js)** (`^12.4.1`): For interactive command-line user interface (prompts).
12
+ * **[Chalk](https://github.com/chalk/chalk)** (`^5.4.1`): For terminal string styling (color output).
13
+ * **[EJS (Embedded JavaScript templates)](https://github.com/mde/ejs)** (`^3.1.10`): For templating files (dynamic content generation).
14
+ * **[fs-extra](https://github.com/jprichardson/node-fs-extra)** (`^11.3.0`): For enhanced file system methods (copy, ensureDir, etc.).
15
+
16
+ ## 2. User Choices (Cases)
17
+
18
+ The generator prompts the user for the following configurations. These determine the logic and structure of the generated project.
19
+
20
+ | Option | Choices | Default | Description |
21
+ | :--- | :--- | :--- | :--- |
22
+ | **Project Name** | Input String | `nodejs-service` | Name of the project directory. |
23
+ | **Language** | `JavaScript`, `TypeScript` | `TypeScript` | The programming language to use. |
24
+ | **Architecture** | `MVC`, `Clean Architecture` | `MVC` | The architectural pattern. |
25
+ | **View Engine** | `None`, `EJS`, `Pug` | `None` | (MVC Only) Template engine for server-side rendering. |
26
+ | **Database** | `MySQL`, `PostgreSQL`, `MongoDB` | `MySQL` | The primary database. |
27
+ | **Database Name** | Input String | `demo` | The name of the database to use/create. |
28
+ | **Communication**| `REST APIs`, `Kafka` | `REST APIs` | The primary communication method. |
29
+ | **CI/CD Provider**| `None`, `GitHub Actions`, `Jenkins`| `None` | Setup for Continuous Integration/Deployment. |
30
+
31
+ ## 3. Main Generator Flow
32
+
33
+ The `generateProject` function in `lib/generator.js` executes the following steps:
34
+
35
+ 1. **Create Project Directory**: Ensures the directory does not already exist and creates it.
36
+ 2. **Select & Copy Base Structure**:
37
+ * Based on **Architecture** (`mvc`/`clean-architecture`) and **Language** (`js`/`ts`), it selects the appropriate template from `templates/{arch}/{lang}`.
38
+ * Copies the entire base template to the target directory.
39
+ 3. **Render `package.json`**:
40
+ * Uses `templates/common/package.json.ejs`.
41
+ * Injects dependencies based on User Choices (DB drivers, view engines, etc.).
42
+ 4. **Render `docker-compose.yml`**:
43
+ * Uses `templates/common/docker-compose.yml.ejs`.
44
+ * Configures services (DB, Zookeeper/Kafka) based on selection.
45
+ 5. **Render `README.md`**:
46
+ * Generates custom documentation specific to the selected stack.
47
+ 6. **Render `src/index.{js|ts}`**:
48
+ * Processes the entry point file to wire up the selected DB and Architecture.
49
+ 7. **Dynamic Component Generation**:
50
+ * **MVC**: Generates `userController` (imports specific DB service).
51
+ * **Clean Architecture**: Generates `UserRepository` (infrastructure layer implementation).
52
+ * **Clean Architecture (JS only)**: Generates `server.js` (webserver setup).
53
+ 8. **Communication Setup (Kafka)**:
54
+ * If **Kafka** is selected:
55
+ * Copies Kafka client/service templates.
56
+ * **Clean Architecture Restructuring**:
57
+ * Moves service to `src/infrastructure/messaging`.
58
+ * Moves config to `src/infrastructure/config`.
59
+ * Removes REST-specific folders (`interfaces/routes`, `interfaces/controllers`).
60
+ * **MVC Cleanup**:
61
+ * If no View Engine is selected, removes `src/controllers` and `src/routes` (assumes pure worker).
62
+ 9. **Common Configuration**:
63
+ * Copies `.gitignore`, `.dockerignore`, `Dockerfile`.
64
+ * Copies `tsconfig.json` (if TypeScript).
65
+ 10. **Database Setup**:
66
+ * **MongoDB**: Sets up `migrate-mongo-config.js` and initial migration script.
67
+ * **SQL (MySQL/Postgres)**: Sets up `flyway/sql` directory and copies initial SQL migration files.
68
+ 11. **Database Connection Config**:
69
+ * Renders `database.{js|ts}` or `mongoose.{js|ts}` based on DB selection.
70
+ * Places it in `src/config` (MVC) or `src/infrastructure/database` (Clean Arch).
71
+ 12. **Model Generation**:
72
+ * Renders `User` model (Mongoose schema or Sequelize/TypeORM model) in the appropriate directory.
73
+ 13. **View Engine Setup (MVC)**:
74
+ * If selected, copies views (`views/ejs` or `views/pug`) and `public` assets.
75
+ 14. **Swagger Config**:
76
+ * If **REST APIs** is selected, generates Swagger configuration.
77
+ 15. **Code Quality Setup**:
78
+ * Generates `.eslintrc.json`, `.prettierrc`, `.lintstagedrc`.
79
+ 16. **Test Setup**:
80
+ * Generates `jest.config.js` and a sample `health.test.{js|ts}`.
81
+ 17. **CI/CD Setup**:
82
+ * Copies GitHub Actions workflow or renders `Jenkinsfile` if selected.
83
+
84
+ ## 4. TypeScript vs JavaScript Generation Steps
85
+
86
+ The logic handles language differences via conditional checks and file extensions (`langExt` variable).
87
+
88
+ | Step | JavaScript (`js`) | TypeScript (`ts`) |
89
+ | :--- | :--- | :--- |
90
+ | **Base Template** | `templates/{arch}/js` | `templates/{arch}/ts` |
91
+ | **Entry Point** | `src/index.js` | `src/index.ts` |
92
+ | **tsconfig.json** | Skipped | Copied from `templates/common/tsconfig.json` |
93
+ | **Linting** | Standard JS config | TS-specific parser and plugins in `.eslintrc` |
94
+ | **Database Config** | `mongoose.js` / `database.js` | `mongoose.ts` / `database.ts` |
95
+ | **Models/Controllers**| `.js` extension | `.ts` extension |
96
+ | **Build Step** | No compilation needed | Compilation typically handled by `tsc` or `ts-node` in dev |
97
+
98
+ ## 5. Possible Codebase Structures
99
+
100
+ The final structure depends heavily on **Architecture**, **Communication**, and **View Engine**.
101
+
102
+ ### Case A: MVC (REST API)
103
+ Standard architecture for web APIs.
104
+
105
+ ```text
106
+ project-name/
107
+ ├── src/
108
+ │ ├── config/ # Database, Swagger, etc.
109
+ │ ├── controllers/ # Request handlers
110
+ │ ├── models/ # Database models
111
+ │ ├── routes/ # Express routes
112
+ │ └── index.js|ts # Entry point
113
+ ├── tests/ # Jest tests
114
+ ├── package.json
115
+ ├── Dockerfile
116
+ └── docker-compose.yml
117
+ ```
118
+
119
+ ### Case B: MVC (Web App with Views)
120
+ Includes frontend views rendered on the server.
121
+
122
+ ```text
123
+ project-name/
124
+ ├── public/ # CSS, JS, Images
125
+ ├── src/
126
+ │ ├── config/
127
+ │ ├── controllers/
128
+ │ ├── models/
129
+ │ ├── routes/
130
+ │ ├── views/ # EJS or Pug templates
131
+ │ └── index.js|ts
132
+ └── ...
133
+ ```
134
+
135
+ ### Case C: Clean Architecture (REST API)
136
+ Separation of concerns with Domain, Use Cases, and Infrastructure.
137
+
138
+ ```text
139
+ project-name/
140
+ ├── src/
141
+ │ ├── domain/ # Entities (Enterprise rules)
142
+ │ ├── use_cases/ # Application business rules
143
+ │ ├── interfaces/ # Adapters
144
+ │ │ ├── controllers/
145
+ │ │ └── routes/
146
+ │ ├── infrastructure/ # Frameworks & Drivers
147
+ │ │ ├── config/ # Environment config
148
+ │ │ ├── database/ # DB connection & models
149
+ │ │ ├── repositories/ # Data access implementation
150
+ │ │ └── webserver/ # Express server setup
151
+ │ └── index.js|ts
152
+ └── ...
153
+ ```
154
+
155
+ ### Case D: Clean Architecture (Kafka Worker)
156
+ Optimized for event-driven microservices. HTTP routes are removed.
157
+
158
+ ```text
159
+ project-name/
160
+ ├── src/
161
+ │ ├── domain/
162
+ │ ├── use_cases/
163
+ │ ├── infrastructure/
164
+ │ │ ├── config/ # Includes Kafka config
165
+ │ │ ├── database/
166
+ │ │ ├── messaging/ # Kafka Client/Consumer
167
+ │ │ ├── repositories/
168
+ │ │ └── webserver/ # (Optional/Minimal)
169
+ │ └── index.js|ts
170
+ └── ...
171
+ ```
package/lib/generator.js CHANGED
@@ -131,15 +131,15 @@ export const generateProject = async (config) => {
131
131
  const kafkaServiceTemplate = path.join(targetDir, 'src', 'services', `${kafkaServiceFileName}.ejs`);
132
132
 
133
133
  if (await fs.pathExists(kafkaServiceTemplate)) {
134
- const loggerPath = architecture === 'Clean Architecture' ? '../log/logger' : '../utils/logger';
135
- // Note: For MVC, it's relative to src/services (../utils/logger). Wait, ../utils/logger means src/utils/logger.
136
- // src/services/kafka.ts -> ../utils/logger -> src/utils/logger. Correct.
137
- // But wait, generated code for MVC usually puts it in src/services.
138
- // Let's re-verify MVC structure for logger.
139
- // In MVC, logger is usually in src/utils/logger.ts?
140
- // Let's check where logger is copied for MVC.
134
+ let loggerPath = architecture === 'Clean Architecture' ? '../log/logger' : '../utils/logger';
135
+ let configPath = '../config/kafka';
136
+
137
+ if (language === 'TypeScript') {
138
+ loggerPath = architecture === 'Clean Architecture' ? '@/infrastructure/log/logger' : '@/utils/logger';
139
+ configPath = architecture === 'Clean Architecture' ? '@/infrastructure/config/kafka' : '@/config/kafka';
140
+ }
141
141
 
142
- const content = ejs.render(await fs.readFile(kafkaServiceTemplate, 'utf-8'), { loggerPath });
142
+ const content = ejs.render(await fs.readFile(kafkaServiceTemplate, 'utf-8'), { loggerPath, configPath });
143
143
  await fs.writeFile(path.join(targetDir, 'src', 'services', kafkaServiceFileName), content);
144
144
  await fs.remove(kafkaServiceTemplate);
145
145
  }
@@ -198,14 +198,33 @@ export const generateProject = async (config) => {
198
198
  await fs.copy(path.join(templatesDir, 'common', 'tsconfig.json'), path.join(targetDir, 'tsconfig.json'));
199
199
  }
200
200
 
201
- // 6. Database Migrations (Flyway)
202
- await fs.ensureDir(path.join(targetDir, 'flyway/sql'));
203
- const dbType = database === 'PostgreSQL' ? 'postgres' : 'mysql';
204
- await fs.copy(path.join(templatesDir, 'db', dbType), path.join(targetDir, 'flyway/sql'));
201
+ // 6. Database Migrations
202
+ if (database === 'MongoDB') {
203
+ // Copy migrate-mongo config
204
+ const migrateConfigTemplate = await fs.readFile(path.join(templatesDir, 'common', 'migrate-mongo-config.js.ejs'), 'utf-8');
205
+ const migrateConfigContent = ejs.render(migrateConfigTemplate, { dbName });
206
+ await fs.writeFile(path.join(targetDir, 'migrate-mongo-config.js'), migrateConfigContent);
207
+
208
+ // Setup migrations directory
209
+ await fs.ensureDir(path.join(targetDir, 'migrations'));
210
+
211
+ // Create initial migration file with timestamp
212
+ const timestamp = new Date().toISOString().replace(/[-T:.Z]/g, '').slice(0, 14); // YYYYMMDDHHMMSS
213
+ const migrationTemplate = await fs.readFile(path.join(templatesDir, 'common', 'migrations', 'init.js.ejs'), 'utf-8');
214
+ await fs.writeFile(path.join(targetDir, 'migrations', `${timestamp}-initial-setup.js`), migrationTemplate);
215
+
216
+ } else {
217
+ // Flyway for SQL
218
+ await fs.ensureDir(path.join(targetDir, 'flyway/sql'));
219
+ const dbType = database === 'PostgreSQL' ? 'postgres' : 'mysql';
220
+ await fs.copy(path.join(templatesDir, 'db', dbType), path.join(targetDir, 'flyway/sql'));
221
+ }
205
222
 
206
223
  // 7. Database Config
207
- const dbConfigFileName = language === 'TypeScript' ? 'database.ts' : 'database.js';
208
- const dbConfigTemplateSource = path.join(templatesDir, 'common', 'database', langExt, `${dbConfigFileName}.ejs`);
224
+ const dbConfigFileName = language === 'TypeScript' ? (database === 'MongoDB' ? 'mongoose.ts' : 'database.ts') : (database === 'MongoDB' ? 'mongoose.js' : 'database.js');
225
+ const dbConfigTemplateSource = database === 'MongoDB'
226
+ ? path.join(templatesDir, 'common', 'database', langExt, `${dbConfigFileName}.ejs`)
227
+ : path.join(templatesDir, 'common', 'database', langExt, `${dbConfigFileName}.ejs`);
209
228
 
210
229
  let dbConfigTarget;
211
230
 
@@ -217,22 +236,27 @@ export const generateProject = async (config) => {
217
236
  await fs.copy(path.join(templatesDir, 'common', 'views', viewEngine.toLowerCase()), path.join(targetDir, 'src/views'));
218
237
  }
219
238
  await fs.ensureDir(path.join(targetDir, 'src/config'));
220
- dbConfigTarget = path.join(targetDir, 'src/config', dbConfigFileName);
239
+ dbConfigTarget = path.join(targetDir, 'src/config', database === 'MongoDB' ? (language === 'TypeScript' ? 'database.ts' : 'database.js') : dbConfigFileName);
221
240
  } else {
222
241
  // Clean Architecture
223
242
  await fs.ensureDir(path.join(targetDir, 'src/infrastructure/database'));
224
- dbConfigTarget = path.join(targetDir, 'src/infrastructure/database', dbConfigFileName);
243
+ dbConfigTarget = path.join(targetDir, 'src/infrastructure/database', language === 'TypeScript' ? 'database.ts' : 'database.js');
225
244
  }
226
245
 
227
246
  if (await fs.pathExists(dbConfigTemplateSource)) {
228
247
  const dbTemplate = await fs.readFile(dbConfigTemplateSource, 'utf-8');
229
- const dbContent = ejs.render(dbTemplate, { database, dbName });
248
+ const dbContent = ejs.render(dbTemplate, { database, dbName, architecture });
249
+ // Ensure consistent naming for imports in other files
250
+ // For MVC, we might want to rename mongoose.js to database.js to minimize refactoring in index.js?
251
+ // Actually, let's keep it consistent. If MVC, we typically call it 'database.js' in require.
252
+ // So we should save it as 'database.js' even if source is mongoose.js.ejs
230
253
  await fs.writeFile(dbConfigTarget, dbContent);
231
254
  }
232
255
 
233
256
  // Render Models
234
257
  const modelFileName = language === 'TypeScript' ? 'User.ts' : 'User.js';
235
- const modelTemplateSource = path.join(templatesDir, 'common', 'database', langExt, 'models', `${modelFileName}.ejs`);
258
+ const sourceModelName = database === 'MongoDB' ? `${modelFileName}.mongoose.ejs` : `${modelFileName}.ejs`;
259
+ const modelTemplateSource = path.join(templatesDir, 'common', 'database', langExt, 'models', sourceModelName);
236
260
  let modelTarget;
237
261
 
238
262
  if (architecture === 'MVC') {
@@ -252,6 +276,10 @@ export const generateProject = async (config) => {
252
276
 
253
277
  // 8. View Engine (MVC)
254
278
  if (architecture === 'MVC' && viewEngine && viewEngine !== 'None') {
279
+ const publicDir = path.join(templatesDir, 'common', 'public');
280
+ if (await fs.pathExists(publicDir)) {
281
+ await fs.copy(publicDir, path.join(targetDir, 'public'));
282
+ }
255
283
  }
256
284
 
257
285
  // 9. Render Swagger Config (if .ejs exists)
package/lib/prompts.js CHANGED
@@ -42,7 +42,7 @@ export const getProjectDetails = async (options = {}) => {
42
42
  type: 'list',
43
43
  name: 'database',
44
44
  message: 'Select Database:',
45
- choices: ['MySQL', 'PostgreSQL'],
45
+ choices: ['MySQL', 'PostgreSQL', 'MongoDB'],
46
46
  default: 'MySQL',
47
47
  when: !options.database
48
48
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-quickstart-structure",
3
- "version": "1.3.5",
3
+ "version": "1.4.1",
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",
@@ -11,7 +11,8 @@
11
11
  "test": "echo \"Error: no test specified\" && exit 1",
12
12
  "test:e2e": "npm run test:e2e:windows",
13
13
  "test:e2e:windows": "node scripts/validate-windows.js",
14
- "test:e2e:linux": "node scripts/validate-linux.js"
14
+ "test:e2e:linux": "node scripts/validate-linux.js",
15
+ "test:verify:mongo": "node scripts/verify-migration.js"
15
16
  },
16
17
  "keywords": [
17
18
  "nodejs",
@@ -20,7 +21,7 @@
20
21
  "mvc",
21
22
  "clean-architecture"
22
23
  ],
23
- "author": "Pau Dang <phucdangb1400718@gmail.com>",
24
+ "author": "Pau Dang <[EMAIL_ADDRESS]>",
24
25
  "repository": {
25
26
  "type": "git",
26
27
  "url": "git+https://github.com/paudang/nodejs-quickstart-structure.git"
@@ -11,8 +11,13 @@ const syncDatabase = async () => {
11
11
  let retries = 30;
12
12
  while (retries) {
13
13
  try {
14
+ <% if (database === 'MongoDB') { %>
15
+ const connectDB = require('./infrastructure/database/database');
16
+ await connectDB();
17
+ <% } else { %>
14
18
  const sequelize = require('./infrastructure/database/database');
15
19
  await sequelize.sync();
20
+ <% } %>
16
21
  logger.info('Database synced');
17
22
  // Start the web server after DB sync
18
23
  startServer(PORT);
@@ -3,16 +3,25 @@ const UserModel = require('../database/models/User');
3
3
  class UserRepository {
4
4
  async save(user) {
5
5
  const newUser = await UserModel.create({ name: user.name, email: user.email });
6
- return { ...user, id: newUser.id };
6
+ <% if (database === 'MongoDB') { %> return { ...user, id: newUser._id.toString() };
7
+ <% } else { %> return { ...user, id: newUser.id };
8
+ <% } -%>
7
9
  }
8
10
 
9
11
  async getUsers() {
10
- const users = await UserModel.findAll();
12
+ <% if (database === 'MongoDB') { %> const users = await UserModel.find();
13
+ return users.map(user => ({
14
+ id: user._id.toString(),
15
+ name: user.name,
16
+ email: user.email
17
+ }));
18
+ <% } else { %> const users = await UserModel.findAll();
11
19
  return users.map(user => ({
12
20
  id: user.id,
13
21
  name: user.name,
14
22
  email: user.email
15
23
  }));
24
+ <% } -%>
16
25
  }
17
26
  }
18
27
 
@@ -1,6 +1,6 @@
1
1
  export class User {
2
2
  constructor(
3
- public id: number | null,
3
+ public id: number | string | null,
4
4
  public name: string,
5
5
  public email: string
6
6
  ) { }
@@ -4,12 +4,12 @@ import helmet from 'helmet';
4
4
  import hpp from 'hpp';
5
5
  import rateLimit from 'express-rate-limit';
6
6
  import dotenv from 'dotenv';
7
- import logger from './infrastructure/log/logger';
8
- <% if (communication === 'REST APIs') { %>import userRoutes from './interfaces/routes/userRoutes';<% } -%>
7
+ import logger from '@/infrastructure/log/logger';
8
+ <% if (communication === 'REST APIs') { %>import userRoutes from '@/interfaces/routes/userRoutes';<% } -%>
9
9
  <% if (communication === 'REST APIs') { -%>
10
10
  import swaggerUi from 'swagger-ui-express';
11
- import swaggerSpecs from './config/swagger';<% } -%>
12
- <% if (communication === 'Kafka') { %>import { KafkaService } from './infrastructure/messaging/kafkaClient';<% } -%>
11
+ import swaggerSpecs from '@/config/swagger';<% } -%>
12
+ <% if (communication === 'Kafka') { %>import { KafkaService } from '@/infrastructure/messaging/kafkaClient';<% } -%>
13
13
 
14
14
  dotenv.config();
15
15
 
@@ -42,8 +42,13 @@ const syncDatabase = async () => {
42
42
  let retries = 30;
43
43
  while (retries) {
44
44
  try {
45
- const sequelize = (await import('./infrastructure/database/database')).default;
45
+ <% if (database === 'MongoDB') { %>
46
+ const connectDB = (await import('@/infrastructure/database/database')).default;
47
+ await connectDB();
48
+ <% } else { %>
49
+ const sequelize = (await import('@/infrastructure/database/database')).default;
46
50
  await sequelize.sync();
51
+ <% } %>
47
52
  logger.info('Database synced');
48
53
 
49
54
  app.listen(port, async () => {
@@ -1,18 +1,27 @@
1
- import { User as UserEntity } from '../../domain/user';
2
- import UserModel from '../database/models/User';
1
+ import { User as UserEntity } from '@/domain/user';
2
+ import UserModel from '@/infrastructure/database/models/User';
3
3
 
4
4
  export class UserRepository {
5
5
  async save(user: UserEntity): Promise<UserEntity> {
6
6
  const newUser = await UserModel.create({ name: user.name, email: user.email });
7
- return { id: newUser.id, name: newUser.name, email: newUser.email };
7
+ <% if (database === 'MongoDB') { %> return { id: newUser._id.toString(), name: newUser.name, email: newUser.email };
8
+ <% } else { %> return { id: newUser.id, name: newUser.name, email: newUser.email };
9
+ <% } -%>
8
10
  }
9
11
 
10
12
  async getUsers(): Promise<UserEntity[]> {
11
- const users = await UserModel.findAll();
13
+ <% if (database === 'MongoDB') { %> const users = await UserModel.find();
14
+ return users.map(user => ({
15
+ id: user._id.toString(),
16
+ name: user.name,
17
+ email: user.email
18
+ }));
19
+ <% } else { %> const users = await UserModel.findAll();
12
20
  return users.map(user => ({
13
21
  id: user.id,
14
22
  name: user.name,
15
23
  email: user.email
16
24
  }));
25
+ <% } -%>
17
26
  }
18
27
  }
@@ -1,9 +1,9 @@
1
1
  import { Request, Response } from 'express';
2
- import { UserRepository } from '../../infrastructure/repositories/UserRepository';
3
- import CreateUser from '../../usecases/createUser';
4
- import GetAllUsers from '../../usecases/getAllUsers';
5
- import { HTTP_STATUS } from '../../utils/httpCodes';
6
- import logger from '../../infrastructure/log/logger';
2
+ import { UserRepository } from '@/infrastructure/repositories/UserRepository';
3
+ import CreateUser from '@/usecases/createUser';
4
+ import GetAllUsers from '@/usecases/getAllUsers';
5
+ import { HTTP_STATUS } from '@/utils/httpCodes';
6
+ import logger from '@/infrastructure/log/logger';
7
7
 
8
8
  export class UserController {
9
9
  private createUserUseCase: CreateUser;
@@ -1,5 +1,5 @@
1
1
  import { Router, Request, Response } from 'express';
2
- import { UserController } from '../controllers/userController';
2
+ import { UserController } from '@/interfaces/controllers/userController';
3
3
 
4
4
  const router = Router();
5
5
  const userController = new UserController();
@@ -1,6 +1,6 @@
1
- import { User } from '../domain/user';
1
+ import { User } from '@/domain/user';
2
2
 
3
- import { UserRepository } from '../infrastructure/repositories/UserRepository';
3
+ import { UserRepository } from '@/infrastructure/repositories/UserRepository';
4
4
 
5
5
  export default class CreateUser {
6
6
  constructor(private userRepository: UserRepository) {}
@@ -1,4 +1,4 @@
1
- import { UserRepository } from '../infrastructure/repositories/UserRepository';
1
+ import { UserRepository } from '@/infrastructure/repositories/UserRepository';
2
2
 
3
3
  export default class GetAllUsers {
4
4
  constructor(private userRepository: UserRepository) {}
@@ -40,6 +40,7 @@ COPY --from=builder /app/src ./src
40
40
  # Copy other necessary files (like views if MVC)
41
41
  <% if (viewEngine && viewEngine !== 'None') { %>
42
42
  COPY --from=builder /app/src/views ./dist/views
43
+ <% if (viewEngine && viewEngine !== 'None') { %>COPY --from=builder /app/public ./public<% } %>
43
44
  <% } %>
44
45
 
45
46
  EXPOSE 3000
@@ -10,7 +10,7 @@ This project comes pre-configured with industry-standard tooling for **Code Qual
10
10
  ## 🚀 Key Features
11
11
 
12
12
  - **Architecture**: <%= architecture %> (<% if (architecture === 'Clean Architecture') { %>Domain, UseCases, Infrastructure<% } else { %>MVC Pattern<% } %>).
13
- - **Database**: <%= database %> with **Flyway** migrations.
13
+ - **Database**: <%= database %> <% if (database !== 'MongoDB') { %>with **Flyway** migrations<% } else { %>with **Mongoose** schemas<% } %>.
14
14
  - **Security**: Helmet, CORS, Rate Limiting, HPP.
15
15
  - **Quality**: Eslint, Prettier, Husky, Lint-Staged.
16
16
  - **Testing**: Jest (Unit & Integration).