nodejs-quickstart-structure 1.3.9 → 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 +34 -10
- 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 +5 -0
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +11 -2
- 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.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/migrate-mongo-config.js.ejs +31 -0
- package/templates/common/migrations/init.js.ejs +23 -0
- package/templates/common/package.json.ejs +8 -4
- package/templates/mvc/js/src/controllers/userController.js.ejs +3 -1
- package/templates/mvc/js/src/index.js.ejs +5 -0
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +3 -1
- package/templates/mvc/ts/src/index.ts.ejs +5 -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
|
@@ -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') {
|
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
|
|
|
@@ -42,8 +42,13 @@ const syncDatabase = async () => {
|
|
|
42
42
|
let retries = 30;
|
|
43
43
|
while (retries) {
|
|
44
44
|
try {
|
|
45
|
+
<% if (database === 'MongoDB') { %>
|
|
46
|
+
const connectDB = (await import('@/infrastructure/database/database')).default;
|
|
47
|
+
await connectDB();
|
|
48
|
+
<% } else { %>
|
|
45
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
|
@@ -4,15 +4,24 @@ import UserModel from '@/infrastructure/database/models/User';
|
|
|
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
|
}
|
|
@@ -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).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const UserSchema = new mongoose.Schema({
|
|
4
|
+
name: {
|
|
5
|
+
type: String,
|
|
6
|
+
required: true
|
|
7
|
+
},
|
|
8
|
+
email: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: true,
|
|
11
|
+
unique: true
|
|
12
|
+
},
|
|
13
|
+
createdAt: {
|
|
14
|
+
type: Date,
|
|
15
|
+
default: Date.now
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
module.exports = mongoose.model('User', UserSchema);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
let logger;
|
|
4
|
+
<% if (architecture === 'MVC') { %>
|
|
5
|
+
logger = require('../utils/logger');
|
|
6
|
+
<% } else { %>
|
|
7
|
+
logger = require('../log/logger');
|
|
8
|
+
<% } %>
|
|
9
|
+
|
|
10
|
+
const connectDB = async () => {
|
|
11
|
+
const dbHost = process.env.DB_HOST || 'localhost';
|
|
12
|
+
const mongoURI = process.env.MONGO_URI || `mongodb://${dbHost}:27017/<%= dbName %>`;
|
|
13
|
+
|
|
14
|
+
let retries = 5;
|
|
15
|
+
while (retries) {
|
|
16
|
+
try {
|
|
17
|
+
await mongoose.connect(mongoURI, {
|
|
18
|
+
useNewUrlParser: true,
|
|
19
|
+
useUnifiedTopology: true
|
|
20
|
+
});
|
|
21
|
+
logger.info('MongoDB Connected...');
|
|
22
|
+
break;
|
|
23
|
+
} catch (err) {
|
|
24
|
+
logger.error('MongoDB connection failed:', err);
|
|
25
|
+
retries -= 1;
|
|
26
|
+
logger.info(`Retries left: ${retries}. Waiting 5s...`);
|
|
27
|
+
await new Promise(res => setTimeout(res, 5000));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = connectDB; // Export function to call in index.js
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import mongoose, { Schema, Document } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
export interface IUser extends Document {
|
|
4
|
+
name: string;
|
|
5
|
+
email: string;
|
|
6
|
+
createdAt: Date;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const UserSchema: Schema = new Schema({
|
|
10
|
+
name: {
|
|
11
|
+
type: String,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
email: {
|
|
15
|
+
type: String,
|
|
16
|
+
required: true,
|
|
17
|
+
unique: true
|
|
18
|
+
},
|
|
19
|
+
createdAt: {
|
|
20
|
+
type: Date,
|
|
21
|
+
default: Date.now
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default mongoose.model<IUser>('User', UserSchema);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
<% if (architecture === 'MVC') { %>
|
|
3
|
+
import logger from '@/utils/logger';
|
|
4
|
+
<% } else { %>
|
|
5
|
+
import logger from '@/infrastructure/log/logger';
|
|
6
|
+
<% } %>
|
|
7
|
+
|
|
8
|
+
const connectDB = async (): Promise<void> => {
|
|
9
|
+
const dbHost = process.env.DB_HOST || 'localhost';
|
|
10
|
+
const mongoURI = process.env.MONGO_URI || `mongodb://${dbHost}:27017/<%= dbName %>`;
|
|
11
|
+
|
|
12
|
+
let retries = 5;
|
|
13
|
+
while (retries) {
|
|
14
|
+
try {
|
|
15
|
+
await mongoose.connect(mongoURI);
|
|
16
|
+
logger.info('MongoDB Connected...');
|
|
17
|
+
break;
|
|
18
|
+
} catch (err) {
|
|
19
|
+
logger.error('MongoDB connection failed:', err);
|
|
20
|
+
retries -= 1;
|
|
21
|
+
logger.info(`Retries left: ${retries}. Waiting 5s...`);
|
|
22
|
+
await new Promise(res => setTimeout(res, 5000));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default connectDB;
|
|
@@ -18,7 +18,7 @@ services:
|
|
|
18
18
|
- DB_PASSWORD=root
|
|
19
19
|
- DB_NAME=<%= dbName %>
|
|
20
20
|
<% } %><% if (database === 'PostgreSQL') { %> - DB_USER=postgres
|
|
21
|
-
- DB_PASSWORD=
|
|
21
|
+
- DB_PASSWORD=root
|
|
22
22
|
- DB_NAME=<%= dbName %>
|
|
23
23
|
<% } -%>
|
|
24
24
|
<% } else { %>
|
|
@@ -29,30 +29,52 @@ services:
|
|
|
29
29
|
- DB_PASSWORD=root
|
|
30
30
|
- DB_NAME=<%= dbName %>
|
|
31
31
|
<% } %><% if (database === 'PostgreSQL') { %> - DB_USER=postgres
|
|
32
|
-
- DB_PASSWORD=
|
|
32
|
+
- DB_PASSWORD=root
|
|
33
33
|
- DB_NAME=<%= dbName %>
|
|
34
34
|
<% } -%>
|
|
35
35
|
<% } %>
|
|
36
36
|
db:
|
|
37
37
|
<% if (database === 'MySQL') { %> image: mysql:8.0
|
|
38
|
-
command: --default-authentication-plugin=mysql_native_password
|
|
39
38
|
restart: always
|
|
40
39
|
environment:
|
|
41
40
|
MYSQL_ROOT_PASSWORD: root
|
|
42
41
|
MYSQL_DATABASE: <%= dbName %>
|
|
43
42
|
ports:
|
|
44
43
|
- "${DB_PORT:-3306}:3306"
|
|
45
|
-
|
|
44
|
+
volumes:
|
|
45
|
+
- ./flyway/sql:/docker-entrypoint-initdb.d
|
|
46
|
+
<% } else if (database === 'PostgreSQL') { %> image: postgres:15
|
|
46
47
|
restart: always
|
|
47
48
|
environment:
|
|
48
49
|
POSTGRES_USER: postgres
|
|
49
|
-
POSTGRES_PASSWORD:
|
|
50
|
+
POSTGRES_PASSWORD: root
|
|
50
51
|
POSTGRES_DB: <%= dbName %>
|
|
51
52
|
ports:
|
|
52
53
|
- "${DB_PORT:-5432}:5432"
|
|
53
|
-
|
|
54
|
-
-
|
|
54
|
+
volumes:
|
|
55
|
+
- ./flyway/sql:/docker-entrypoint-initdb.d
|
|
56
|
+
<% } else if (database === 'MongoDB') { %> image: mongo:latest
|
|
57
|
+
restart: always
|
|
58
|
+
environment:
|
|
59
|
+
MONGO_INITDB_DATABASE: <%= dbName %>
|
|
60
|
+
ports:
|
|
61
|
+
- "${DB_PORT:-27017}:27017"
|
|
62
|
+
volumes:
|
|
63
|
+
- mongodb_data:/data/db
|
|
55
64
|
|
|
65
|
+
mongo-migrate:
|
|
66
|
+
image: node:18-alpine
|
|
67
|
+
working_dir: /app
|
|
68
|
+
volumes:
|
|
69
|
+
- .:/app
|
|
70
|
+
command: sh -c "npm install migrate-mongo && npm run migrate"
|
|
71
|
+
environment:
|
|
72
|
+
- DB_HOST=db
|
|
73
|
+
- DB_NAME=<%= dbName %>
|
|
74
|
+
depends_on:
|
|
75
|
+
- db
|
|
76
|
+
<% } %>
|
|
77
|
+
<% if (database !== 'MongoDB') { %>
|
|
56
78
|
flyway:
|
|
57
79
|
image: flyway/flyway
|
|
58
80
|
command: -connectRetries=60 migrate
|
|
@@ -64,9 +86,10 @@ services:
|
|
|
64
86
|
FLYWAY_PASSWORD: root
|
|
65
87
|
<% } %><% if (database === 'PostgreSQL') { %> FLYWAY_URL: jdbc:postgresql://db:5432/<%= dbName %>
|
|
66
88
|
FLYWAY_USER: postgres
|
|
67
|
-
FLYWAY_PASSWORD:
|
|
89
|
+
FLYWAY_PASSWORD: root
|
|
68
90
|
<% } %> depends_on:
|
|
69
91
|
- db
|
|
92
|
+
<% } %>
|
|
70
93
|
<% if (communication === 'Kafka') { %> zookeeper:
|
|
71
94
|
image: confluentinc/cp-zookeeper:7.4.0
|
|
72
95
|
environment:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
mongodb: {
|
|
3
|
+
url: process.env.MONGO_URI || `mongodb://${process.env.DB_HOST || 'localhost'}:27017`,
|
|
4
|
+
databaseName: process.env.DB_NAME || '<%= dbName %>',
|
|
5
|
+
|
|
6
|
+
options: {
|
|
7
|
+
// useNewUrlParser: true, // No longer needed in Node.js driver v4+
|
|
8
|
+
// useUnifiedTopology: true, // No longer needed in Node.js driver v4+
|
|
9
|
+
// connectTimeoutMS: 3600000, // increase connection timeout to 1 hour
|
|
10
|
+
// socketTimeoutMS: 3600000, // increase socket timeout to 1 hour
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// The migrations dir, can be an relative or absolute path. Only edit this when really necessary.
|
|
15
|
+
migrationsDir: "migrations",
|
|
16
|
+
|
|
17
|
+
// The mongodb collection where the applied changes are stored. Only edit this when really necessary.
|
|
18
|
+
changelogCollectionName: "changelog",
|
|
19
|
+
|
|
20
|
+
// The file extension to create migrations and search for in migration dir
|
|
21
|
+
migrationFileExtension: ".js",
|
|
22
|
+
|
|
23
|
+
// Enable the algorithm to create a checksum of the file contents and use that in the comparison to determine
|
|
24
|
+
// if the file should be run. Requires that scripts are coded to be run multiple times.
|
|
25
|
+
useFileHash: false,
|
|
26
|
+
|
|
27
|
+
// Don't change this, unless you know what you are doing
|
|
28
|
+
moduleSystem: 'commonjs',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
module.exports = config;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
async up(db, client) {
|
|
3
|
+
const adminEmail = 'admin@example.com';
|
|
4
|
+
const existingAdmin = await db.collection('users').findOne({ email: adminEmail });
|
|
5
|
+
|
|
6
|
+
if (!existingAdmin) {
|
|
7
|
+
await db.collection('users').insertOne({
|
|
8
|
+
name: 'Admin User',
|
|
9
|
+
email: adminEmail,
|
|
10
|
+
createdAt: new Date(),
|
|
11
|
+
updatedAt: new Date()
|
|
12
|
+
});
|
|
13
|
+
console.log('Admin User seeded successfully');
|
|
14
|
+
} else {
|
|
15
|
+
console.log('Admin User already exists, skipping seed');
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
async down(db, client) {
|
|
20
|
+
// Optional: Undo the seed. Usually for seeds we might want to keep data, but strictly speaking 'down' should reverse 'up'.
|
|
21
|
+
// await db.collection('users').deleteOne({ email: 'admin@example.com' });
|
|
22
|
+
}
|
|
23
|
+
};
|
|
@@ -13,16 +13,21 @@
|
|
|
13
13
|
"prepare": "husky install",
|
|
14
14
|
"test": "jest",
|
|
15
15
|
"test:watch": "jest --watch",
|
|
16
|
-
"test:coverage": "jest --coverage"
|
|
16
|
+
"test:coverage": "jest --coverage",
|
|
17
|
+
"migrate": "migrate-mongo up"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
20
|
"express": "^4.18.2",
|
|
20
21
|
"dotenv": "^16.3.1",
|
|
21
22
|
<% if (database === 'MySQL') { %> "mysql2": "^3.6.5",
|
|
23
|
+
"sequelize": "^6.35.2",
|
|
22
24
|
<% } -%>
|
|
23
25
|
<% if (database === 'PostgreSQL') { %> "pg": "^8.11.3",
|
|
24
|
-
<% } -%>
|
|
25
26
|
"sequelize": "^6.35.2",
|
|
27
|
+
<% } -%>
|
|
28
|
+
<% if (database === 'MongoDB') { %> "mongoose": "^8.0.3",
|
|
29
|
+
"migrate-mongo": "^11.0.0",
|
|
30
|
+
<% } -%>
|
|
26
31
|
<% if (communication === 'Kafka') { %> "kafkajs": "^2.2.4",
|
|
27
32
|
<% } -%>
|
|
28
33
|
<% if (viewEngine === 'EJS') { %> "ejs": "^3.1.9",
|
|
@@ -35,8 +40,7 @@
|
|
|
35
40
|
"express-rate-limit": "^7.1.5",
|
|
36
41
|
"winston": "^3.11.0"<% if (communication === 'REST APIs') { %>,
|
|
37
42
|
"swagger-ui-express": "^5.0.0",
|
|
38
|
-
"swagger-jsdoc": "^6.2.8"
|
|
39
|
-
<% } %>
|
|
43
|
+
"swagger-jsdoc": "^6.2.8"<% } %>
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
42
46
|
"nodemon": "^3.0.2"<% if (language === 'TypeScript') { %>,
|
|
@@ -4,7 +4,9 @@ const logger = require('../utils/logger');
|
|
|
4
4
|
|
|
5
5
|
const getUsers = async (req, res) => {
|
|
6
6
|
try {
|
|
7
|
-
const users = await User.
|
|
7
|
+
<% if (database === 'MongoDB') { %> const users = await User.find();
|
|
8
|
+
<% } else { %> const users = await User.findAll();
|
|
9
|
+
<% } -%>
|
|
8
10
|
res.json(users);
|
|
9
11
|
} catch (error) {
|
|
10
12
|
logger.error('Error fetching users:', error);
|
|
@@ -50,8 +50,13 @@ const syncDatabase = async () => {
|
|
|
50
50
|
let retries = 30;
|
|
51
51
|
while (retries) {
|
|
52
52
|
try {
|
|
53
|
+
<% if (database === 'MongoDB') { %>
|
|
54
|
+
const connectDB = require('./config/database');
|
|
55
|
+
await connectDB();
|
|
56
|
+
<% } else { %>
|
|
53
57
|
const sequelize = require('./config/database');
|
|
54
58
|
await sequelize.sync();
|
|
59
|
+
<% } %>
|
|
55
60
|
logger.info('Database synced');
|
|
56
61
|
|
|
57
62
|
// Start Server after DB is ready
|
|
@@ -6,7 +6,9 @@ import logger from '@/utils/logger';
|
|
|
6
6
|
export class UserController {
|
|
7
7
|
async getUsers(req: Request, res: Response) {
|
|
8
8
|
try {
|
|
9
|
-
const users = await User.
|
|
9
|
+
<% if (database === 'MongoDB') { %> const users = await User.find();
|
|
10
|
+
<% } else { %> const users = await User.findAll();
|
|
11
|
+
<% } -%>
|
|
10
12
|
res.json(users);
|
|
11
13
|
} catch (error) {
|
|
12
14
|
logger.error('Error fetching users:', error);
|
|
@@ -60,10 +60,14 @@ const syncDatabase = async () => {
|
|
|
60
60
|
let retries = 30;
|
|
61
61
|
while (retries) {
|
|
62
62
|
try {
|
|
63
|
+
<% if (database === 'MongoDB') { %>
|
|
64
|
+
const connectDB = (await import('@/config/database')).default;
|
|
65
|
+
await connectDB();
|
|
66
|
+
<% } else { %>
|
|
63
67
|
const sequelize = (await import('@/config/database')).default;
|
|
64
68
|
await sequelize.sync();
|
|
69
|
+
<% } %>
|
|
65
70
|
logger.info('Database synced');
|
|
66
|
-
|
|
67
71
|
// Start Server after DB is ready
|
|
68
72
|
app.listen(port, async () => {
|
|
69
73
|
logger.info(`Server running on port ${port}`);
|