nodejs-quickstart-structure 1.16.0 โ 1.16.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/CHANGELOG.md +10 -0
- package/README.md +14 -5
- package/package.json +1 -1
- package/templates/clean-architecture/js/src/index.js.ejs +8 -3
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +1 -1
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +3 -2
- package/templates/clean-architecture/ts/src/index.ts.ejs +4 -2
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +3 -2
- package/templates/common/health/js/healthRoute.js.ejs +5 -2
- package/templates/common/health/ts/healthRoute.ts.ejs +5 -2
- package/templates/common/kafka/js/services/kafkaService.js.ejs +4 -2
- package/templates/common/kafka/ts/services/kafkaService.ts.ejs +5 -12
- package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +8 -11
- package/templates/mvc/js/src/controllers/userController.js.ejs +3 -2
- package/templates/mvc/js/src/index.js.ejs +8 -4
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +2 -2
- package/templates/mvc/ts/src/index.ts.ejs +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.16.1] - 2026-03-17
|
|
9
|
+
|
|
10
|
+
### Refactored
|
|
11
|
+
- **Top-Level Dynamic Imports**: Moved dynamic `await import()` and `require()` calls to the top-level across all TypeScript and JavaScript templates (MVC & Clean Architecture).
|
|
12
|
+
- **Module Loading Standardization**: Standardized database connections (Mongoose/Sequelize), Kafka services, and graceful shutdown logic for better static analysis and ESM/CJS consistency.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **Kafka Service Scope**: Resolved a potential `ReferenceError` in `kafkaService.ts.ejs` by correcting the instantiation order of dynamic consumers.
|
|
16
|
+
- **Health Check Imports**: Optimized `healthRoute.ts.ejs` to use top-level database driver imports.
|
|
17
|
+
|
|
8
18
|
## [1.16.0] - 2026-03-14
|
|
9
19
|
|
|
10
20
|
### Added
|
package/README.md
CHANGED
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
A powerful CLI tool to scaffold production-ready Node.js microservices with built-in best practices, allowing you to choose between **MVC** or **Clean Architecture**, **JavaScript** or **TypeScript**, and your preferred database.
|
|
9
9
|
|
|
10
|
-
[](https://medium.com/@paudang/nodejs-quickstart-generator-93c276d60e0b)
|
|
11
|
-
|
|
12
10
|

|
|
13
11
|
|
|
14
12
|
## Features
|
|
@@ -24,6 +22,12 @@ A powerful CLI tool to scaffold production-ready Node.js microservices with buil
|
|
|
24
22
|
- **Database Migrations/Schemas**: Integrated **Flyway** for SQL migrations or **Mongoose** schemas for MongoDB.
|
|
25
23
|
- **Professional Standards**: Generated projects come with highly professional, industry-standard tooling.
|
|
26
24
|
|
|
25
|
+
## ๐ Why developers love this?
|
|
26
|
+
|
|
27
|
+
- **Community Trusted**: Over **3,000+** projects bootstrapped within the first month.
|
|
28
|
+
- **Actively Maintained**: Constant updates and optimizations (30+ versions released) based on real-world developer feedback.
|
|
29
|
+
- **Resilience First**: Unlike basic boilerplates, our generated code focuses on infrastructure stability (Retry logic, Health checks, and Graceful shutdowns).
|
|
30
|
+
|
|
27
31
|
## ๐ Professional Standards (New)
|
|
28
32
|
|
|
29
33
|
We don't just generate boilerplate; we generate **production-ready** foundations. Every project includes:
|
|
@@ -34,7 +38,7 @@ We don't just generate boilerplate; we generate **production-ready** foundations
|
|
|
34
38
|
- **๐งช Testing Excellence**: Integrated `Jest` and `Supertest`. Every generated project maintains **>70% Unit Test coverage** for controllers, services, and resolvers out of the box.
|
|
35
39
|
- **๐ CI/CD Integration**: Pre-configured workflows for **GitHub Actions**, **Jenkins**, and **GitLab CI**.
|
|
36
40
|
- **โ Git Hooks**: `Husky` and `Lint-Staged` to ensure no bad code is ever committed.
|
|
37
|
-
- **๐ค Reliability**:
|
|
41
|
+
- **๐ค Reliability**: Health Checks (`/health`) with deep database pings, Infrastructure Retry Logic (handling Docker startup delays), and Graceful Shutdown workflows.
|
|
38
42
|
- **๐ณ DevOps**: Highly optimized **Multi-Stage Dockerfile** for small, secure production images.
|
|
39
43
|
- **๐ Deployment**: Ship confidently with an integrated **PM2 Ecosystem Configuration** for zero-downtime reloads and robust process management.
|
|
40
44
|
|
|
@@ -66,14 +70,13 @@ Once installed, simply run the following command in any directory where you want
|
|
|
66
70
|
```bash
|
|
67
71
|
nodejs-quickstart init
|
|
68
72
|
```
|
|
69
|
-
or
|
|
70
73
|
|
|
71
74
|
## Quick Start (Recommended)
|
|
72
75
|
|
|
73
76
|
You can run the generator directly without installing it globally:
|
|
74
77
|
|
|
75
78
|
```bash
|
|
76
|
-
npx nodejs-quickstart-structure init
|
|
79
|
+
npx nodejs-quickstart-structure@latest init
|
|
77
80
|
```
|
|
78
81
|
|
|
79
82
|
### Configuration Options
|
|
@@ -111,6 +114,12 @@ npm install
|
|
|
111
114
|
docker-compose up
|
|
112
115
|
```
|
|
113
116
|
|
|
117
|
+
## โค๏ธ Support the Project
|
|
118
|
+
|
|
119
|
+
We just hit **3,000 downloads**! If this tool helped you save hours of setup time, please consider:
|
|
120
|
+
- Giving us a โญ on [GitHub](https://github.com/paudang/nodejs-quickstart-structure) to help others find it.
|
|
121
|
+
- Following the [Medium Article](https://medium.com/@paudang/nodejs-quickstart-generator-93c276d60e0b) for deep-dive tutorials.
|
|
122
|
+
|
|
114
123
|
## License
|
|
115
124
|
|
|
116
125
|
ISC
|
package/package.json
CHANGED
|
@@ -3,18 +3,23 @@ const logger = require('./infrastructure/log/logger');
|
|
|
3
3
|
<% if (communication === 'Kafka') { -%>
|
|
4
4
|
const { connectKafka } = require('./infrastructure/messaging/kafkaClient');
|
|
5
5
|
<% } -%>
|
|
6
|
-
|
|
7
6
|
<%_ if (database !== 'None') { -%>
|
|
8
7
|
// Database Sync
|
|
8
|
+
<%_ if (database !== 'None') { -%>
|
|
9
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
10
|
+
const connectDB = require('./infrastructure/database/database');
|
|
11
|
+
<%_ } else { -%>
|
|
12
|
+
const sequelize = require('./infrastructure/database/database');
|
|
13
|
+
<%_ } -%>
|
|
14
|
+
<%_ } -%>
|
|
15
|
+
|
|
9
16
|
const syncDatabase = async () => {
|
|
10
17
|
let retries = 30;
|
|
11
18
|
while (retries) {
|
|
12
19
|
try {
|
|
13
20
|
<%_ if (database === 'MongoDB') { -%>
|
|
14
|
-
const connectDB = require('./infrastructure/database/database');
|
|
15
21
|
await connectDB();
|
|
16
22
|
<%_ } else { -%>
|
|
17
|
-
const sequelize = require('./infrastructure/database/database');
|
|
18
23
|
await sequelize.sync();
|
|
19
24
|
<%_ } -%>
|
|
20
25
|
logger.info('Database synced');
|
|
@@ -4,6 +4,7 @@ const logger = require('../log/logger');
|
|
|
4
4
|
const morgan = require('morgan');
|
|
5
5
|
const { errorMiddleware } = require('./middleware/errorMiddleware');
|
|
6
6
|
const healthRoutes = require('../../interfaces/routes/healthRoute');
|
|
7
|
+
const setupGracefulShutdown = require('../../utils/gracefulShutdown');
|
|
7
8
|
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
8
9
|
const apiRoutes = require('../../interfaces/routes/api');
|
|
9
10
|
const swaggerUi = require('swagger-ui-express');
|
|
@@ -82,7 +83,6 @@ const startServer = async () => {
|
|
|
82
83
|
<%_ } -%>
|
|
83
84
|
});
|
|
84
85
|
|
|
85
|
-
const setupGracefulShutdown = require('../../utils/gracefulShutdown');
|
|
86
86
|
setupGracefulShutdown(server);
|
|
87
87
|
};
|
|
88
88
|
|
|
@@ -5,6 +5,9 @@ const UserRepository = require('../../infrastructure/repositories/UserRepository
|
|
|
5
5
|
const HTTP_STATUS = require('../../utils/httpCodes');
|
|
6
6
|
<% } -%>
|
|
7
7
|
const logger = require('../../infrastructure/log/logger');
|
|
8
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
9
|
+
const { sendMessage } = require('../../infrastructure/messaging/kafkaClient');
|
|
10
|
+
<%_ } -%>
|
|
8
11
|
|
|
9
12
|
class UserController {
|
|
10
13
|
constructor() {
|
|
@@ -28,7 +31,6 @@ class UserController {
|
|
|
28
31
|
try {
|
|
29
32
|
const user = await this.createUserUseCase.execute(name, email);
|
|
30
33
|
<%_ if (communication === 'Kafka') { -%>
|
|
31
|
-
const { sendMessage } = require('../../infrastructure/messaging/kafkaClient');
|
|
32
34
|
await sendMessage('user-topic', JSON.stringify({
|
|
33
35
|
action: 'USER_CREATED',
|
|
34
36
|
payload: { id: user.id || user._id, email: user.email }
|
|
@@ -56,7 +58,6 @@ class UserController {
|
|
|
56
58
|
try {
|
|
57
59
|
const user = await this.createUserUseCase.execute(name, email);
|
|
58
60
|
<%_ if (communication === 'Kafka') { -%>
|
|
59
|
-
const { sendMessage } = require('../../infrastructure/messaging/kafkaClient');
|
|
60
61
|
await sendMessage('user-topic', JSON.stringify({
|
|
61
62
|
action: 'USER_CREATED',
|
|
62
63
|
payload: { id: user.id || user._id, email: user.email }
|
|
@@ -110,15 +110,17 @@ const startServer = async () => {
|
|
|
110
110
|
|
|
111
111
|
<%_ if (database !== 'None') { -%>
|
|
112
112
|
// Database Sync
|
|
113
|
+
<%_ if (database !== 'None') { -%>
|
|
114
|
+
import <% if (database === 'MongoDB') { %>connectDB<% } else { %>sequelize<% } %> from '@/infrastructure/database/database';
|
|
115
|
+
<%_ } -%>
|
|
116
|
+
|
|
113
117
|
const syncDatabase = async () => {
|
|
114
118
|
let retries = 30;
|
|
115
119
|
while (retries) {
|
|
116
120
|
try {
|
|
117
121
|
<%_ if (database === 'MongoDB') { -%>
|
|
118
|
-
const connectDB = (await import('@/infrastructure/database/database')).default;
|
|
119
122
|
await connectDB();
|
|
120
123
|
<%_ } else { -%>
|
|
121
|
-
const sequelize = (await import('@/infrastructure/database/database')).default;
|
|
122
124
|
await sequelize.sync();
|
|
123
125
|
<%_ } -%>
|
|
124
126
|
logger.info('Database synced');
|
|
@@ -6,6 +6,9 @@ import { UserRepository } from '@/infrastructure/repositories/UserRepository';
|
|
|
6
6
|
import CreateUser from '@/usecases/createUser';
|
|
7
7
|
import GetAllUsers from '@/usecases/getAllUsers';
|
|
8
8
|
import logger from '@/infrastructure/log/logger';
|
|
9
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
10
|
+
import { kafkaService } from '@/infrastructure/messaging/kafkaClient';
|
|
11
|
+
<%_ } -%>
|
|
9
12
|
|
|
10
13
|
export class UserController {
|
|
11
14
|
private createUserUseCase: CreateUser;
|
|
@@ -23,7 +26,6 @@ export class UserController {
|
|
|
23
26
|
const { name, email } = data;
|
|
24
27
|
const user = await this.createUserUseCase.execute(name, email);
|
|
25
28
|
<%_ if (communication === 'Kafka') { -%>
|
|
26
|
-
const { kafkaService } = await import('@/infrastructure/messaging/kafkaClient');
|
|
27
29
|
await kafkaService.sendMessage('user-topic', JSON.stringify({
|
|
28
30
|
action: 'USER_CREATED',
|
|
29
31
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -54,7 +56,6 @@ export class UserController {
|
|
|
54
56
|
const { name, email } = req.body;
|
|
55
57
|
const user = await this.createUserUseCase.execute(name, email);
|
|
56
58
|
<%_ if (communication === 'Kafka') { -%>
|
|
57
|
-
const { kafkaService } = await import('@/infrastructure/messaging/kafkaClient');
|
|
58
59
|
await kafkaService.sendMessage('user-topic', JSON.stringify({
|
|
59
60
|
action: 'USER_CREATED',
|
|
60
61
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -2,6 +2,11 @@ const express = require('express');
|
|
|
2
2
|
const router = express.Router();
|
|
3
3
|
const logger = require('<% if (architecture === "MVC") { %>../utils/logger<% } else { %>../../infrastructure/log/logger<% } %>');
|
|
4
4
|
const HTTP_STATUS = require('<% if (architecture === "MVC") { %>../utils/httpCodes<% } else { %>../../utils/httpCodes<% } %>');
|
|
5
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
6
|
+
const mongoose = require('mongoose');
|
|
7
|
+
<%_ } else if (database !== 'None') { -%>
|
|
8
|
+
const sequelize = require('<% if (architecture === "MVC") { %>../config/database<% } else { %>../../infrastructure/database/database<% } %>');
|
|
9
|
+
<%_ } -%>
|
|
5
10
|
|
|
6
11
|
router.get('/', async (req, res) => {
|
|
7
12
|
const healthData = {
|
|
@@ -16,7 +21,6 @@ router.get('/', async (req, res) => {
|
|
|
16
21
|
<%_ if (database !== 'None') { -%>
|
|
17
22
|
try {
|
|
18
23
|
<%_ if (database === 'MongoDB') { -%>
|
|
19
|
-
const mongoose = require('mongoose');
|
|
20
24
|
if (mongoose.connection.readyState === 1) {
|
|
21
25
|
if (mongoose.connection.db && mongoose.connection.db.admin) {
|
|
22
26
|
await mongoose.connection.db.admin().ping();
|
|
@@ -24,7 +28,6 @@ router.get('/', async (req, res) => {
|
|
|
24
28
|
healthData.database = 'connected';
|
|
25
29
|
}
|
|
26
30
|
<%_ } else { -%>
|
|
27
|
-
const sequelize = require('<% if (architecture === "MVC") { %>../config/database<% } else { %>../../infrastructure/database/database<% } %>');
|
|
28
31
|
await sequelize.authenticate();
|
|
29
32
|
healthData.database = 'connected';
|
|
30
33
|
<%_ } -%>
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Router, Request, Response } from 'express';
|
|
2
2
|
import logger from '<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>';
|
|
3
3
|
import { HTTP_STATUS } from '@/utils/httpCodes';
|
|
4
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
5
|
+
import mongoose from 'mongoose';
|
|
6
|
+
<%_ } else if (database !== 'None') { -%>
|
|
7
|
+
import sequelize from '<% if (architecture === "MVC") { %>@/config/database<% } else { %>@/infrastructure/database/database<% } %>';
|
|
8
|
+
<%_ } -%>
|
|
4
9
|
|
|
5
10
|
const router = Router();
|
|
6
11
|
|
|
@@ -17,13 +22,11 @@ router.get('/', async (req: Request, res: Response) => {
|
|
|
17
22
|
<%_ if (database !== 'None') { -%>
|
|
18
23
|
try {
|
|
19
24
|
<%_ if (database === 'MongoDB') { -%>
|
|
20
|
-
const mongoose = (await import('mongoose')).default;
|
|
21
25
|
if (mongoose.connection.readyState === 1) {
|
|
22
26
|
await mongoose.connection.db?.admin().ping();
|
|
23
27
|
healthData.database = 'connected';
|
|
24
28
|
}
|
|
25
29
|
<%_ } else { -%>
|
|
26
|
-
const sequelize = (await import('<% if (architecture === "MVC") { %>@/config/database<% } else { %>@/infrastructure/database/database<% } %>')).default;
|
|
27
30
|
await sequelize.authenticate();
|
|
28
31
|
healthData.database = 'connected';
|
|
29
32
|
<%_ } -%>
|
|
@@ -14,6 +14,10 @@ const connectKafka = async (retries = 10) => {
|
|
|
14
14
|
if (!consumer) consumer = kafka.consumer({ groupId: 'test-group' });
|
|
15
15
|
|
|
16
16
|
let attempt = 0;
|
|
17
|
+
// Auto-register WelcomeEmailConsumer if it exists
|
|
18
|
+
// Note: Dynamic import used here for simplicity and to avoid startup crashes.
|
|
19
|
+
// In enterprise production, consider using Dependency Injection.
|
|
20
|
+
const WelcomeEmailConsumer = require('<% if (architecture === "Clean Architecture") { %>../../interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>../messaging/consumers/instances/welcomeEmailConsumer<% } %>');
|
|
17
21
|
while (attempt < retries) {
|
|
18
22
|
try {
|
|
19
23
|
await producer.connect();
|
|
@@ -22,9 +26,7 @@ const connectKafka = async (retries = 10) => {
|
|
|
22
26
|
logger.info('[Kafka] Consumer connected successfully');
|
|
23
27
|
isConnected = true;
|
|
24
28
|
|
|
25
|
-
// Auto-register WelcomeEmailConsumer if it exists
|
|
26
29
|
try {
|
|
27
|
-
const WelcomeEmailConsumer = require('<% if (architecture === "Clean Architecture") { %>../../interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>../messaging/consumers/instances/welcomeEmailConsumer<% } %>');
|
|
28
30
|
const welcomeConsumer = new WelcomeEmailConsumer();
|
|
29
31
|
await consumer.subscribe({ topic: welcomeConsumer.topic, fromBeginning: true });
|
|
30
32
|
logger.info(`[Kafka] Registered consumer for topic: ${welcomeConsumer.topic}`);
|
|
@@ -18,6 +18,10 @@ export class KafkaService {
|
|
|
18
18
|
|
|
19
19
|
this.connectionPromise = (async () => {
|
|
20
20
|
let attempt = 0;
|
|
21
|
+
// Auto-register WelcomeEmailConsumer if it exists
|
|
22
|
+
// Note: Dynamic import used here for simplicity and to avoid startup crashes.
|
|
23
|
+
// In enterprise production, consider using Dependency Injection.
|
|
24
|
+
const { WelcomeEmailConsumer } = await import('<% if (architecture === "Clean Architecture") { %>@/interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>@/messaging/consumers/instances/welcomeEmailConsumer<% } %>');
|
|
21
25
|
while (attempt < retries) {
|
|
22
26
|
try {
|
|
23
27
|
await this.producer.connect();
|
|
@@ -26,10 +30,7 @@ export class KafkaService {
|
|
|
26
30
|
logger.info('[Kafka] Consumer connected successfully');
|
|
27
31
|
this.isConnected = true;
|
|
28
32
|
|
|
29
|
-
<%_ if (language === 'TypeScript') { -%>
|
|
30
|
-
// Auto-register WelcomeEmailConsumer if it exists
|
|
31
33
|
try {
|
|
32
|
-
const { WelcomeEmailConsumer } = await import('<% if (architecture === "Clean Architecture") { %>@/interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>@/messaging/consumers/instances/welcomeEmailConsumer<% } %>');
|
|
33
34
|
const welcomeConsumer = new WelcomeEmailConsumer();
|
|
34
35
|
await this.consumer.subscribe({ topic: welcomeConsumer.topic, fromBeginning: true });
|
|
35
36
|
logger.info(`[Kafka] Registered consumer for topic: ${welcomeConsumer.topic}`);
|
|
@@ -47,15 +48,7 @@ export class KafkaService {
|
|
|
47
48
|
},
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
-
await this.consumer.subscribe({ topic: 'test-topic', fromBeginning: true });
|
|
52
|
-
await this.consumer.run({
|
|
53
|
-
eachMessage: async ({ message }: EachMessagePayload) => {
|
|
54
|
-
logger.info({ value: message.value?.toString() });
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
<%_ } _%>
|
|
58
|
-
return;
|
|
51
|
+
return; // Success
|
|
59
52
|
} catch (error) {
|
|
60
53
|
attempt++;
|
|
61
54
|
logger.error(`[Kafka] Connection attempt ${attempt} failed:`, (error as Error).message);
|
|
@@ -4,6 +4,14 @@ import logger from '@/utils/logger';
|
|
|
4
4
|
<%_ } else { -%>
|
|
5
5
|
import logger from '@/infrastructure/log/logger';
|
|
6
6
|
<%_ } -%>
|
|
7
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
8
|
+
import mongoose from 'mongoose';
|
|
9
|
+
<%_ } else if (database !== 'None') { -%>
|
|
10
|
+
import sequelize from '<% if (architecture === "MVC") { %>@/config/database<% } else { %>@/infrastructure/database/database<% } %>';
|
|
11
|
+
<%_ } -%>
|
|
12
|
+
<%_ if (caching === 'Redis') { -%>
|
|
13
|
+
import redisService from '<% if (architecture === "MVC") { %>@/config/redisClient<% } else { %>@/infrastructure/caching/redisClient<% } %>';
|
|
14
|
+
<%_ } -%>
|
|
7
15
|
|
|
8
16
|
export const setupGracefulShutdown = (server: Server<% if (communication === 'Kafka') { %>, kafkaService: { disconnect: () => Promise<void> }<% } %>) => {
|
|
9
17
|
const gracefulShutdown = async (signal: string) => {
|
|
@@ -13,25 +21,14 @@ export const setupGracefulShutdown = (server: Server<% if (communication === 'Ka
|
|
|
13
21
|
try {
|
|
14
22
|
<%_ if (database !== 'None') { -%>
|
|
15
23
|
<%_ if (database === 'MongoDB') { -%>
|
|
16
|
-
const mongoose = (await import('mongoose')).default;
|
|
17
24
|
await mongoose.connection.close(false);
|
|
18
25
|
logger.info('MongoDB connection closed.');
|
|
19
26
|
<%_ } else { -%>
|
|
20
|
-
<%_ if (architecture === 'MVC') { -%>
|
|
21
|
-
const sequelize = (await import('@/config/database')).default;
|
|
22
|
-
<%_ } else { -%>
|
|
23
|
-
const sequelize = (await import('@/infrastructure/database/database')).default;
|
|
24
|
-
<%_ } -%>
|
|
25
27
|
await sequelize.close();
|
|
26
28
|
logger.info('Database connection closed.');
|
|
27
29
|
<%_ } -%>
|
|
28
30
|
<%_ } -%>
|
|
29
31
|
<%_ if (caching === 'Redis') { -%>
|
|
30
|
-
<%_ if (architecture === 'MVC') { -%>
|
|
31
|
-
const redisService = (await import('@/config/redisClient')).default;
|
|
32
|
-
<%_ } else { -%>
|
|
33
|
-
const redisService = (await import('@/infrastructure/caching/redisClient')).default;
|
|
34
|
-
<%_ } -%>
|
|
35
32
|
await redisService.quit();
|
|
36
33
|
logger.info('Redis connection closed.');
|
|
37
34
|
<%_ } -%>
|
|
@@ -8,6 +8,9 @@ const cacheService = require('../config/redisClient');
|
|
|
8
8
|
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
9
9
|
const cacheService = require('../config/memoryCache');
|
|
10
10
|
<%_ } -%>
|
|
11
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
12
|
+
const { sendMessage } = require('../services/kafkaService');
|
|
13
|
+
<%_ } -%>
|
|
11
14
|
|
|
12
15
|
<% if (communication === 'GraphQL') { -%>
|
|
13
16
|
const getUsers = async () => {
|
|
@@ -42,7 +45,6 @@ const createUser = async (data) => {
|
|
|
42
45
|
await cacheService.del('users:all');
|
|
43
46
|
<%_ } -%>
|
|
44
47
|
<%_ if (communication === 'Kafka') { -%>
|
|
45
|
-
const { sendMessage } = require('../services/kafkaService');
|
|
46
48
|
await sendMessage('user-topic', JSON.stringify({
|
|
47
49
|
action: 'USER_CREATED',
|
|
48
50
|
payload: { id: user.id || user._id, email: user.email }
|
|
@@ -87,7 +89,6 @@ const createUser = async (req, res, next) => {
|
|
|
87
89
|
await cacheService.del('users:all');
|
|
88
90
|
<%_ } -%>
|
|
89
91
|
<%_ if (communication === 'Kafka') { -%>
|
|
90
|
-
const { sendMessage } = require('../services/kafkaService');
|
|
91
92
|
await sendMessage('user-topic', JSON.stringify({
|
|
92
93
|
action: 'USER_CREATED',
|
|
93
94
|
payload: { id: user.id || user._id, email: user.email }
|
|
@@ -17,6 +17,7 @@ const swaggerUi = require('swagger-ui-express');
|
|
|
17
17
|
const swaggerSpecs = require('./config/swagger');
|
|
18
18
|
<%_ } -%>
|
|
19
19
|
const { env } = require('./config/env');
|
|
20
|
+
const setupGracefulShutdown = require('./utils/gracefulShutdown');
|
|
20
21
|
|
|
21
22
|
const app = express();
|
|
22
23
|
const PORT = env.PORT;
|
|
@@ -96,25 +97,28 @@ const startServer = async () => {
|
|
|
96
97
|
<%_ } -%>
|
|
97
98
|
});
|
|
98
99
|
|
|
99
|
-
const setupGracefulShutdown = require('./utils/gracefulShutdown');
|
|
100
100
|
setupGracefulShutdown(server);
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
<%_ if (database !== 'None') { -%>
|
|
104
104
|
// Database Sync
|
|
105
|
+
<%_ if (database !== 'None') { -%>
|
|
106
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
107
|
+
const connectDB = require('./config/database');
|
|
108
|
+
<%_ } else { -%>
|
|
109
|
+
const sequelize = require('./config/database');
|
|
110
|
+
<%_ } -%>
|
|
111
|
+
<%_ } -%>
|
|
105
112
|
const syncDatabase = async () => {
|
|
106
113
|
let retries = 30;
|
|
107
114
|
while (retries) {
|
|
108
115
|
try {
|
|
109
116
|
<%_ if (database === 'MongoDB') { -%>
|
|
110
|
-
const connectDB = require('./config/database');
|
|
111
117
|
await connectDB();
|
|
112
118
|
<%_ } else { -%>
|
|
113
|
-
const sequelize = require('./config/database');
|
|
114
119
|
await sequelize.sync();
|
|
115
120
|
<%_ } -%>
|
|
116
121
|
logger.info('Database synced');
|
|
117
|
-
|
|
118
122
|
// Start Server after DB is ready
|
|
119
123
|
await startServer();
|
|
120
124
|
break;
|
|
@@ -8,6 +8,8 @@ import logger from '@/utils/logger';
|
|
|
8
8
|
import cacheService from '@/config/redisClient';
|
|
9
9
|
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
10
10
|
import cacheService from '@/config/memoryCache';
|
|
11
|
+
<%_ } -%><%_ if (communication === 'Kafka') { -%>
|
|
12
|
+
import { kafkaService } from '@/services/kafkaService';
|
|
11
13
|
<%_ } -%>
|
|
12
14
|
|
|
13
15
|
export class UserController {
|
|
@@ -44,7 +46,6 @@ export class UserController {
|
|
|
44
46
|
await cacheService.del('users:all');
|
|
45
47
|
<%_ } -%>
|
|
46
48
|
<%_ if (communication === 'Kafka') { -%>
|
|
47
|
-
const { kafkaService } = await import('@/services/kafkaService');
|
|
48
49
|
await kafkaService.sendMessage('user-topic', JSON.stringify({
|
|
49
50
|
action: 'USER_CREATED',
|
|
50
51
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -90,7 +91,6 @@ export class UserController {
|
|
|
90
91
|
await cacheService.del('users:all');
|
|
91
92
|
<%_ } -%>
|
|
92
93
|
<%_ if (communication === 'Kafka') { -%>
|
|
93
|
-
const { kafkaService } = await import('@/services/kafkaService');
|
|
94
94
|
await kafkaService.sendMessage('user-topic', JSON.stringify({
|
|
95
95
|
action: 'USER_CREATED',
|
|
96
96
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -123,15 +123,16 @@ const startServer = async () => {
|
|
|
123
123
|
|
|
124
124
|
<%_ if (database !== 'None') { -%>
|
|
125
125
|
// Database Sync
|
|
126
|
+
<%_ if (database !== 'None') { -%>
|
|
127
|
+
import <% if (database === 'MongoDB') { %>connectDB<% } else { %>sequelize<% } %> from '@/config/database';
|
|
128
|
+
<%_ } -%>
|
|
126
129
|
const syncDatabase = async () => {
|
|
127
130
|
let retries = 30;
|
|
128
131
|
while (retries) {
|
|
129
132
|
try {
|
|
130
133
|
<%_ if (database === 'MongoDB') { -%>
|
|
131
|
-
const connectDB = (await import('@/config/database')).default;
|
|
132
134
|
await connectDB();
|
|
133
135
|
<%_ } else { -%>
|
|
134
|
-
const sequelize = (await import('@/config/database')).default;
|
|
135
136
|
await sequelize.sync();
|
|
136
137
|
<%_ } -%>
|
|
137
138
|
logger.info('Database synced');
|