nodejs-quickstart-structure 1.4.3 → 1.7.5

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 (45) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +18 -20
  3. package/bin/index.js +1 -0
  4. package/docs/generateCase.md +127 -61
  5. package/docs/generatorFlow.md +15 -3
  6. package/docs/releaseNoteRule.md +42 -0
  7. package/lib/generator.js +46 -314
  8. package/lib/modules/app-setup.js +96 -0
  9. package/lib/modules/caching-setup.js +56 -0
  10. package/lib/modules/config-files.js +109 -0
  11. package/lib/modules/database-setup.js +111 -0
  12. package/lib/modules/kafka-setup.js +112 -0
  13. package/lib/modules/project-setup.js +31 -0
  14. package/lib/prompts.js +12 -4
  15. package/package.json +4 -3
  16. package/templates/clean-architecture/js/src/index.js.ejs +19 -6
  17. package/templates/clean-architecture/js/src/infrastructure/log/logger.js +16 -2
  18. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +18 -6
  19. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +2 -0
  20. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +1 -2
  21. package/templates/clean-architecture/ts/src/index.ts.ejs +27 -19
  22. package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +16 -2
  23. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +17 -6
  24. package/templates/common/.env.example.ejs +39 -0
  25. package/templates/common/Dockerfile +3 -0
  26. package/templates/common/Jenkinsfile.ejs +41 -0
  27. package/templates/common/README.md.ejs +113 -106
  28. package/templates/common/caching/clean/js/CreateUser.js.ejs +25 -0
  29. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +33 -0
  30. package/templates/common/caching/clean/ts/createUser.ts.ejs +23 -0
  31. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +30 -0
  32. package/templates/common/caching/js/redisClient.js.ejs +71 -0
  33. package/templates/common/caching/ts/redisClient.ts.ejs +76 -0
  34. package/templates/common/docker-compose.yml.ejs +156 -116
  35. package/templates/common/package.json.ejs +13 -2
  36. package/templates/mvc/js/src/controllers/userController.js.ejs +35 -3
  37. package/templates/mvc/js/src/index.js.ejs +26 -17
  38. package/templates/mvc/js/src/utils/logger.js +16 -6
  39. package/templates/mvc/ts/src/config/swagger.ts.ejs +1 -2
  40. package/templates/mvc/ts/src/controllers/userController.ts.ejs +35 -3
  41. package/templates/mvc/ts/src/index.ts.ejs +27 -18
  42. package/templates/mvc/ts/src/utils/logger.ts +16 -2
  43. package/templates/mvc/js/src/config/database.js +0 -12
  44. /package/templates/db/mysql/{V1__Initial_Setup.sql → V1__Initial_Setup.sql.ejs} +0 -0
  45. /package/templates/db/postgres/{V1__Initial_Setup.sql → V1__Initial_Setup.sql.ejs} +0 -0
