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.
- package/README.md +4 -4
- package/docs/generateCase.md +54 -38
- package/docs/generatorFlow.md +171 -0
- package/lib/generator.js +46 -18
- package/lib/prompts.js +1 -1
- package/package.json +4 -3
- package/templates/clean-architecture/js/src/index.js.ejs +5 -0
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +11 -2
- package/templates/clean-architecture/ts/src/domain/user.ts +1 -1
- package/templates/clean-architecture/ts/src/index.ts.ejs +10 -5
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +13 -4
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts +5 -5
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +1 -1
- package/templates/clean-architecture/ts/src/usecases/createUser.ts +2 -2
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +1 -1
- package/templates/common/Dockerfile +1 -0
- package/templates/common/README.md.ejs +1 -1
- package/templates/common/database/js/models/User.js.mongoose.ejs +19 -0
- package/templates/common/database/js/mongoose.js.ejs +32 -0
- package/templates/common/database/ts/models/User.ts.ejs +1 -1
- package/templates/common/database/ts/models/User.ts.mongoose.ejs +25 -0
- package/templates/common/database/ts/mongoose.ts.ejs +27 -0
- package/templates/common/docker-compose.yml.ejs +31 -8
- package/templates/common/jest.config.js.ejs +4 -1
- package/templates/common/kafka/ts/services/kafkaService.ts.ejs +1 -1
- package/templates/common/migrate-mongo-config.js.ejs +31 -0
- package/templates/common/migrations/init.js.ejs +23 -0
- package/templates/common/package.json.ejs +12 -6
- package/templates/common/public/css/style.css +147 -0
- package/templates/common/tsconfig.json +5 -1
- package/templates/common/views/ejs/index.ejs +44 -20
- package/templates/common/views/pug/index.pug +32 -18
- package/templates/mvc/js/src/controllers/userController.js.ejs +3 -1
- package/templates/mvc/js/src/index.js.ejs +6 -1
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +6 -4
- package/templates/mvc/ts/src/index.ts.ejs +11 -7
- 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 **
|
|
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**
|
|
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 `
|
|
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.
|
package/docs/generateCase.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# NodeJS Quickstart Generator - Test Cases
|
|
2
2
|
|
|
3
|
-
This document lists the **
|
|
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**:
|
|
7
|
-
- (2 Languages × 3 View Engines ×
|
|
8
|
-
- **Clean Architecture**:
|
|
9
|
-
- (2 Languages × 1 View Engine (None) ×
|
|
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:
|
|
11
|
+
**Total Core Combinations: 48**
|
|
12
12
|
|
|
13
|
-
> **Note on CI/CD**: Each of these
|
|
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 (
|
|
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 |
|
|
26
|
-
| 6 | JavaScript | MVC |
|
|
27
|
-
| 7 | JavaScript | MVC | EJS |
|
|
28
|
-
| 8 | JavaScript | MVC | EJS |
|
|
29
|
-
| 9 | JavaScript | MVC |
|
|
30
|
-
| 10 | JavaScript | MVC |
|
|
31
|
-
| 11 | JavaScript | MVC |
|
|
32
|
-
| 12 | JavaScript | MVC |
|
|
33
|
-
| 13 |
|
|
34
|
-
| 14 |
|
|
35
|
-
| 15 |
|
|
36
|
-
| 16 |
|
|
37
|
-
| 17 |
|
|
38
|
-
| 18 |
|
|
39
|
-
| 19 | TypeScript | MVC |
|
|
40
|
-
| 20 | TypeScript | MVC |
|
|
41
|
-
| 21 | TypeScript | MVC |
|
|
42
|
-
| 22 | TypeScript | MVC |
|
|
43
|
-
| 23 | TypeScript | MVC |
|
|
44
|
-
| 24 | TypeScript | MVC |
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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 =
|
|
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',
|
|
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
|
|
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
|
+
"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 <
|
|
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);
|
package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
|
|
@@ -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 '
|
|
8
|
-
<% if (communication === 'REST APIs') { %>import userRoutes from '
|
|
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 '
|
|
12
|
-
<% if (communication === 'Kafka') { %>import { KafkaService } from '
|
|
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
|
-
|
|
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 () => {
|
package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
import { User as UserEntity } from '
|
|
2
|
-
import UserModel from '
|
|
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.
|
|
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.
|
|
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 '
|
|
3
|
-
import CreateUser from '
|
|
4
|
-
import GetAllUsers from '
|
|
5
|
-
import { HTTP_STATUS } from '
|
|
6
|
-
import logger from '
|
|
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 '
|
|
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 '
|
|
1
|
+
import { User } from '@/domain/user';
|
|
2
2
|
|
|
3
|
-
import { UserRepository } from '
|
|
3
|
+
import { UserRepository } from '@/infrastructure/repositories/UserRepository';
|
|
4
4
|
|
|
5
5
|
export default class CreateUser {
|
|
6
6
|
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).
|