@ifecodes/backend-template 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +288 -0
  2. package/bin/cli.js +249 -0
  3. package/bin/lib/microservice-config.js +89 -0
  4. package/bin/lib/prompts.js +159 -0
  5. package/bin/lib/readme-generator.js +245 -0
  6. package/bin/lib/service-setup.js +316 -0
  7. package/package.json +52 -0
  8. package/template/base/.env.example +5 -0
  9. package/template/base/.eslintrc.json +17 -0
  10. package/template/base/.husky/pre-commit +13 -0
  11. package/template/base/.prettierignore +47 -0
  12. package/template/base/.prettierrc +7 -0
  13. package/template/base/eslint.config.js +33 -0
  14. package/template/base/package.json +32 -0
  15. package/template/base/src/app.ts +9 -0
  16. package/template/base/src/config/db.ts +4 -0
  17. package/template/base/src/config/env.ts +9 -0
  18. package/template/base/src/config/index.ts +2 -0
  19. package/template/base/src/middlewares/index.ts +3 -0
  20. package/template/base/src/middlewares/method-not-allowed.middleware.ts +17 -0
  21. package/template/base/src/middlewares/not-found.middleware.ts +8 -0
  22. package/template/base/src/middlewares/root.middleware.ts +14 -0
  23. package/template/base/src/modules/index.ts +8 -0
  24. package/template/base/src/modules/v1/health/health.controller.ts +18 -0
  25. package/template/base/src/modules/v1/health/health.route.ts +9 -0
  26. package/template/base/src/modules/v1/health/index.ts +1 -0
  27. package/template/base/src/modules/v1/index.ts +8 -0
  28. package/template/base/src/routes.ts +15 -0
  29. package/template/base/src/server.ts +11 -0
  30. package/template/base/src/utils/http-error.ts +47 -0
  31. package/template/base/src/utils/index.ts +11 -0
  32. package/template/base/src/utils/logger.ts +34 -0
  33. package/template/base/tsconfig.json +22 -0
  34. package/template/features/auth/argon2/inject.js +25 -0
  35. package/template/features/auth/base/inject.js +89 -0
  36. package/template/features/auth/bcrypt/inject.js +18 -0
  37. package/template/features/auth/models/index.ts +1 -0
  38. package/template/features/auth/models/user.model.ts +28 -0
  39. package/template/features/auth/modules/auth.controller.ts +20 -0
  40. package/template/features/auth/modules/auth.routes.ts +11 -0
  41. package/template/features/auth/modules/auth.service.ts +38 -0
  42. package/template/features/auth/modules/index.ts +1 -0
  43. package/template/features/auth/utils/hash.ts +20 -0
  44. package/template/features/auth/utils/jwt.ts +15 -0
  45. package/template/features/cors/inject.js +9 -0
  46. package/template/features/helmet/inject.js +3 -0
  47. package/template/features/morgan/inject.js +3 -0
  48. package/template/features/rate-limit/inject.js +3 -0
  49. package/template/gateway/app.ts +26 -0
  50. package/template/gateway/inject.js +27 -0
  51. package/template/gateway/server.ts +19 -0
  52. package/template/microservice/docker/Dockerfile +5 -0
  53. package/template/microservice/docker/docker-compose.yml +6 -0
  54. package/template/microservice/nodocker/pm2.config.js +3 -0