@@ -1,116 +1,156 @@
1
- version: '3.8'
2
-
3
- services:
4
- app:
5
- build: .
6
- ports:
7
- - "${PORT:-3000}:3000"
8
- depends_on:
9
- - db
10
- <% if (communication === 'Kafka') { %> - kafka
11
- <% } -%>
12
- <% if (communication === 'Kafka') { %> environment:
13
- - KAFKA_BROKER=kafka:29092
14
- - KAFKAJS_NO_PARTITIONER_WARNING=1
15
- - PORT=3000
16
- - DB_HOST=db
17
- <% if (database === 'MySQL') { %> - DB_USER=root
18
- - DB_PASSWORD=root
19
- - DB_NAME=<%= dbName %>
20
- <% } %><% if (database === 'PostgreSQL') { %> - DB_USER=postgres
21
- - DB_PASSWORD=root
22
- - DB_NAME=<%= dbName %>
23
- <% } -%>
24
- <% } else { %>
25
- environment:
26
- - PORT=3000
27
- - DB_HOST=db
28
- <% if (database === 'MySQL') { %> - DB_USER=root
29
- - DB_PASSWORD=root
30
- - DB_NAME=<%= dbName %>
31
- <% } %><% if (database === 'PostgreSQL') { %> - DB_USER=postgres
32
- - DB_PASSWORD=root
33
- - DB_NAME=<%= dbName %>
34
- <% } -%>
35
- <% } %>
36
- db:
37
- <% if (database === 'MySQL') { %> image: mysql:8.0
38
- restart: always
39
- environment:
40
- MYSQL_ROOT_PASSWORD: root
41
- MYSQL_DATABASE: <%= dbName %>
42
- ports:
43
- - "${DB_PORT:-3306}:3306"
44
- volumes:
45
- - ./flyway/sql:/docker-entrypoint-initdb.d
46
- <% } else if (database === 'PostgreSQL') { %> image: postgres:15
47
- restart: always
48
- environment:
49
- POSTGRES_USER: postgres
50
- POSTGRES_PASSWORD: root
51
- POSTGRES_DB: <%= dbName %>
52
- ports:
53
- - "${DB_PORT:-5432}:5432"
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
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') { %>
78
- flyway:
79
- image: flyway/flyway
80
- command: -connectRetries=60 migrate
81
- volumes:
82
- - ./flyway/sql:/flyway/sql
83
- environment:
84
- <% if (database === 'MySQL') { %> FLYWAY_URL: jdbc:mysql://db:3306/<%= dbName %>
85
- FLYWAY_USER: root
86
- FLYWAY_PASSWORD: root
87
- <% } %><% if (database === 'PostgreSQL') { %> FLYWAY_URL: jdbc:postgresql://db:5432/<%= dbName %>
88
- FLYWAY_USER: postgres
89
- FLYWAY_PASSWORD: root
90
- <% } %> depends_on:
91
- - db
92
- <% } %>
93
- <% if (communication === 'Kafka') { %> zookeeper:
94
- image: confluentinc/cp-zookeeper:7.4.0
95
- environment:
96
- ZOOKEEPER_CLIENT_PORT: 2181
97
- ZOOKEEPER_TICK_TIME: 2000
98
- ports:
99
- - "${ZOOKEEPER_PORT:-2181}:2181"
100
-
101
- kafka:
102
- image: confluentinc/cp-kafka:7.4.0
103
- depends_on:
104
- - zookeeper
105
- ports:
106
- - "${KAFKA_PORT:-9092}:9092"
107
- environment:
108
- KAFKA_BROKER_ID: 1
109
- KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
110
- KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
111
- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
112
- KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
113
- KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
114
- <% } -%>
115
- volumes:
116
- <%= database.toLowerCase() %>_data:
1
+ services:
2
+ app:
3
+ build: .
4
+ ports:
5
+ - "${PORT:-3000}:3000"
6
+ <%_ if (database !== 'None' || communication === 'Kafka') { -%>
7
+ depends_on:
8
+ <%_ if (database !== 'None') { -%>
9
+ - db
10
+ <%_ } -%>
11
+ <%_ if (communication === 'Kafka') { -%>
12
+ - kafka
13
+ <%_ } -%>
14
+ <%_ } -%>
15
+ <%_ if (communication === 'Kafka') { -%>
16
+ environment:
17
+ - KAFKA_BROKER=kafka:29092
18
+ - KAFKAJS_NO_PARTITIONER_WARNING=1
19
+ - PORT=3000
20
+ <%_ if (caching === 'Redis') { -%>
21
+ - REDIS_HOST=redis
22
+ - REDIS_PORT=6379
23
+ - REDIS_PASSWORD=
24
+ <%_ } -%>
25
+ <%_ if (database !== 'None') { -%>
26
+ - DB_HOST=db
27
+ <%_ if (database === 'MySQL') { -%>
28
+ - DB_USER=root
29
+ - DB_PASSWORD=root
30
+ - DB_NAME=<%= dbName %>
31
+ <%_ } -%><%_ if (database === 'PostgreSQL') { -%>
32
+ - DB_USER=postgres
33
+ - DB_PASSWORD=root
34
+ - DB_NAME=<%= dbName %>
35
+ <%_ } -%>
36
+ <%_ } -%>
37
+ <%_ } else { -%>
38
+ environment:
39
+ - PORT=3000
40
+ <%_ if (caching === 'Redis') { -%>
41
+ - REDIS_HOST=redis
42
+ - REDIS_PORT=6379
43
+ - REDIS_PASSWORD=
44
+ <%_ } -%>
45
+ <%_ if (database !== 'None') { -%>
46
+ - DB_HOST=db
47
+ <%_ if (database === 'MySQL') { -%>
48
+ - DB_USER=root
49
+ - DB_PASSWORD=root
50
+ - DB_NAME=<%= dbName %>
51
+ <%_ } -%><%_ if (database === 'PostgreSQL') { -%>
52
+ - DB_USER=postgres
53
+ - DB_PASSWORD=root
54
+ - DB_NAME=<%= dbName %>
55
+ <%_ } -%>
56
+ <%_ } -%>
57
+ <%_ } -%>
58
+ <%_ if (database !== 'None') { -%>
59
+ db:
60
+ <%_ if (database === 'MySQL') { -%>
61
+ image: mysql:8.0
62
+ restart: always
63
+ environment:
64
+ MYSQL_ROOT_PASSWORD: root
65
+ MYSQL_DATABASE: <%= dbName %>
66
+ ports:
67
+ - "${DB_PORT:-3306}:3306"
68
+ volumes:
69
+ - ./flyway/sql:/docker-entrypoint-initdb.d
70
+ <%_ } else if (database === 'PostgreSQL') { -%>
71
+ image: postgres:15
72
+ restart: always
73
+ environment:
74
+ POSTGRES_USER: postgres
75
+ POSTGRES_PASSWORD: root
76
+ POSTGRES_DB: <%= dbName %>
77
+ ports:
78
+ - "${DB_PORT:-5432}:5432"
79
+ volumes:
80
+ - ./flyway/sql:/docker-entrypoint-initdb.d
81
+ <%_ } else if (database === 'MongoDB') { -%>
82
+ image: mongo:latest
83
+ restart: always
84
+ environment:
85
+ MONGO_INITDB_DATABASE: <%= dbName %>
86
+ ports:
87
+ - "${DB_PORT:-27017}:27017"
88
+ volumes:
89
+ - mongodb_data:/data/db
90
+
91
+ mongo-migrate:
92
+ image: node:18-alpine
93
+ working_dir: /app
94
+ volumes:
95
+ - .:/app
96
+ command: sh -c "npm install migrate-mongo && npm run migrate"
97
+ environment:
98
+ - DB_HOST=db
99
+ - DB_NAME=<%= dbName %>
100
+ depends_on:
101
+ - db
102
+ <%_ } -%>
103
+ <%_ } -%>
104
+ <%_ if (database !== 'MongoDB' && database !== 'None') { -%>
105
+ flyway:
106
+ image: flyway/flyway
107
+ command: -connectRetries=60 migrate
108
+ volumes:
109
+ - ./flyway/sql:/flyway/sql
110
+ environment:
111
+ <%_ if (database === 'MySQL') { -%>
112
+ FLYWAY_URL: jdbc:mysql://db:3306/<%= dbName %>
113
+ FLYWAY_USER: root
114
+ FLYWAY_PASSWORD: root
115
+ <%_ } -%><%_ if (database === 'PostgreSQL') { -%>
116
+ FLYWAY_URL: jdbc:postgresql://db:5432/<%= dbName %>
117
+ FLYWAY_USER: postgres
118
+ FLYWAY_PASSWORD: root
119
+ <%_ } -%>
120
+ depends_on:
121
+ - db
122
+ <%_ } -%>
123
+ <%_ if (communication === 'Kafka') { -%>
124
+ zookeeper:
125
+ image: confluentinc/cp-zookeeper:7.4.0
126
+ environment:
127
+ ZOOKEEPER_CLIENT_PORT: 2181
128
+ ZOOKEEPER_TICK_TIME: 2000
129
+ ports:
130
+ - "${ZOOKEEPER_PORT:-2181}:2181"
131
+
132
+ kafka:
133
+ image: confluentinc/cp-kafka:7.4.0
134
+ depends_on:
135
+ - zookeeper
136
+ ports:
137
+ - "${KAFKA_PORT:-9092}:9092"
138
+ environment:
139
+ KAFKA_BROKER_ID: 1
140
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
141
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
142
+ KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
143
+ KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
144
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
145
+ <%_ } -%>
146
+ <%_ if (caching === 'Redis') { -%>
147
+ redis:
148
+ image: redis:alpine
149
+ restart: always
150
+ ports:
151
+ - "${REDIS_PORT:-6379}:6379"
152
+ <%_ } -%>
153
+ <%_ if (database !== 'None') { -%>
154
+ volumes:
155
+ <%= database.toLowerCase() %>_data:
156
+ <%_ } -%>
@@ -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",
@@ -30,6 +32,8 @@
30
32
  <% } -%>
