nodejs-quickstart-structure 1.18.1 → 1.19.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 (104) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +2 -1
  3. package/lib/modules/caching-setup.js +76 -73
  4. package/lib/modules/kafka-setup.js +249 -191
  5. package/lib/modules/project-setup.js +1 -0
  6. package/package.json +13 -2
  7. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  8. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  9. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  10. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  11. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  12. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  13. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  14. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  15. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  16. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  17. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  18. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  19. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  20. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  21. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  22. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  23. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  24. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  25. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  26. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  27. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  28. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  29. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  30. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  31. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  32. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  33. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  34. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  35. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  36. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  37. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  38. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  39. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  40. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  41. package/templates/common/.gitattributes +46 -0
  42. package/templates/common/README.md.ejs +294 -270
  43. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  44. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  45. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  46. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  47. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  48. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  49. package/templates/common/database/js/models/User.js.ejs +79 -53
  50. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  51. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  52. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  53. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  54. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  55. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  56. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  57. package/templates/common/jest.e2e.config.js.ejs +8 -8
  58. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  59. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  60. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  61. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  62. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  63. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  64. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  65. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  66. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  67. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  68. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  69. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  70. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  71. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  72. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  73. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  74. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  75. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  76. package/templates/common/swagger.yml.ejs +118 -66
  77. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  78. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  79. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  80. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  81. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  82. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  83. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  84. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  85. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  86. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  87. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  88. package/templates/mvc/js/src/routes/api.js +10 -8
  89. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  90. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  91. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  92. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  93. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  94. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  95. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  96. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  97. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  98. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  99. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  100. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  101. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  102. package/templates/mvc/ts/src/routes/api.ts +12 -10
  103. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  104. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