package/README.md ADDED
@@ -0,0 +1,288 @@
1
+ # šŸš€ Backend Template Generator
2
+
3
+ A powerful CLI tool to generate production-ready Node.js + TypeScript backend applications with Express.js. Supports both monolith and microservice architectures with optional features like authentication, CORS, rate limiting, and more.
4
+
5
+ ---
6
+
7
+ ## šŸ“¦ Installation & Usage
8
+
9
+ ### Quick Start
10
+
11
+ ```bash
12
+ npx @ifecodes/backend-template my-project
13
+ ```
14
+
15
+ Or install globally:
16
+
17
+ ```bash
18
+ npm install -g @ifecodes/backend-template
19
+ ifecodes-template my-project
20
+ ```
21
+
22
+ ### With Arguments
23
+
24
+ ```bash
25
+ # Create a monolith
26
+ npx @ifecodes/backend-template my-api mono
27
+
28
+ # Create a microservice
29
+ npx @ifecodes/backend-template my-project micro
30
+ ```
31
+
32
+ ---
33
+
34
+ ## 🧠 Interactive Setup
35
+
36
+ When you run the CLI, you'll be prompted to choose:
37
+
38
+ ### 1. **Project Type**
39
+ - **Monolith API** - Traditional single-server architecture
40
+ - **Microservice** - Distributed services with API Gateway
41
+
42
+ ### 2. **Deployment Mode** (Microservices only)
43
+ - **Docker** - Container-based deployment with docker-compose
44
+ - **PM2** - Process manager for Node.js applications
45
+
46
+ ### 3. **Optional Features**
47
+ - āœ… **CORS** - Cross-Origin Resource Sharing
48
+ - āœ… **Helmet** - Security headers middleware
49
+ - āœ… **Rate Limiting** - API request throttling
50
+ - āœ… **Morgan** - HTTP request logger
51
+
52
+ ### 4. **Authentication**
53
+ - āœ… **JWT Authentication** with MongoDB
54
+ - Choose between **bcrypt** (recommended for Windows) or **argon2** for password hashing
55
+
56
+ ---
57
+
58
+ ## šŸ—‚ Project Structure
59
+
60
+ ### Monolith
61
+
62
+ ```
63
+ my-backend/
64
+ ā”œā”€ā”€ src/
65
+ │ ā”œā”€ā”€ config/ # Configuration files
66
+ │ ā”œā”€ā”€ middlewares/ # Custom middlewares
67
+ │ ā”œā”€ā”€ modules/ # Feature modules
68
+ │ │ └── v1/ # API version 1
69
+ │ │ ā”œā”€ā”€ auth/ # Auth module (if enabled)
70
+ │ │ └── health/ # Health check
71
+ │ ā”œā”€ā”€ models/ # Database models (if auth)
72
+ │ ā”œā”€ā”€ utils/ # Utility functions
73
+ │ ā”œā”€ā”€ app.ts # Express app setup
74
+ │ ā”œā”€ā”€ routes.ts # Route definitions
75
+ │ └── server.ts # Server entry point
76
+ ā”œā”€ā”€ .husky/ # Git hooks
77
+ ā”œā”€ā”€ .env # Environment variables
78
+ ā”œā”€ā”€ package.json
79
+ └── tsconfig.json
80
+ ```
81
+
82
+ ### Microservice
83
+
84
+ ```
85
+ my-project/
86
+ ā”œā”€ā”€ shared/ # Shared utilities across services
87
+ │ ā”œā”€ā”€ config/ # Database, environment configs
88
+ │ └── utils/ # Logger, error handlers
89
+ ā”œā”€ā”€ services/
90
+ │ ā”œā”€ā”€ gateway/ # API Gateway (port 4000)
91
+ │ ā”œā”€ā”€ health-service/ # Health checks (port 4001)
92
+ │ └── auth-service/ # Authentication (port 4002)
93
+ ā”œā”€ā”€ docker-compose.yml # Docker setup (if selected)
94
+ ā”œā”€ā”€ pm2.config.js # PM2 setup (if selected)
95
+ ā”œā”€ā”€ .husky/ # Git hooks
96
+ └── package.json # Root package.json
97
+ ```
98
+
99
+ ---
100
+
101
+ ## ā–¶ļø Running the Application
102
+
103
+ ### Monolith
104
+
105
+ ```bash
106
+ cd my-backend
107
+
108
+ # Development
109
+ npm run dev
110
+
111
+ # Production
112
+ npm run build
113
+ npm start
114
+ ```
115
+
116
+ ### Microservice (Docker)
117
+
118
+ ```bash
119
+ cd my-project
120
+
121
+ # Start all services
122
+ docker-compose up
123
+
124
+ # Start in detached mode
125
+ docker-compose up -d
126
+
127
+ # View logs
128
+ docker-compose logs -f
129
+
130
+ # Stop all services
131
+ docker-compose down
132
+ ```
133
+
134
+ ### Microservice (PM2)
135
+
136
+ ```bash
137
+ cd my-project
138
+
139
+ # Start all services
140
+ pm2 start pm2.config.js
141
+
142
+ # View logs
143
+ pm2 logs
144
+
145
+ # Monitor services
146
+ pm2 monit
147
+
148
+ # Stop all services
149
+ pm2 stop all
150
+ ```
151
+
152
+ ---
153
+
154
+ ## šŸ›  Tech Stack
155
+
156
+ - **Runtime**: Node.js (v18+)
157
+ - **Language**: TypeScript
158
+ - **Framework**: Express.js
159
+ - **Database**: MongoDB (with Mongoose, if auth enabled)
160
+ - **Authentication**: JWT + bcrypt/argon2
161
+ - **Security**: Helmet, CORS, Rate Limiting
162
+ - **Logging**: Morgan, Custom Logger
163
+ - **Git Hooks**: Husky
164
+ - **Deployment**: Docker or PM2
165
+
166
+ ---
167
+
168
+ ## 🌟 Features
169
+
170
+ ### āœ… Smart Defaults
171
+ - Auto-generates README with project-specific instructions
172
+ - Creates `.env` from `.env.example` with default values
173
+ - Configures TypeScript paths for clean imports (`@/config`, `@/utils`)
174
+
175
+ ### āœ… Microservice Architecture
176
+ - **API Gateway** on port 4000 (single entry point)
177
+ - **Service Discovery** - Automatically routes to correct service
178
+ - **Shared Folder** - Common utilities across all services
179
+ - **Health Checks** - Built-in monitoring endpoints
180
+
181
+ ### āœ… Developer Experience
182
+ - **Hot Reload** - Development server with nodemon
183
+ - **ESLint** - Code quality enforcement
184
+ - **Git Hooks** - Pre-commit linting with Husky
185
+ - **Type Safety** - Full TypeScript support
186
+
187
+ ---
188
+
189
+ ## šŸ“” API Endpoints
190
+
191
+ ### Monolith
192
+
193
+ ```
194
+ GET / - API information
195
+ GET /v1/health - Health check
196
+ POST /v1/auth/register - Register user (if auth enabled)
197
+ POST /v1/auth/login - Login user (if auth enabled)
198
+ ```
199
+
200
+ ### Microservice
201
+
202
+ All requests go through the API Gateway at `http://localhost:4000`
203
+
204
+ ```
205
+ GET /health - Health service
206
+ POST /auth/register - Auth service (if enabled)
207
+ POST /auth/login - Auth service (if enabled)
208
+ ```
209
+
210
+ ---
211
+
212
+ ## šŸ”§ Environment Variables
213
+
214
+ ### Basic Setup
215
+
216
+ ```env
217
+ PORT=4000
218
+ NODE_ENV=development
219
+ ```
220
+
221
+ ### With CORS
222
+
223
+ ```env
224
+ ALLOWED_ORIGIN=http://localhost:3000
225
+ ```
226
+
227
+ ### With Authentication
228
+
229
+ ```env
230
+ MONGO_URI=mongodb://localhost:27017/your-database-name
231
+ JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
232
+ ```
233
+
234
+ ---
235
+
236
+ ## šŸš€ Adding Services (Microservice)
237
+
238
+ You can add more services to an existing microservice project:
239
+
240
+ ```bash
241
+ cd my-project
242
+ npx @ifecodes/backend-template
243
+
244
+ # You'll be prompted to name the new service
245
+ # Example: user-service, order-service, etc.
246
+ ```
247
+
248
+ The CLI will:
249
+ - Create the new service
250
+ - Update `docker-compose.yml` or `pm2.config.js`
251
+ - Configure routing in the API Gateway
252
+
253
+ ---
254
+
255
+ ## šŸ¤ Contributing
256
+
257
+ Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for details.
258
+
259
+ ### Development
260
+
261
+ ```bash
262
+ git clone https://github.com/ALADETAN-IFE/backend-template.git
263
+ cd backend-template
264
+ npm install
265
+ npm link
266
+ ```
267
+
268
+ ---
269
+
270
+ ## šŸ“„ License
271
+
272
+ MIT
273
+
274
+ ---
275
+
276
+ ## ✨ Author
277
+
278
+ **Aladetan Fortune Ifeloju (IfeCodes)**
279
+ Full Stack Developer & TechPreneur
280
+
281
+ - GitHub: [@ALADETAN-IFE](https://github.com/ALADETAN-IFE)
282
+ - Twitter: [@IfeCodes](https://twitter.com/IfeCodes_)
283
+
284
+ ---
285
+
286
+ ## šŸ™ Acknowledgments
287
+
288
+ Built with ā¤ļø for the developer community to accelerate backend development.
package/bin/cli.js ADDED
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env node
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { execSync } from "child_process";
5
+ import { fileURLToPath } from "url";
6
+ import { getProjectConfig } from "./lib/prompts.js";
7
+ import { setupService } from "./lib/service-setup.js";
8
+ import { generateReadme } from "./lib/readme-generator.js";
9
+ import {
10
+ generateDockerCompose,
11
+ generatePm2Config,
12
+ copyDockerfile,
13
+ } from "./lib/microservice-config.js";
14
+
15
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
+
17
+ // Get project configuration from user
18
+ const config = await getProjectConfig();
19
+ const {
20
+ sanitizedName,
21
+ target,
22
+ isExistingProject,
23
+ mode,
24
+ isInMicroserviceProject,
25
+ } = config;
26
+
27
+ const base = path.join(__dirname, "../template/base");
28
+
29
+ // Determine which services to create
30
+ const servicesToCreate = [];
31
+ if (isInMicroserviceProject) {
32
+ const newServiceName = config.serviceName.replace(/\s+/g, "-");
33
+ servicesToCreate.push(newServiceName);
34
+ } else if (config.projectType === "microservice") {
35
+ servicesToCreate.push("gateway");
36
+ servicesToCreate.push("health-service");
37
+ if (config.auth) {
38
+ servicesToCreate.push("auth-service");
39
+ }
40
+ }
41
+
42
+ // Validate and prepare project
43
+ if (!isInMicroserviceProject && config.projectType === "microservice") {
44
+ if (isExistingProject) {
45
+ console.error(`\nāŒ Error: Project '${sanitizedName}' already exists!`);
46
+ process.exit(1);
47
+ }
48
+ console.log(
49
+ `\nšŸ—ļø Creating microservices: ${servicesToCreate.join(", ")}...\n`
50
+ );
51
+ } else if (!isInMicroserviceProject && config.projectType === "monolith") {
52
+ if (isExistingProject) {
53
+ console.error(`\nāŒ Error: Project '${sanitizedName}' already exists!`);
54
+ process.exit(1);
55
+ }
56
+ fs.cpSync(base, target, { recursive: true });
57
+ } else if (isInMicroserviceProject) {
58
+ console.log(`\nšŸ—ļø Adding service: ${servicesToCreate[0]}...\n`);
59
+ }
60
+
61
+ // Process services
62
+ if (isInMicroserviceProject || config.projectType === "microservice") {
63
+ // Create shared folder for config and utils (only once)
64
+ if (!isInMicroserviceProject) {
65
+ const sharedDir = path.join(target, "shared");
66
+ if (!fs.existsSync(sharedDir)) {
67
+ console.log(`\nšŸ“¦ Creating shared folder for config and utils...`);
68
+ fs.mkdirSync(sharedDir, { recursive: true });
69
+
70
+ // Copy config and utils from base template
71
+ const baseConfigDir = path.join(base, "src", "config");
72
+ const baseUtilsDir = path.join(base, "src", "utils");
73
+ const sharedConfigDir = path.join(sharedDir, "config");
74
+ const sharedUtilsDir = path.join(sharedDir, "utils");
75
+
76
+ fs.cpSync(baseConfigDir, sharedConfigDir, { recursive: true });
77
+ fs.cpSync(baseUtilsDir, sharedUtilsDir, { recursive: true });
78
+
79
+ // Create shared package.json
80
+ const sharedPackageJson = {
81
+ name: "@shared/common",
82
+ version: "1.0.0",
83
+ type: "module",
84
+ exports: {
85
+ "./config/*": "./config/*",
86
+ "./utils/*": "./utils/*",
87
+ },
88
+ };
89
+ fs.writeFileSync(
90
+ path.join(sharedDir, "package.json"),
91
+ JSON.stringify(sharedPackageJson, null, 2)
92
+ );
93
+ }
94
+ }
95
+
96
+ for (const serviceName of servicesToCreate) {
97
+ const serviceRoot = path.join(target, "services", serviceName);
98
+
99
+ if (fs.existsSync(serviceRoot)) {
100
+ console.error(`\nāŒ Error: Service '${serviceName}' already exists!`);
101
+ process.exit(1);
102
+ }
103
+
104
+ console.log(`\nšŸ”Ø Setting up ${serviceName}...`);
105
+ fs.cpSync(base, serviceRoot, { recursive: true });
106
+
107
+ // Remove config and utils from service (they'll use shared) - except gateway handles it differently
108
+ if (serviceName !== "gateway") {
109
+ const serviceConfigDir = path.join(serviceRoot, "src", "config");
110
+ const serviceUtilsDir = path.join(serviceRoot, "src", "utils");
111
+ if (fs.existsSync(serviceConfigDir))
112
+ fs.rmSync(serviceConfigDir, { recursive: true });
113
+ if (fs.existsSync(serviceUtilsDir))
114
+ fs.rmSync(serviceUtilsDir, { recursive: true });
115
+ }
116
+ }
117
+
118
+ // Get all services first (needed for gateway routing)
119
+ const servicesDir = path.join(target, "services");
120
+ const allServices = fs.existsSync(servicesDir)
121
+ ? fs
122
+ .readdirSync(servicesDir)
123
+ .filter((f) => fs.statSync(path.join(servicesDir, f)).isDirectory())
124
+ : servicesToCreate;
125
+
126
+ // Now setup each service with knowledge of all services
127
+ for (const serviceName of servicesToCreate) {
128
+ const serviceRoot = path.join(target, "services", serviceName);
129
+ const shouldIncludeAuth = isInMicroserviceProject
130
+ ? config.auth
131
+ : serviceName === "auth-service";
132
+ await setupService(
133
+ config,
134
+ serviceName,
135
+ serviceRoot,
136
+ shouldIncludeAuth,
137
+ allServices
138
+ );
139
+ }
140
+
141
+ if (mode === "docker") {
142
+ generateDockerCompose(target, allServices);
143
+ copyDockerfile(target, servicesToCreate);
144
+ } else {
145
+ generatePm2Config(target, allServices);
146
+ }
147
+
148
+ // Create root package.json for microservice monorepo if it doesn't exist
149
+ const rootPackageJsonPath = path.join(target, "package.json");
150
+ if (!fs.existsSync(rootPackageJsonPath)) {
151
+ const rootPackageJson = {
152
+ name: sanitizedName,
153
+ version: "1.0.0",
154
+ private: true,
155
+ scripts: {
156
+ prepare: "husky install",
157
+ },
158
+ devDependencies: {
159
+ husky: "^8.0.3",
160
+ },
161
+ };
162
+ fs.writeFileSync(
163
+ rootPackageJsonPath,
164
+ JSON.stringify(rootPackageJson, null, 2) + "\n"
165
+ );
166
+ }
167
+ } else {
168
+ await setupService(config, null, target, true);
169
+ }
170
+
171
+ // Generate README.md
172
+ if (!isInMicroserviceProject) {
173
+ console.log("\nšŸ“ Generating README.md...\n");
174
+ const readmeContent = generateReadme(config);
175
+ fs.writeFileSync(path.join(target, "README.md"), readmeContent);
176
+
177
+ // Generate .env from .env.example for each service or root
178
+ console.log("šŸ“„ Setting up environment files...\n");
179
+ if (config.projectType === "microservice") {
180
+ const servicesDir = path.join(target, "services");
181
+ const allServices = fs.readdirSync(servicesDir).filter((f) =>
182
+ fs.statSync(path.join(servicesDir, f)).isDirectory()
183
+ );
184
+
185
+ for (const service of allServices) {
186
+ const envExamplePath = path.join(servicesDir, service, ".env.example");
187
+ const envPath = path.join(servicesDir, service, ".env");
188
+ if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
189
+ fs.copyFileSync(envExamplePath, envPath);
190
+ }
191
+ }
192
+ } else {
193
+ const envExamplePath = path.join(target, ".env.example");
194
+ const envPath = path.join(target, ".env");
195
+ if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
196
+ fs.copyFileSync(envExamplePath, envPath);
197
+ }
198
+ }
199
+ }
200
+
201
+ // Initialize git and Husky
202
+ if (!isInMicroserviceProject) {
203
+ execSync("git init", { cwd: target, stdio: "inherit" });
204
+
205
+ // Install husky and setup at root level
206
+ if (config.projectType === "microservice") {
207
+ console.log("\nšŸ“¦ Installing Husky at root level...\n");
208
+ execSync("npm install", { cwd: target, stdio: "inherit" });
209
+ console.log("\nšŸ”§ Setting up Husky...\n");
210
+ execSync("npm run prepare", { cwd: target, stdio: "inherit" });
211
+ } else if (config.projectType === "monolith") {
212
+ console.log("\nšŸ”§ Setting up Husky...\n");
213
+ execSync("npm run prepare", { cwd: target, stdio: "inherit" });
214
+ }
215
+ }
216
+
217
+ // Success messages
218
+ const servicesDir = path.join(target, "services");
219
+ const allServices = fs.existsSync(servicesDir)
220
+ ? fs
221
+ .readdirSync(servicesDir)
222
+ .filter((f) => fs.statSync(path.join(servicesDir, f)).isDirectory())
223
+ : servicesToCreate;
224
+
225
+ if (isInMicroserviceProject) {
226
+ console.log(`\nāœ… Service '${servicesToCreate[0]}' added successfully!`);
227
+ console.log(`\nšŸ“¦ All services: ${allServices.join(", ")}`);
228
+ console.log(`\nšŸ’” Next steps:`);
229
+ console.log(
230
+ mode === "docker"
231
+ ? ` 1. Start services: docker-compose up`
232
+ : ` 1. Start services: pm2 start pm2.config.js`
233
+ );
234
+ } else if (config.projectType === "microservice") {
235
+ console.log("\nāœ… Backend created successfully!");
236
+ console.log(`\nšŸ“¦ Created services: ${servicesToCreate.join(", ")}`);
237
+ console.log(`\nšŸ’” Next steps:`);
238
+ console.log(` 1. cd ${sanitizedName}`);
239
+ console.log(
240
+ mode === "docker"
241
+ ? ` 2. Start services: docker-compose up`
242
+ : ` 2. Start services: pm2 start pm2.config.js`
243
+ );
244
+ } else {
245
+ console.log("\nāœ… Backend created successfully!");
246
+ console.log(`\nšŸ’” Next steps:`);
247
+ console.log(` 1. cd ${sanitizedName}`);
248
+ console.log(` 2. npm run dev`);
249
+ }
@@ -0,0 +1,89 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+
7
+ export const generateDockerCompose = (target, allServices) => {
8
+ const dockerCompose = {
9
+ version: "3.8",
10
+ services: {},
11
+ };
12
+
13
+ for (const serviceName of allServices) {
14
+ // Gateway runs on 4000, other services start from 4001
15
+ const isGateway = serviceName === "gateway";
16
+ const serviceIndex = allServices.indexOf(serviceName);
17
+ const port = isGateway ? 4000 : 4001 + allServices.filter((s, i) => s !== "gateway" && i < serviceIndex).length;
18
+
19
+ dockerCompose.services[serviceName] = {
20
+ build: `./services/${serviceName}`,
21
+ ports: [
22
+ `\${${serviceName
23
+ .toUpperCase()
24
+ .replace(/-/g, "_")}_PORT:-${port}}:${isGateway ? 4000 : 4000}`,
25
+ ],
26
+ environment: [`NODE_ENV=\${NODE_ENV:-development}`],
27
+ volumes: [`./services/${serviceName}:/app`, `/app/node_modules`],
28
+ };
29
+ }
30
+
31
+ fs.writeFileSync(
32
+ path.join(target, "docker-compose.yml"),
33
+ `version: "${dockerCompose.version}"\nservices:\n` +
34
+ Object.entries(dockerCompose.services)
35
+ .map(
36
+ ([name, config]) =>
37
+ ` ${name}:\n` +
38
+ ` build: ${config.build}\n` +
39
+ ` ports:\n - "${config.ports[0]}"\n` +
40
+ ` environment:\n - ${config.environment[0]}\n` +
41
+ ` volumes:\n` +
42
+ config.volumes.map((v) => ` - ${v}`).join("\n")
43
+ )
44
+ .join("\n")
45
+ );
46
+ };
47
+
48
+ export const generatePm2Config = (target, allServices) => {
49
+ const pm2Config = {
50
+ apps: allServices.map((serviceName, index) => {
51
+ const isGateway = serviceName === "gateway";
52
+ const port = isGateway ? 4000 : 4001 + allServices.filter((s, i) => s !== "gateway" && i < index).length;
53
+
54
+ return {
55
+ name: serviceName,
56
+ script: `./services/${serviceName}/src/server.ts`,
57
+ instances: 1,
58
+ exec_mode: "fork",
59
+ env: {
60
+ PORT: port
61
+ }
62
+ };
63
+ }),
64
+ };
65
+
66
+ fs.writeFileSync(
67
+ path.join(target, "pm2.config.js"),
68
+ `module.exports = ${JSON.stringify(pm2Config, null, 2)};\n`
69
+ );
70
+ };
71
+
72
+ export const copyDockerfile = (target, servicesToCreate) => {
73
+ const dockerfilePath = path.join(
74
+ __dirname,
75
+ "../../template/microservice/docker/Dockerfile"
76
+ );
77
+
78
+ for (const serviceName of servicesToCreate) {
79
+ const serviceDockerfile = path.join(
80
+ target,
81
+ "services",
82
+ serviceName,
83
+ "Dockerfile"
84
+ );
85
+ if (!fs.existsSync(serviceDockerfile)) {
86
+ fs.copyFileSync(dockerfilePath, serviceDockerfile);
87
+ }
88
+ }
89
+ };