31
33
  <% if (communication === 'Kafka') { %> "kafkajs": "^2.2.4",
32
34
  <% } -%>
35
+ <% if (caching === 'Redis') { %> "ioredis": "^5.3.2",
36
+ <% } -%>
33
37
  <% if (viewEngine === 'EJS') { %> "ejs": "^3.1.9",
34
38
  <% } -%>
35
39
  <% if (viewEngine === 'Pug') { %> "pug": "^3.0.2",
@@ -38,7 +42,9 @@
38
42
  "helmet": "^7.1.0",
39
43
  "hpp": "^0.2.3",
40
44
  "express-rate-limit": "^7.1.5",
41
- "winston": "^3.11.0"<% if (communication === 'REST APIs') { %>,
45
+ "winston": "^3.11.0",
46
+ "winston-daily-rotate-file": "^5.0.0",
47
+ "morgan": "^1.10.0"<% if (communication === 'REST APIs') { %>,
42
48
  "swagger-ui-express": "^5.0.0",
43
49
  "swagger-jsdoc": "^6.2.8"<% } %>
44
50
  },
@@ -51,9 +57,14 @@
51
57
  "@types/cors": "^2.8.17",
52
58
  "@types/dotenv": "^8.2.0",
53
59
  "@types/hpp": "^0.2.3",
60
+ <% if (caching === 'Redis') { %> "@types/ioredis": "^5.0.0",
61
+ <% } -%>
54
62
  <% if (database === 'PostgreSQL') { %> "@types/pg": "^8.10.9",
55
63
  <% } -%>
64
+ <%_ if (database === 'MySQL' || database === 'PostgreSQL') { -%>
56
65
  "@types/sequelize": "^4.28.19",
66
+ <%_ } -%>
67
+ "@types/morgan": "^1.9.9",
57
68
  "rimraf": "^5.0.5"<% if (viewEngine && viewEngine !== 'None') { %>,
58
69
  "copyfiles": "^2.4.1"<% } %><% } %>,
