nodejs-quickstart-structure 1.4.3 → 1.6.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 +59 -0
- package/README.md +14 -18
- package/docs/generateCase.md +23 -7
- package/docs/generatorFlow.md +5 -1
- package/docs/releaseNoteRule.md +42 -0
- package/lib/generator.js +41 -316
- package/lib/modules/app-setup.js +91 -0
- package/lib/modules/config-files.js +88 -0
- package/lib/modules/database-setup.js +99 -0
- package/lib/modules/kafka-setup.js +112 -0
- package/lib/modules/project-setup.js +31 -0
- package/lib/prompts.js +3 -3
- package/package.json +4 -3
- package/templates/clean-architecture/js/src/index.js.ejs +19 -6
- package/templates/clean-architecture/js/src/infrastructure/log/logger.js +16 -2
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +18 -6
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +2 -0
- package/templates/clean-architecture/ts/src/index.ts.ejs +27 -19
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +16 -2
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +17 -6
- package/templates/common/Dockerfile +3 -0
- package/templates/common/docker-compose.yml.ejs +47 -24
- package/templates/common/package.json.ejs +9 -2
- package/templates/mvc/js/src/controllers/userController.js.ejs +13 -3
- package/templates/mvc/js/src/index.js.ejs +26 -17
- package/templates/mvc/js/src/utils/logger.js +16 -6
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +13 -3
- package/templates/mvc/ts/src/index.ts.ejs +27 -18
- package/templates/mvc/ts/src/utils/logger.ts +16 -2
- package/templates/mvc/js/src/config/database.js +0 -12
|
@@ -5,6 +5,7 @@ import hpp from 'hpp';
|
|
|
5
5
|
import rateLimit from 'express-rate-limit';
|
|
6
6
|
import dotenv from 'dotenv';
|
|
7
7
|
import logger from '@/infrastructure/log/logger';
|
|
8
|
+
import morgan from 'morgan';
|
|
8
9
|
<% if (communication === 'REST APIs') { %>import userRoutes from '@/interfaces/routes/userRoutes';<% } -%>
|
|
9
10
|
<% if (communication === 'REST APIs') { -%>
|
|
10
11
|
import swaggerUi from 'swagger-ui-express';
|
|
@@ -24,6 +25,7 @@ const limiter = rateLimit({ windowMs: 10 * 60 * 1000, max: 100 });
|
|
|
24
25
|
app.use(limiter);
|
|
25
26
|
|
|
26
27
|
app.use(express.json());
|
|
28
|
+
app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
|
|
27
29
|
|
|
28
30
|
<% if (communication === 'REST APIs') { -%>
|
|
29
31
|
app.use('/api/users', userRoutes);
|
|
@@ -37,34 +39,37 @@ app.get('/health', (req: Request, res: Response) => {
|
|
|
37
39
|
res.json({ status: 'UP' });
|
|
38
40
|
});
|
|
39
41
|
|
|
42
|
+
// Start Server Logic
|
|
43
|
+
const startServer = async () => {
|
|
44
|
+
logger.info(`Server running on port ${port}`);
|
|
45
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
46
|
+
try {
|
|
47
|
+
const kafkaService = new KafkaService();
|
|
48
|
+
await kafkaService.connect();
|
|
49
|
+
logger.info('Kafka connected');
|
|
50
|
+
// Demo
|
|
51
|
+
await kafkaService.sendMessage('test-topic', 'Hello Kafka from Clean Arch TS!');
|
|
52
|
+
} catch (err) {
|
|
53
|
+
logger.error('Failed to connect to Kafka:', err);
|
|
54
|
+
}
|
|
55
|
+
<%_ } -%>
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
<%_ if (database !== 'None') { -%>
|
|
40
59
|
// Database Sync
|
|
41
60
|
const syncDatabase = async () => {
|
|
42
61
|
let retries = 30;
|
|
43
62
|
while (retries) {
|
|
44
63
|
try {
|
|
45
|
-
<% if (database === 'MongoDB') {
|
|
64
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
46
65
|
const connectDB = (await import('@/infrastructure/database/database')).default;
|
|
47
66
|
await connectDB();
|
|
48
|
-
<% } else {
|
|
67
|
+
<%_ } else { -%>
|
|
49
68
|
const sequelize = (await import('@/infrastructure/database/database')).default;
|
|
50
69
|
await sequelize.sync();
|
|
51
|
-
<% }
|
|
70
|
+
<%_ } -%>
|
|
52
71
|
logger.info('Database synced');
|
|
53
|
-
|
|
54
|
-
app.listen(port, async () => {
|
|
55
|
-
logger.info(`Server running on port ${port}`);
|
|
56
|
-
<%_ if (communication === 'Kafka') { -%>
|
|
57
|
-
try {
|
|
58
|
-
const kafkaService = new KafkaService();
|
|
59
|
-
await kafkaService.connect();
|
|
60
|
-
logger.info('Kafka connected');
|
|
61
|
-
// Demo
|
|
62
|
-
await kafkaService.sendMessage('test-topic', 'Hello Kafka from Clean Arch TS!');
|
|
63
|
-
} catch (err) {
|
|
64
|
-
logger.error('Failed to connect to Kafka:', err);
|
|
65
|
-
}
|
|
66
|
-
<%_ } -%>
|
|
67
|
-
});
|
|
72
|
+
app.listen(port, startServer);
|
|
68
73
|
break;
|
|
69
74
|
} catch (error) {
|
|
70
75
|
logger.error('Error syncing database:', error);
|
|
@@ -75,4 +80,7 @@ const syncDatabase = async () => {
|
|
|
75
80
|
}
|
|
76
81
|
};
|
|
77
82
|
|
|
78
|
-
syncDatabase();
|
|
83
|
+
syncDatabase();
|
|
84
|
+
<%_ } else { -%>
|
|
85
|
+
app.listen(port, startServer);
|
|
86
|
+
<%_ } -%>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import winston from 'winston';
|
|
2
|
+
import 'winston-daily-rotate-file';
|
|
2
3
|
|
|
3
4
|
const logger = winston.createLogger({
|
|
4
5
|
level: 'info',
|
|
@@ -8,8 +9,21 @@ const logger = winston.createLogger({
|
|
|
8
9
|
),
|
|
9
10
|
defaultMeta: { service: 'user-service' },
|
|
10
11
|
transports: [
|
|
11
|
-
new winston.transports.
|
|
12
|
-
|
|
12
|
+
new winston.transports.DailyRotateFile({
|
|
13
|
+
filename: 'logs/error-%DATE%.log',
|
|
14
|
+
datePattern: 'YYYY-MM-DD',
|
|
15
|
+
zippedArchive: true,
|
|
16
|
+
maxSize: '20m',
|
|
17
|
+
maxFiles: '14d',
|
|
18
|
+
level: 'error',
|
|
19
|
+
}),
|
|
20
|
+
new winston.transports.DailyRotateFile({
|
|
21
|
+
filename: 'logs/combined-%DATE%.log',
|
|
22
|
+
datePattern: 'YYYY-MM-DD',
|
|
23
|
+
zippedArchive: true,
|
|
24
|
+
maxSize: '20m',
|
|
25
|
+
maxFiles: '14d',
|
|
26
|
+
}),
|
|
13
27
|
],
|
|
14
28
|
});
|
|
15
29
|
|
package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs
CHANGED
|
@@ -3,25 +3,36 @@ import UserModel from '@/infrastructure/database/models/User';
|
|
|
3
3
|
|
|
4
4
|
export class UserRepository {
|
|
5
5
|
async save(user: UserEntity): Promise<UserEntity> {
|
|
6
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
6
7
|
const newUser = await UserModel.create({ name: user.name, email: user.email });
|
|
7
|
-
|
|
8
|
-
<% } else
|
|
9
|
-
|
|
8
|
+
return { id: newUser._id.toString(), name: newUser.name, email: newUser.email };
|
|
9
|
+
<%_ } else if (database === 'None') { -%>
|
|
10
|
+
const newUser = { id: String(UserModel.mockData.length + 1), name: user.name, email: user.email };
|
|
11
|
+
UserModel.mockData.push(newUser);
|
|
12
|
+
return newUser;
|
|
13
|
+
<%_ } else { -%>
|
|
14
|
+
const newUser = await UserModel.create({ name: user.name, email: user.email });
|
|
15
|
+
return { id: newUser.id, name: newUser.name, email: newUser.email };
|
|
16
|
+
<%_ } -%>
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
async getUsers(): Promise<UserEntity[]> {
|
|
13
|
-
<% if (database === 'MongoDB') {
|
|
20
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
21
|
+
const users = await UserModel.find();
|
|
14
22
|
return users.map(user => ({
|
|
15
23
|
id: user._id.toString(),
|
|
16
24
|
name: user.name,
|
|
17
25
|
email: user.email
|
|
18
26
|
}));
|
|
19
|
-
<% } else
|
|
27
|
+
<%_ } else if (database === 'None') { -%>
|
|
28
|
+
return UserModel.mockData;
|
|
29
|
+
<%_ } else { -%>
|
|
30
|
+
const users = await UserModel.findAll();
|
|
20
31
|
return users.map(user => ({
|
|
21
32
|
id: user.id,
|
|
22
33
|
name: user.name,
|
|
23
34
|
email: user.email
|
|
24
35
|
}));
|
|
25
|
-
<% } -%>
|
|
36
|
+
<%_ } -%>
|
|
26
37
|
}
|
|
27
38
|
}
|
|
@@ -1,40 +1,54 @@
|
|
|
1
|
-
version: '3.8'
|
|
2
|
-
|
|
3
1
|
services:
|
|
4
2
|
app:
|
|
5
3
|
build: .
|
|
6
4
|
ports:
|
|
7
5
|
- "${PORT:-3000}:3000"
|
|
6
|
+
<%_ if (database !== 'None' || communication === 'Kafka') { -%>
|
|
8
7
|
depends_on:
|
|
8
|
+
<%_ if (database !== 'None') { -%>
|
|
9
9
|
- db
|
|
10
|
-
<%
|
|
11
|
-
<%
|
|
12
|
-
|
|
10
|
+
<%_ } -%>
|
|
11
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
12
|
+
- kafka
|
|
13
|
+
<%_ } -%>
|
|
14
|
+
<%_ } -%>
|
|
15
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
16
|
+
environment:
|
|
13
17
|
- KAFKA_BROKER=kafka:29092
|
|
14
18
|
- KAFKAJS_NO_PARTITIONER_WARNING=1
|
|
15
19
|
- PORT=3000
|
|
20
|
+
<%_ if (database !== 'None') { -%>
|
|
16
21
|
- DB_HOST=db
|
|
17
|
-
<% if (database === 'MySQL') {
|
|
22
|
+
<%_ if (database === 'MySQL') { -%>
|
|
23
|
+
- DB_USER=root
|
|
18
24
|
- DB_PASSWORD=root
|
|
19
25
|
- DB_NAME=<%= dbName %>
|
|
20
|
-
<% }
|
|
26
|
+
<%_ } -%><%_ if (database === 'PostgreSQL') { -%>
|
|
27
|
+
- DB_USER=postgres
|
|
21
28
|
- DB_PASSWORD=root
|
|
22
29
|
- DB_NAME=<%= dbName %>
|
|
23
|
-
<% } -%>
|
|
24
|
-
<% }
|
|
30
|
+
<%_ } -%>
|
|
31
|
+
<%_ } -%>
|
|
32
|
+
<%_ } else { -%>
|
|
25
33
|
environment:
|
|
26
34
|
- PORT=3000
|
|
35
|
+
<%_ if (database !== 'None') { -%>
|
|
27
36
|
- DB_HOST=db
|
|
28
|
-
<% if (database === 'MySQL') {
|
|
37
|
+
<%_ if (database === 'MySQL') { -%>
|
|
38
|
+
- DB_USER=root
|
|
29
39
|
- DB_PASSWORD=root
|
|
30
40
|
- DB_NAME=<%= dbName %>
|
|
31
|
-
<% }
|
|
41
|
+
<%_ } -%><%_ if (database === 'PostgreSQL') { -%>
|
|
42
|
+
- DB_USER=postgres
|
|
32
43
|
- DB_PASSWORD=root
|
|
33
44
|
- DB_NAME=<%= dbName %>
|
|
34
|
-
<% } -%>
|
|
35
|
-
<% }
|
|
45
|
+
<%_ } -%>
|
|
46
|
+
<%_ } -%>
|
|
47
|
+
<%_ } -%>
|
|
48
|
+
<%_ if (database !== 'None') { -%>
|
|
36
49
|
db:
|
|
37
|
-
<% if (database === 'MySQL') {
|
|
50
|
+
<%_ if (database === 'MySQL') { -%>
|
|
51
|
+
image: mysql:8.0
|
|
38
52
|
restart: always
|
|
39
53
|
environment:
|
|
40
54
|
MYSQL_ROOT_PASSWORD: root
|
|
@@ -43,7 +57,8 @@ services:
|
|
|
43
57
|
- "${DB_PORT:-3306}:3306"
|
|
44
58
|
volumes:
|
|
45
59
|
- ./flyway/sql:/docker-entrypoint-initdb.d
|
|
46
|
-
<% } else if (database === 'PostgreSQL') {
|
|
60
|
+
<%_ } else if (database === 'PostgreSQL') { -%>
|
|
61
|
+
image: postgres:15
|
|
47
62
|
restart: always
|
|
48
63
|
environment:
|
|
49
64
|
POSTGRES_USER: postgres
|
|
@@ -53,7 +68,8 @@ services:
|
|
|
53
68
|
- "${DB_PORT:-5432}:5432"
|
|
54
69
|
volumes:
|
|
55
70
|
- ./flyway/sql:/docker-entrypoint-initdb.d
|
|
56
|
-
<% } else if (database === 'MongoDB') {
|
|
71
|
+
<%_ } else if (database === 'MongoDB') { -%>
|
|
72
|
+
image: mongo:latest
|
|
57
73
|
restart: always
|
|
58
74
|
environment:
|
|
59
75
|
MONGO_INITDB_DATABASE: <%= dbName %>
|
|
@@ -73,24 +89,29 @@ services:
|
|
|
73
89
|
- DB_NAME=<%= dbName %>
|
|
74
90
|
depends_on:
|
|
75
91
|
- db
|
|
76
|
-
<% }
|
|
77
|
-
<%
|
|
92
|
+
<%_ } -%>
|
|
93
|
+
<%_ } -%>
|
|
94
|
+
<%_ if (database !== 'MongoDB' && database !== 'None') { -%>
|
|
78
95
|
flyway:
|
|
79
96
|
image: flyway/flyway
|
|
80
97
|
command: -connectRetries=60 migrate
|
|
81
98
|
volumes:
|
|
82
99
|
- ./flyway/sql:/flyway/sql
|
|
83
100
|
environment:
|
|
84
|
-
<% if (database === 'MySQL') {
|
|
101
|
+
<%_ if (database === 'MySQL') { -%>
|
|
102
|
+
FLYWAY_URL: jdbc:mysql://db:3306/<%= dbName %>
|
|
85
103
|
FLYWAY_USER: root
|
|
86
104
|
FLYWAY_PASSWORD: root
|
|
87
|
-
<% }
|
|
105
|
+
<%_ } -%><%_ if (database === 'PostgreSQL') { -%>
|
|
106
|
+
FLYWAY_URL: jdbc:postgresql://db:5432/<%= dbName %>
|
|
88
107
|
FLYWAY_USER: postgres
|
|
89
108
|
FLYWAY_PASSWORD: root
|
|
90
|
-
<% }
|
|
109
|
+
<%_ } -%>
|
|
110
|
+
depends_on:
|
|
91
111
|
- db
|
|
92
|
-
<% }
|
|
93
|
-
<% if (communication === 'Kafka') {
|
|
112
|
+
<%_ } -%>
|
|
113
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
114
|
+
zookeeper:
|
|
94
115
|
image: confluentinc/cp-zookeeper:7.4.0
|
|
95
116
|
environment:
|
|
96
117
|
ZOOKEEPER_CLIENT_PORT: 2181
|
|
@@ -111,6 +132,8 @@ services:
|
|
|
111
132
|
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
|
|
112
133
|
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
|
|
113
134
|
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
|
114
|
-
<% } -%>
|
|
135
|
+
<%_ } -%>
|
|
136
|
+
<%_ if (database !== 'None') { -%>
|
|
115
137
|
volumes:
|
|
116
138
|
<%= database.toLowerCase() %>_data:
|
|
139
|
+
<%_ } -%>
|
|
@@ -13,8 +13,10 @@
|
|
|
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
|
+
<%_ if (database === 'MongoDB') { -%>,
|
|
17
18
|
"migrate": "migrate-mongo up"
|
|
19
|
+
<%_ } -%>
|
|
18
20
|
},
|
|
19
21
|
"dependencies": {
|
|
20
22
|
"express": "^4.18.2",
|
|
@@ -38,7 +40,9 @@
|
|
|
38
40
|
"helmet": "^7.1.0",
|
|
39
41
|
"hpp": "^0.2.3",
|
|
40
42
|
"express-rate-limit": "^7.1.5",
|
|
41
|
-
"winston": "^3.11.0"
|
|
43
|
+
"winston": "^3.11.0",
|
|
44
|
+
"winston-daily-rotate-file": "^5.0.0",
|
|
45
|
+
"morgan": "^1.10.0"<% if (communication === 'REST APIs') { %>,
|
|
42
46
|
"swagger-ui-express": "^5.0.0",
|
|
43
47
|
"swagger-jsdoc": "^6.2.8"<% } %>
|
|
44
48
|
},
|
|
@@ -53,7 +57,10 @@
|
|
|
53
57
|
"@types/hpp": "^0.2.3",
|
|
54
58
|
<% if (database === 'PostgreSQL') { %> "@types/pg": "^8.10.9",
|
|
55
59
|
<% } -%>
|
|
60
|
+
<%_ if (database === 'MySQL' || database === 'PostgreSQL') { -%>
|
|
56
61
|
"@types/sequelize": "^4.28.19",
|
|
62
|
+
<%_ } -%>
|
|
63
|
+
"@types/morgan": "^1.9.9",
|
|
57
64
|
"rimraf": "^5.0.5"<% if (viewEngine && viewEngine !== 'None') { %>,
|
|
58
65
|
"copyfiles": "^2.4.1"<% } %><% } %>,
|
|
59
66
|
"eslint": "^8.56.0",
|
|
@@ -4,9 +4,13 @@ const logger = require('../utils/logger');
|
|
|
4
4
|
|
|
5
5
|
const getUsers = async (req, res) => {
|
|
6
6
|
try {
|
|
7
|
-
<% if (database === 'MongoDB') {
|
|
8
|
-
|
|
9
|
-
<% } -%>
|
|
7
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
8
|
+
const users = await User.find();
|
|
9
|
+
<%_ } else if (database === 'None') { -%>
|
|
10
|
+
const users = User.mockData;
|
|
11
|
+
<%_ } else { -%>
|
|
12
|
+
const users = await User.findAll();
|
|
13
|
+
<%_ } -%>
|
|
10
14
|
res.json(users);
|
|
11
15
|
} catch (error) {
|
|
12
16
|
logger.error('Error fetching users:', error);
|
|
@@ -17,8 +21,14 @@ const getUsers = async (req, res) => {
|
|
|
17
21
|
const createUser = async (req, res) => {
|
|
18
22
|
try {
|
|
19
23
|
const { name, email } = req.body;
|
|
24
|
+
<%_ if (database === 'None') { -%>
|
|
25
|
+
const newUser = { id: String(User.mockData.length + 1), name, email };
|
|
26
|
+
User.mockData.push(newUser);
|
|
27
|
+
res.status(HTTP_STATUS.CREATED).json(newUser);
|
|
28
|
+
<%_ } else { -%>
|
|
20
29
|
const user = await User.create({ name, email });
|
|
21
30
|
res.status(HTTP_STATUS.CREATED).json(user);
|
|
31
|
+
<%_ } -%>
|
|
22
32
|
} catch (error) {
|
|
23
33
|
res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: error.message });
|
|
24
34
|
}
|
|
@@ -11,9 +11,11 @@ const swaggerSpecs = require('./config/swagger');
|
|
|
11
11
|
const app = express();
|
|
12
12
|
const PORT = process.env.PORT || 3000;
|
|
13
13
|
const logger = require('./utils/logger');
|
|
14
|
+
const morgan = require('morgan');
|
|
14
15
|
|
|
15
16
|
app.use(cors());
|
|
16
17
|
app.use(express.json());
|
|
18
|
+
app.use(morgan('combined', { stream: { write: message => logger.info(message.trim()) } }));
|
|
17
19
|
|
|
18
20
|
<% if (communication === 'REST APIs') { -%>
|
|
19
21
|
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
|
|
@@ -45,34 +47,38 @@ app.get('/health', (req, res) => {
|
|
|
45
47
|
res.json({ status: 'UP' });
|
|
46
48
|
});
|
|
47
49
|
|
|
50
|
+
// Start Server Logic
|
|
51
|
+
const startServer = async () => {
|
|
52
|
+
logger.info(`Server running on port ${PORT}`);
|
|
53
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
54
|
+
try {
|
|
55
|
+
await connectKafka();
|
|
56
|
+
logger.info('Kafka connected');
|
|
57
|
+
// Demo: Send a test message
|
|
58
|
+
await sendMessage('test-topic', 'Hello Kafka from MVC JS!');
|
|
59
|
+
} catch (err) {
|
|
60
|
+
logger.error('Failed to connect to Kafka:', err);
|
|
61
|
+
}
|
|
62
|
+
<%_ } -%>
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
<%_ if (database !== 'None') { -%>
|
|
48
66
|
// Database Sync
|
|
49
67
|
const syncDatabase = async () => {
|
|
50
68
|
let retries = 30;
|
|
51
69
|
while (retries) {
|
|
52
70
|
try {
|
|
53
|
-
<% if (database === 'MongoDB') {
|
|
71
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
54
72
|
const connectDB = require('./config/database');
|
|
55
73
|
await connectDB();
|
|
56
|
-
<% } else {
|
|
74
|
+
<%_ } else { -%>
|
|
57
75
|
const sequelize = require('./config/database');
|
|
58
76
|
await sequelize.sync();
|
|
59
|
-
<% }
|
|
77
|
+
<%_ } -%>
|
|
60
78
|
logger.info('Database synced');
|
|
61
79
|
|
|
62
80
|
// Start Server after DB is ready
|
|
63
|
-
app.listen(PORT,
|
|
64
|
-
logger.info(`Server running on port ${PORT}`);
|
|
65
|
-
<%_ if (communication === 'Kafka') { -%>
|
|
66
|
-
try {
|
|
67
|
-
await connectKafka();
|
|
68
|
-
logger.info('Kafka connected');
|
|
69
|
-
// Demo: Send a test message
|
|
70
|
-
await sendMessage('test-topic', 'Hello Kafka from MVC JS!');
|
|
71
|
-
} catch (err) {
|
|
72
|
-
logger.error('Failed to connect to Kafka:', err);
|
|
73
|
-
}
|
|
74
|
-
<%_ } -%>
|
|
75
|
-
});
|
|
81
|
+
app.listen(PORT, startServer);
|
|
76
82
|
break;
|
|
77
83
|
} catch (err) {
|
|
78
84
|
logger.error('Database sync failed:', err);
|
|
@@ -83,4 +89,7 @@ const syncDatabase = async () => {
|
|
|
83
89
|
}
|
|
84
90
|
};
|
|
85
91
|
|
|
86
|
-
syncDatabase();
|
|
92
|
+
syncDatabase();
|
|
93
|
+
<%_ } else { -%>
|
|
94
|
+
app.listen(PORT, startServer);
|
|
95
|
+
<%_ } -%>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const winston = require('winston');
|
|
2
|
+
require('winston-daily-rotate-file');
|
|
2
3
|
|
|
3
4
|
const logger = winston.createLogger({
|
|
4
5
|
level: 'info',
|
|
@@ -8,12 +9,21 @@ const logger = winston.createLogger({
|
|
|
8
9
|
),
|
|
9
10
|
defaultMeta: { service: 'user-service' },
|
|
10
11
|
transports: [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
new winston.transports.DailyRotateFile({
|
|
13
|
+
filename: 'logs/error-%DATE%.log',
|
|
14
|
+
datePattern: 'YYYY-MM-DD',
|
|
15
|
+
zippedArchive: true,
|
|
16
|
+
maxSize: '20m',
|
|
17
|
+
maxFiles: '14d',
|
|
18
|
+
level: 'error',
|
|
19
|
+
}),
|
|
20
|
+
new winston.transports.DailyRotateFile({
|
|
21
|
+
filename: 'logs/combined-%DATE%.log',
|
|
22
|
+
datePattern: 'YYYY-MM-DD',
|
|
23
|
+
zippedArchive: true,
|
|
24
|
+
maxSize: '20m',
|
|
25
|
+
maxFiles: '14d',
|
|
26
|
+
}),
|
|
17
27
|
],
|
|
18
28
|
});
|
|
19
29
|
|
|
@@ -6,9 +6,13 @@ import logger from '@/utils/logger';
|
|
|
6
6
|
export class UserController {
|
|
7
7
|
async getUsers(req: Request, res: Response) {
|
|
8
8
|
try {
|
|
9
|
-
<% if (database === 'MongoDB') {
|
|
10
|
-
|
|
11
|
-
<% } -%>
|
|
9
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
10
|
+
const users = await User.find();
|
|
11
|
+
<%_ } else if (database === 'None') { -%>
|
|
12
|
+
const users = User.mockData;
|
|
13
|
+
<%_ } else { -%>
|
|
14
|
+
const users = await User.findAll();
|
|
15
|
+
<%_ } -%>
|
|
12
16
|
res.json(users);
|
|
13
17
|
} catch (error) {
|
|
14
18
|
logger.error('Error fetching users:', error);
|
|
@@ -23,8 +27,14 @@ export class UserController {
|
|
|
23
27
|
async createUser(req: Request, res: Response) {
|
|
24
28
|
try {
|
|
25
29
|
const { name, email } = req.body;
|
|
30
|
+
<%_ if (database === 'None') { -%>
|
|
31
|
+
const newUser = { id: String(User.mockData.length + 1), name, email };
|
|
32
|
+
User.mockData.push(newUser);
|
|
33
|
+
res.status(HTTP_STATUS.CREATED).json(newUser);
|
|
34
|
+
<%_ } else { -%>
|
|
26
35
|
const user = await User.create({ name, email });
|
|
27
36
|
res.status(HTTP_STATUS.CREATED).json(user);
|
|
37
|
+
<%_ } -%>
|
|
28
38
|
} catch (error) {
|
|
29
39
|
logger.error('Error creating user:', error);
|
|
30
40
|
if (error instanceof Error) {
|
|
@@ -5,6 +5,7 @@ import hpp from 'hpp';
|
|
|
5
5
|
import rateLimit from 'express-rate-limit';
|
|
6
6
|
import dotenv from 'dotenv';
|
|
7
7
|
import logger from '@/utils/logger';
|
|
8
|
+
import morgan from 'morgan';
|
|
8
9
|
<% if (communication === 'REST APIs' || (viewEngine && viewEngine !== 'None')) { %>import apiRoutes from '@/routes/api';<% } -%>
|
|
9
10
|
<% if (communication === 'REST APIs') { %>
|
|
10
11
|
import swaggerUi from 'swagger-ui-express';
|
|
@@ -24,6 +25,7 @@ const limiter = rateLimit({ windowMs: 10 * 60 * 1000, max: 100 });
|
|
|
24
25
|
app.use(limiter);
|
|
25
26
|
|
|
26
27
|
app.use(express.json());
|
|
28
|
+
app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
|
|
27
29
|
|
|
28
30
|
<% if (communication === 'REST APIs') { -%>
|
|
29
31
|
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
|
|
@@ -55,34 +57,38 @@ app.get('/health', (req: Request, res: Response) => {
|
|
|
55
57
|
res.json({ status: 'UP' });
|
|
56
58
|
});
|
|
57
59
|
|
|
60
|
+
// Start Server Logic
|
|
61
|
+
const startServer = async () => {
|
|
62
|
+
logger.info(`Server running on port ${port}`);
|
|
63
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
64
|
+
try {
|
|
65
|
+
const kafkaService = new KafkaService();
|
|
66
|
+
await kafkaService.connect();
|
|
67
|
+
logger.info('Kafka connected');
|
|
68
|
+
// Demo: Send a test message
|
|
69
|
+
await kafkaService.sendMessage('test-topic', 'Hello Kafka from MVC TS!');
|
|
70
|
+
} catch (err) {
|
|
71
|
+
logger.error('Failed to connect to Kafka:', err);
|
|
72
|
+
}
|
|
73
|
+
<%_ } -%>
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
<%_ if (database !== 'None') { -%>
|
|
58
77
|
// Database Sync
|
|
59
78
|
const syncDatabase = async () => {
|
|
60
79
|
let retries = 30;
|
|
61
80
|
while (retries) {
|
|
62
81
|
try {
|
|
63
|
-
<% if (database === 'MongoDB') {
|
|
82
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
64
83
|
const connectDB = (await import('@/config/database')).default;
|
|
65
84
|
await connectDB();
|
|
66
|
-
<% } else {
|
|
85
|
+
<%_ } else { -%>
|
|
67
86
|
const sequelize = (await import('@/config/database')).default;
|
|
68
87
|
await sequelize.sync();
|
|
69
|
-
<% }
|
|
88
|
+
<%_ } -%>
|
|
70
89
|
logger.info('Database synced');
|
|
71
90
|
// Start Server after DB is ready
|
|
72
|
-
app.listen(port,
|
|
73
|
-
logger.info(`Server running on port ${port}`);
|
|
74
|
-
<%_ if (communication === 'Kafka') { -%>
|
|
75
|
-
try {
|
|
76
|
-
const kafkaService = new KafkaService();
|
|
77
|
-
await kafkaService.connect();
|
|
78
|
-
logger.info('Kafka connected');
|
|
79
|
-
// Demo: Send a test message
|
|
80
|
-
await kafkaService.sendMessage('test-topic', 'Hello Kafka from MVC TS!');
|
|
81
|
-
} catch (err) {
|
|
82
|
-
logger.error('Failed to connect to Kafka:', err);
|
|
83
|
-
}
|
|
84
|
-
<%_ } -%>
|
|
85
|
-
});
|
|
91
|
+
app.listen(port, startServer);
|
|
86
92
|
break;
|
|
87
93
|
} catch (error) {
|
|
88
94
|
logger.error('Error syncing database:', error);
|
|
@@ -93,4 +99,7 @@ const syncDatabase = async () => {
|
|
|
93
99
|
}
|
|
94
100
|
};
|
|
95
101
|
|
|
96
|
-
syncDatabase();
|
|
102
|
+
syncDatabase();
|
|
103
|
+
<%_ } else { -%>
|
|
104
|
+
app.listen(port, startServer);
|
|
105
|
+
<%_ } -%>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import winston from 'winston';
|
|
2
|
+
import 'winston-daily-rotate-file';
|
|
2
3
|
|
|
3
4
|
const logger = winston.createLogger({
|
|
4
5
|
level: 'info',
|
|
@@ -8,8 +9,21 @@ const logger = winston.createLogger({
|
|
|
8
9
|
),
|
|
9
10
|
defaultMeta: { service: 'user-service' },
|
|
10
11
|
transports: [
|
|
11
|
-
new winston.transports.
|
|
12
|
-
|
|
12
|
+
new winston.transports.DailyRotateFile({
|
|
13
|
+
filename: 'logs/error-%DATE%.log',
|
|
14
|
+
datePattern: 'YYYY-MM-DD',
|
|
15
|
+
zippedArchive: true,
|
|
16
|
+
maxSize: '20m',
|
|
17
|
+
maxFiles: '14d',
|
|
18
|
+
level: 'error',
|
|
19
|
+
}),
|
|
20
|
+
new winston.transports.DailyRotateFile({
|
|
21
|
+
filename: 'logs/combined-%DATE%.log',
|
|
22
|
+
datePattern: 'YYYY-MM-DD',
|
|
23
|
+
zippedArchive: true,
|
|
24
|
+
maxSize: '20m',
|
|
25
|
+
maxFiles: '14d',
|
|
26
|
+
}),
|
|
13
27
|
],
|
|
14
28
|
});
|
|
15
29
|
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Database configuration placeholder
|
|
2
|
-
// Use environment variables from .env depending on your DB choice (MySQL/Postgres)
|
|
3
|
-
require('dotenv').config();
|
|
4
|
-
|
|
5
|
-
const dbConfig = {
|
|
6
|
-
host: process.env.DB_HOST,
|
|
7
|
-
user: process.env.DB_USER,
|
|
8
|
-
password: process.env.DB_PASSWORD,
|
|
9
|
-
database: process.env.DB_NAME
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
module.exports = dbConfig;
|