@@ -1,47 +1,50 @@
1
- const express = require('express');
2
- const router = express.Router();
3
- const logger = require('<% if (architecture === "MVC") { %>../utils/logger<% } else { %>../../infrastructure/log/logger<% } %>');
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
- <%_ } -%>
10
-
11
- router.get('/', async (req, res) => {
12
- const healthData = {
13
- status: 'UP',
14
- uptime: process.uptime(),
15
- memory: process.memoryUsage(),
16
- database: 'disconnected',
17
- timestamp: Date.now()
18
- };
19
- logger.info('Health Check');
20
-
21
- <%_ if (database !== 'None') { -%>
22
- try {
23
- <%_ if (database === 'MongoDB') { -%>
24
- if (mongoose.connection.readyState === 1) {
25
- if (mongoose.connection.db && mongoose.connection.db.admin) {
26
- await mongoose.connection.db.admin().ping();
27
- }
28
- healthData.database = 'connected';
29
- }
30
- <%_ } else { -%>
31
- await sequelize.authenticate();
32
- healthData.database = 'connected';
33
- <%_ } -%>
34
- } catch (err) {
35
- healthData.database = 'error';
36
- healthData.status = 'DOWN';
37
- logger.error('Health Check Database Ping Failed:', err);
38
- return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json(healthData);
39
- }
40
- <%_ } else { -%>
41
- healthData.database = 'None';
42
- <%_ } -%>
43
-
44
- res.status(HTTP_STATUS.OK).json(healthData);
45
- });
46
-
47
- module.exports = router;
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const logger = require('<% if (architecture === "MVC") { %>../utils/logger<% } else { %>../../infrastructure/log/logger<% } %>');
4
+ const HTTP_STATUS = require('<% if (architecture === "MVC") { %>../utils/httpCodes<% } else { %>../../utils/httpCodes<% } %>');
5
+ <%_ if (database !== 'None') { -%>
6
+ const ERROR_MESSAGES = require('<% if (architecture === "MVC") { %>../utils/errorMessages<% } else { %>../../utils/errorMessages<% } %>');
7
+ <%_ } -%>
8
+ <%_ if (database === 'MongoDB') { -%>
9
+ const mongoose = require('mongoose');
10
+ <%_ } else if (database !== 'None') { -%>
11
+ const sequelize = require('<% if (architecture === "MVC") { %>../config/database<% } else { %>../../infrastructure/database/database<% } %>');
12
+ <%_ } -%>
13
+
14
+ router.get('/', async (req, res) => {
15
+ const healthData = {
16
+ status: 'UP',
17
+ uptime: process.uptime(),
18
+ memory: process.memoryUsage(),
19
+ database: 'disconnected',
20
+ timestamp: Date.now()
21
+ };
22
+ logger.info('Health Check');
23
+
24
+ <%_ if (database !== 'None') { -%>
25
+ try {
26
+ <%_ if (database === 'MongoDB') { -%>
27
+ if (mongoose.connection.readyState === 1) {
28
+ if (mongoose.connection.db && mongoose.connection.db.admin) {
29
+ await mongoose.connection.db.admin().ping();
30
+ }
31
+ healthData.database = 'connected';
32
+ }
33
+ <%_ } else { -%>
34
+ await sequelize.authenticate();
35
+ healthData.database = 'connected';
36
+ <%_ } -%>
37
+ } catch (err) {
38
+ healthData.database = 'error';
39
+ healthData.status = 'DOWN';
40
+ logger.error(`${ERROR_MESSAGES.DATABASE_PING_FAILED}:`, err);
41
+ return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json(healthData);
42
+ }
43
+ <%_ } else { -%>
44
+ healthData.database = 'None';
45
+ <%_ } -%>
46
+
47
+ res.status(HTTP_STATUS.OK).json(healthData);
48
+ });
49
+
50
+ module.exports = router;
@@ -1,46 +1,49 @@
1
- import { Router, Request, Response } from 'express';
2
- import logger from '<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>';
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
- <%_ } -%>
9
-
10
- const router = Router();
11
-
12
- router.get('/', async (req: Request, res: Response) => {
13
- const healthData: Record<string, unknown> = {
14
- status: 'UP',
15
- uptime: process.uptime(),
16
- memory: process.memoryUsage(),
17
- database: 'disconnected',
18
- timestamp: Date.now()
19
- };
20
- logger.info('Health Check');
21
-
22
- <%_ if (database !== 'None') { -%>
23
- try {
24
- <%_ if (database === 'MongoDB') { -%>
25
- if (mongoose.connection.readyState === 1) {
26
- await mongoose.connection.db?.admin().ping();
27
- healthData.database = 'connected';
28
- }
29
- <%_ } else { -%>
30
- await sequelize.authenticate();
31
- healthData.database = 'connected';
32
- <%_ } -%>
33
- } catch (err) {
34
- healthData.database = 'error';
35
- healthData.status = 'DOWN';
36
- logger.error('Health Check Database Ping Failed:', err);
37
- return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json(healthData);
38
- }
39
- <%_ } else { -%>
40
- healthData.database = 'None';
41
- <%_ } -%>
42
-
43
- res.status(HTTP_STATUS.OK).json(healthData);
44
- });
45
-
46
- export default router;
1
+ import { Router, Request, Response } from 'express';
2
+ import logger from '<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>';
3
+ import { HTTP_STATUS } from '@/utils/httpCodes';
4
+ <%_ if (database !== 'None') { -%>
5
+ import { ERROR_MESSAGES } from '@/utils/errorMessages';
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
+
13
+ const router = Router();
14
+
15
+ router.get('/', async (req: Request, res: Response) => {
16
+ const healthData: Record<string, unknown> = {
17
+ status: 'UP',
18
+ uptime: process.uptime(),
19
+ memory: process.memoryUsage(),
20
+ database: 'disconnected',
21
+ timestamp: Date.now()
22
+ };
23
+ logger.info('Health Check');
24
+
25
+ <%_ if (database !== 'None') { -%>
26
+ try {
27
+ <%_ if (database === 'MongoDB') { -%>
28
+ if (mongoose.connection.readyState === 1) {
29
+ await mongoose.connection.db?.admin().ping();
30
+ healthData.database = 'connected';
31
+ }
32
+ <%_ } else { -%>
33
+ await sequelize.authenticate();
34
+ healthData.database = 'connected';
35
+ <%_ } -%>
36
+ } catch (err) {
37
+ healthData.database = 'error';
38
+ healthData.status = 'DOWN';
39
+ logger.error(`${ERROR_MESSAGES.DATABASE_PING_FAILED}:`, err);
40
+ return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json(healthData);
41
+ }
42
+ <%_ } else { -%>
43
+ healthData.database = 'None';
44
+ <%_ } -%>
45
+
46
+ res.status(HTTP_STATUS.OK).json(healthData);
47
+ });
48
+
49
+ export default router;
@@ -1,8 +1,8 @@
1
- <%_ if (language === 'TypeScript') { _%>/* eslint-disable @typescript-eslint/no-require-imports */<%_ } _%>
2
- module.exports = {
3
- ...require('./jest.config'),
4
- testMatch: ['<rootDir>/tests/e2e/**/*.test.ts', '<rootDir>/tests/e2e/**/*.test.js'],
5
- testPathIgnorePatterns: ['/node_modules/'],
6
- testTimeout: 30000,
7
- clearMocks: true
8
- };
1
+ <%_ if (language === 'TypeScript') { -%>/* eslint-disable @typescript-eslint/no-require-imports */<%_ } -%>
2
+ module.exports = {
3
+ ...require('./jest.config'),
4
+ testMatch: ['<rootDir>/tests/e2e/**/*.test.ts', '<rootDir>/tests/e2e/**/*.test.js'],
5
+ testPathIgnorePatterns: ['/node_modules/'],
6
+ testTimeout: 30000,
7
+ clearMocks: true
8
+ };
@@ -1,30 +1,30 @@
1
- const logger = require('<% if (architecture === "Clean Architecture") { %>../../infrastructure/log/logger<% } else { %>../utils/logger<% } %>');
2
-
3
- class BaseConsumer {
4
- constructor() {
5
- if (this.constructor === BaseConsumer) {
6
- throw new Error("Abstract class 'BaseConsumer' cannot be instantiated.");
7
- }
8
- }
9
-
10
- get topic() { throw new Error("Property 'topic' must be implemented"); }
11
- get groupId() { throw new Error("Property 'groupId' must be implemented"); }
12
-
13
- async onMessage({ message }) {
14
- try {
15
- const rawValue = message.value?.toString();
16
- if (!rawValue) return;
17
-
18
- const data = JSON.parse(rawValue);
19
- await this.handle(data);
20
- } catch (error) {
21
- logger.error(`[Kafka] Error processing message on topic ${this.topic}:`, error);
22
- }
23
- }
24
-
25
- async handle(data) {
26
- throw new Error("Method 'handle()' must be implemented");
27
- }
28
- }
29
-
30
- module.exports = BaseConsumer;
1
+ const logger = require('<%- loggerPath %>');
2
+
3
+ class BaseConsumer {
4
+ constructor() {
5
+ if (this.constructor === BaseConsumer) {
6
+ throw new Error("Abstract class 'BaseConsumer' cannot be instantiated.");
7
+ }
8
+ }
9
+
10
+ get topic() { throw new Error("Property 'topic' must be implemented"); }
11
+ get groupId() { throw new Error("Property 'groupId' must be implemented"); }
12
+
13
+ async onMessage({ message }) {
14
+ try {
15
+ const rawValue = message.value?.toString();
16
+ if (!rawValue) return;
17
+
18
+ const data = JSON.parse(rawValue);
19
+ await this.handle(data);
20
+ } catch (error) {
21
+ logger.error(`[Kafka] Error processing message on topic ${this.topic}:`, error);
22
+ }
23
+ }
24
+
25
+ async handle(data) {
26
+ throw new Error("Method 'handle()' must be implemented");
27
+ }
28
+ }
29
+
30
+ module.exports = BaseConsumer;
@@ -1,11 +1,12 @@
1
- const { z } = require('zod');
2
-
3
- const UserEventSchema = z.object({
4
- action: z.enum(['USER_CREATED', 'UPDATE_USER', 'DELETE_USER']),
5
- payload: z.object({
6
- id: z.union([z.string(), z.number()]),
7
- email: z.string().email(),
8
- }),
9
- });
10
-
11
- module.exports = { UserEventSchema };
1
+ const { z } = require('zod');
2
+ const { KAFKA_ACTIONS } = require('<%- kafkaEventsPath %>');
3
+
4
+ const UserEventSchema = z.object({
5
+ action: z.enum(Object.values(KAFKA_ACTIONS)),
6
+ payload: z.object({
7
+ id: z.union([z.string(), z.number()]),
8
+ email: z.string().email().optional(),
9
+ }),
10
+ });
11
+
12
+ module.exports = { UserEventSchema };
@@ -1,31 +1,44 @@
1
- const BaseConsumer = require('../../baseConsumer');
2
- const logger = require('<% if (architecture === "Clean Architecture") { %>../../../../infrastructure/log/logger<% } else { %>../../../utils/logger<% } %>');
3
- const { UserEventSchema } = require('../../schemas/userEventSchema');
4
-
5
- class WelcomeEmailConsumer extends BaseConsumer {
6
- constructor() {
7
- super();
8
- }
9
-
10
- get topic() { return 'user-topic'; }
11
- get groupId() { return 'welcome-email-group'; }
12
-
13
- async handle(data) {
14
- const result = UserEventSchema.safeParse(data);
15
-
16
- if (!result.success) {
17
- logger.error('[Kafka] Invalid user event data:', result.error.format());
18
- return;
19
- }
20
-
21
- const { action, payload } = result.data;
22
-
23
- if (action === 'USER_CREATED') {
24
- logger.info(`[Kafka] Consumer: Received USER_CREATED.`);
25
- logger.info(`[Kafka] Consumer: 📧 Sending welcome email to '${payload.email}'... Done!`);
26
- // In a real app, you would call an EmailService here
27
- }
28
- }
29
- }
30
-
31
- module.exports = WelcomeEmailConsumer;
1
+ const BaseConsumer = require('<%- baseConsumerPath %>');
2
+ const logger = require('<%- loggerPath %>');
3
+ const { UserEventSchema } = require('<%- userEventSchemaPath %>');
4
+ const ERROR_MESSAGES = require('<%- errorMessagesPath %>');
5
+ const { KAFKA_ACTIONS } = require('<%- kafkaEventsPath %>');
6
+
7
+ class WelcomeEmailConsumer extends BaseConsumer {
8
+ constructor() {
9
+ super();
10
+ }
11
+
12
+ get topic() { return 'user-topic'; }
13
+ get groupId() { return 'welcome-email-group'; }
14
+
15
+ async handle(data) {
16
+ const result = UserEventSchema.safeParse(data);
17
+
18
+ if (!result.success) {
19
+ logger.error(`[Kafka] ${ERROR_MESSAGES.INVALID_USER_DATA}:`, result.error.format());
20
+ return;
21
+ }
22
+
23
+ const { action, payload } = result.data;
24
+
25
+ switch (action) {
26
+ case KAFKA_ACTIONS.USER_CREATED:
27
+ logger.info(`[Kafka] Consumer: Received ${KAFKA_ACTIONS.USER_CREATED}.`);
28
+ logger.info(`[Kafka] Consumer: 📧 Sending welcome email to '${payload.email}'... Done!`);
29
+ break;
30
+ case KAFKA_ACTIONS.USER_UPDATED:
31
+ logger.info(`[Kafka] Consumer: Received ${KAFKA_ACTIONS.USER_UPDATED}.`);
32
+ logger.info(`[Kafka] Consumer: 🔄 Updating user records for '${payload.id}' (Email: ${payload.email})... Done!`);
33
+ break;
34
+ case KAFKA_ACTIONS.USER_DELETED:
35
+ logger.info(`[Kafka] Consumer: Received ${KAFKA_ACTIONS.USER_DELETED}.`);
36
+ logger.info(`[Kafka] Consumer: 🗑️ Cleaning up data for user '${payload.id}'... Done!`);
37
+ break;
38
+ default:
39
+ logger.warn(`[Kafka] Unknown action: ${action}`);
40
+ }
41
+ }
42
+ }
43
+
44
+ module.exports = WelcomeEmailConsumer;
@@ -1,49 +1,86 @@
1
- const WelcomeEmailConsumer = require('<% if (architecture === "Clean Architecture") { %>@/interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>@/messaging/consumers/instances/welcomeEmailConsumer<% } %>');
2
- const logger = require('<% if (architecture === "Clean Architecture") { %>@/infrastructure/log/logger<% } else { %>@/utils/logger<% } %>');
3
-
4
- jest.mock('<% if (architecture === "Clean Architecture") { %>@/infrastructure/log/logger<% } else { %>@/utils/logger<% } %>');
5
-
6
- describe('WelcomeEmailConsumer', () => {
7
- let consumer;
8
-
9
- beforeEach(() => {
10
- jest.clearAllMocks();
11
- consumer = new WelcomeEmailConsumer();
12
- });
13
-
14
- it('should log welcome email simulation for USER_CREATED action', async () => {
15
- const data = {
16
- action: 'USER_CREATED',
17
- payload: {
18
- id: 1,
19
- email: 'test@example.com'
20
- }
21
- };
22
-
23
- await consumer.handle(data);
24
-
25
- expect(logger.info).toHaveBeenCalledWith(
26
- expect.stringContaining('[Kafka] Consumer: Received USER_CREATED.')
27
- );
28
- expect(logger.info).toHaveBeenCalledWith(
29
- expect.stringContaining('📧 Sending welcome email to \'test@example.com\'... Done!')
30
- );
31
- });
32
-
33
- it('should log error for invalid data', async () => {
34
- const data = {
35
- action: 'USER_CREATED',
36
- payload: {
37
- id: 1,
38
- email: 'invalid-email'
39
- }
40
- };
41
-
42
- await consumer.handle(data);
43
-
44
- expect(logger.error).toHaveBeenCalledWith(
45
- expect.stringContaining('[Kafka] Invalid user event data:'),
46
- expect.anything()
47
- );
48
- });
49
- });
1
+ const WelcomeEmailConsumer = require('<% if (architecture === "Clean Architecture") { %>@/interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>@/messaging/consumers/instances/welcomeEmailConsumer<% } %>');
2
+ const logger = require('<% if (architecture === "Clean Architecture") { %>@/infrastructure/log/logger<% } else { %>@/utils/logger<% } %>');
3
+
4
+ jest.mock('<% if (architecture === "Clean Architecture") { %>@/infrastructure/log/logger<% } else { %>@/utils/logger<% } %>');
5
+
6
+ describe('WelcomeEmailConsumer', () => {
7
+ let consumer;
8
+
9
+ beforeEach(() => {
10
+ jest.clearAllMocks();
11
+ consumer = new WelcomeEmailConsumer();
12
+ });
13
+
14
+ it('should log welcome email simulation for USER_CREATED action', async () => {
15
+ const data = {
16
+ action: 'USER_CREATED',
17
+ payload: {
18
+ id: 1,
19
+ email: 'test@example.com'
20
+ }
21
+ };
22
+
23
+ await consumer.handle(data);
24
+
25
+ expect(logger.info).toHaveBeenCalledWith(
26
+ expect.stringContaining('[Kafka] Consumer: Received USER_CREATED.')
27
+ );
28
+ expect(logger.info).toHaveBeenCalledWith(
29
+ expect.stringContaining('📧 Sending welcome email to \'test@example.com\'... Done!')
30
+ );
31
+ });
32
+
33
+ it('should log update simulation for USER_UPDATED action', async () => {
34
+ const data = {
35
+ action: 'USER_UPDATED',
36
+ payload: {
37
+ id: 1,
38
+ email: 'updated@example.com'
39
+ }
40
+ };
41
+
42
+ await consumer.handle(data);
43
+
44
+ expect(logger.info).toHaveBeenCalledWith(
45
+ expect.stringContaining('[Kafka] Consumer: Received USER_UPDATED.')
46
+ );
47
+ expect(logger.info).toHaveBeenCalledWith(
48
+ expect.stringContaining('🔄 Updating user records for \'1\' (Email: updated@example.com)... Done!')
49
+ );
50
+ });
51
+
52
+ it('should log deletion simulation for USER_DELETED action', async () => {
53
+ const data = {
54
+ action: 'USER_DELETED',
55
+ payload: {
56
+ id: 1
57
+ }
58
+ };
59
+
60
+ await consumer.handle(data);
61
+
62
+ expect(logger.info).toHaveBeenCalledWith(
63
+ expect.stringContaining('[Kafka] Consumer: Received USER_DELETED.')
64
+ );
65
+ expect(logger.info).toHaveBeenCalledWith(
66
+ expect.stringContaining('🗑️ Cleaning up data for user \'1\'... Done!')
67
+ );
68
+ });
69
+
70
+ it('should log error for invalid data', async () => {
71
+ const data = {
72
+ action: 'USER_CREATED',
73
+ payload: {
74
+ id: 1,
75
+ email: 'invalid-email'
76
+ }
77
+ };
78
+
79
+ await consumer.handle(data);
80
+
81
+ expect(logger.error).toHaveBeenCalledWith(
82
+ expect.stringContaining('[Kafka] Invalid user event data:'),
83
+ expect.anything()
84
+ );
85
+ });
86
+ });