59
70
  "eslint": "^8.56.0",
@@ -1,12 +1,31 @@
1
1
  const User = require('../models/User');
2
2
  const HTTP_STATUS = require('../utils/httpCodes');
3
3
  const logger = require('../utils/logger');
4
+ <%_ if (caching === 'Redis') { -%>
5
+ const redisService = require('../config/redisClient');
6
+ <%_ } -%>
4
7
 
5
8
  const getUsers = async (req, res) => {
6
9
  try {
7
- <% if (database === 'MongoDB') { %> const users = await User.find();
8
- <% } else { %> const users = await User.findAll();
9
- <% } -%>
10
+ <%_ if (caching === 'Redis') { -%>
11
+ const users = await redisService.getOrSet('users:all', async () => {
12
+ <%_ if (database === 'MongoDB') { -%>
13
+ return await User.find();
14
+ <%_ } else if (database === 'None') { -%>
15
+ return User.mockData;
16
+ <%_ } else { -%>
17
+ return await User.findAll();
18
+ <%_ } -%>
19
+ }, 60);
20
+ <%_ } else { -%>
21
+ <%_ if (database === 'MongoDB') { -%>
22
+ const users = await User.find();
23
+ <%_ } else if (database === 'None') { -%>
24
+ const users = User.mockData;
25
+ <%_ } else { -%>
26
+ const users = await User.findAll();
27
+ <%_ } -%>
28
+ <%_ } -%>
10
29
  res.json(users);
11
30
  } catch (error) {
12
31
  logger.error('Error fetching users:', error);
@@ -17,11 +36,24 @@ const getUsers = async (req, res) => {
17
36
  const createUser = async (req, res) => {
18
37
  try {
19
38
  const { name, email } = req.body;
39
+ <%_ if (database === 'None') { -%>
40
+ const newUser = { id: String(User.mockData.length + 1), name, email };
41
+ User.mockData.push(newUser);
42
+ <%_ if (caching === 'Redis') { -%>
43
+ await redisService.del('users:all');
44
+ <%_ } -%>
45
+ res.status(HTTP_STATUS.CREATED).json(newUser);
46
+ <%_ } else { -%>
20
47
  const user = await User.create({ name, email });
48
+ <%_ if (caching === 'Redis') { -%>
49
+ await redisService.del('users:all');
50
+ <%_ } -%>
21
51
  res.status(HTTP_STATUS.CREATED).json(user);
52
+ <%_ } -%>
22
53
  } catch (error) {
23
54
  res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: error.message });
24
55
  }
25
56
  };
26
57
 
27
58
  module.exports = { getUsers, createUser };
59
+
@@ -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, async () => {
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
- // - Write all logs with importance level of `error` or less to `error.log`
13
- // - Write all logs with importance level of `info` or less to `combined.log`
14
- //
15
- new winston.transports.File({ filename: 'error.log', level: 'error' }),
16
- new winston.transports.File({ filename: 'combined.log' }),
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
 
@@ -1,5 +1,4 @@
1
- <% if (communication === 'REST APIs') { %>
2
- import swaggerJsdoc from 'swagger-jsdoc';
1
+ <% if (communication === 'REST APIs') { %>import swaggerJsdoc from 'swagger-jsdoc';
3
2
 
4
3
  const options = {
5
4
  definition: {
@@ -2,13 +2,32 @@ import { Request, Response } from 'express';
2
2
  import User from '@/models/User';
3
3
  import { HTTP_STATUS } from '@/utils/httpCodes';
4
4
  import logger from '@/utils/logger';
5
+ <%_ if (caching === 'Redis') { -%>
6
+ import redisService from '@/config/redisClient';
7
+ <%_ } -%>
5
8
 
6
9
  export class UserController {
7
10
  async getUsers(req: Request, res: Response) {
8
11
  try {
9
- <% if (database === 'MongoDB') { %> const users = await User.find();
10
- <% } else { %> const users = await User.findAll();
11
- <% } -%>
12
+ <%_ if (caching === 'Redis') { -%>
13
+ const users = await redisService.getOrSet('users:all', async () => {
14
+ <%_ if (database === 'MongoDB') { -%>
15
+ return await User.find();
16
+ <%_ } else if (database === 'None') { -%>
17
+ return User.mockData;
18
+ <%_ } else { -%>
19
+ return await User.findAll();
20
+ <%_ } -%>
21
+ }, 60);
22
+ <%_ } else { -%>
23
+ <%_ if (database === 'MongoDB') { -%>
24
+ const users = await User.find();
25
+ <%_ } else if (database === 'None') { -%>
26
+ const users = User.mockData;
27
+ <%_ } else { -%>
28
+ const users = await User.findAll();
29
+ <%_ } -%>
30
+ <%_ } -%>
12
31
  res.json(users);
13
32
  } catch (error) {
14
33
  logger.error('Error fetching users:', error);
@@ -23,8 +42,20 @@ export class UserController {
23
42
  async createUser(req: Request, res: Response) {
24
43
  try {
25
44
  const { name, email } = req.body;
45
+ <%_ if (database === 'None') { -%>
46
+ const newUser = { id: String(User.mockData.length + 1), name, email };
47
+ User.mockData.push(newUser);
48
+ <%_ if (caching === 'Redis') { -%>
49
+ await redisService.del('users:all');
50
+ <%_ } -%>
51
+ res.status(HTTP_STATUS.CREATED).json(newUser);
52
+ <%_ } else { -%>
26
53
  const user = await User.create({ name, email });
54
+ <%_ if (caching === 'Redis') { -%>
55
+ await redisService.del('users:all');
56
+ <%_ } -%>
27
57
  res.status(HTTP_STATUS.CREATED).json(user);
58
+ <%_ } -%>
28
59
  } catch (error) {
29
60
  logger.error('Error creating user:', error);
30
61
  if (error instanceof Error) {
@@ -35,3 +66,4 @@ export class UserController {
35
66
  }
36
67
  }
37
68
  }
69
+
@@ -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, async () => {
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.File({ filename: 'error.log', level: 'error' }),
12
- new winston.transports.File({ filename: 'combined.log' }),
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