nodejs-quickstart-structure 1.19.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +320 -301
- package/LICENSE +15 -15
- package/README.md +45 -10
- package/bin/index.js +7 -1
- package/lib/generator.js +139 -139
- package/lib/modules/app-setup.js +401 -401
- package/lib/modules/config-files.js +151 -151
- package/lib/modules/database-setup.js +116 -116
- package/lib/modules/project-setup.js +32 -32
- package/lib/prompts.js +100 -100
- package/package.json +79 -78
- package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
- package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
- package/templates/clean-architecture/js/src/index.js.ejs +55 -55
- package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
- package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
- package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
- package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
- package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
- package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
- package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
- package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
- package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
- package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
- package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
- package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
- package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
- package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
- package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
- package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
- package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
- package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
- package/templates/common/.cursorrules.ejs +60 -60
- package/templates/common/.dockerignore +12 -12
- package/templates/common/.env.example.ejs +41 -41
- package/templates/common/.gitlab-ci.yml.ejs +86 -86
- package/templates/common/.lintstagedrc +6 -6
- package/templates/common/.prettierrc +7 -7
- package/templates/common/Dockerfile +73 -73
- package/templates/common/Jenkinsfile.ejs +87 -87
- package/templates/common/SECURITY.md +20 -20
- package/templates/common/_github/workflows/ci.yml.ejs +46 -46
- package/templates/common/_github/workflows/security.yml.ejs +36 -36
- package/templates/common/_gitignore +5 -5
- package/templates/common/_husky/pre-commit +4 -4
- package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
- package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
- package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
- package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
- package/templates/common/caching/js/memoryCache.js.ejs +60 -60
- package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
- package/templates/common/caching/js/redisClient.js.ejs +75 -75
- package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
- package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
- package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
- package/templates/common/database/js/database.js.ejs +19 -19
- package/templates/common/database/js/database.spec.js.ejs +56 -56
- package/templates/common/database/js/mongoose.js.ejs +33 -33
- package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
- package/templates/common/database/ts/database.spec.ts.ejs +56 -56
- package/templates/common/database/ts/database.ts.ejs +21 -21
- package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
- package/templates/common/database/ts/mongoose.ts.ejs +28 -28
- package/templates/common/docker-compose.yml.ejs +159 -159
- package/templates/common/ecosystem.config.js.ejs +40 -40
- package/templates/common/eslint.config.mjs.ejs +77 -77
- package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
- package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
- package/templates/common/jest.config.js.ejs +32 -32
- package/templates/common/kafka/js/config/kafka.js +9 -9
- package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
- package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
- package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
- package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
- package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
- package/templates/common/kafka/ts/config/kafka.ts +7 -7
- package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
- package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
- package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
- package/templates/common/migrate-mongo-config.js.ejs +31 -31
- package/templates/common/migrations/init.js.ejs +23 -23
- package/templates/common/package.json.ejs +119 -118
- package/templates/common/prompts/add-feature.md.ejs +26 -26
- package/templates/common/prompts/project-context.md.ejs +43 -43
- package/templates/common/prompts/troubleshoot.md.ejs +28 -28
- package/templates/common/public/css/style.css +147 -147
- package/templates/common/scripts/run-e2e.js.ejs +63 -63
- package/templates/common/sonar-project.properties.ejs +27 -27
- package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
- package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
- package/templates/common/tsconfig.json +22 -22
- package/templates/common/views/ejs/index.ejs +55 -55
- package/templates/common/views/pug/index.pug +40 -40
- package/templates/mvc/js/src/config/env.js.ejs +46 -46
- package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
- package/templates/mvc/js/src/errors/ApiError.js +14 -14
- package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
- package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
- package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
- package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
- package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/mvc/js/src/index.js.ejs +136 -136
- package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
- package/templates/mvc/js/src/utils/httpCodes.js +9 -9
- package/templates/mvc/js/src/utils/logger.js +40 -40
- package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
- package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
- package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
- package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
- package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
- package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
- package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
- package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
- package/templates/mvc/ts/src/utils/logger.ts +36 -36
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
:root {
|
|
2
|
-
--primary-color: #4f46e5;
|
|
3
|
-
--primary-hover: #4338ca;
|
|
4
|
-
--bg-color: #f9fafb;
|
|
5
|
-
--card-bg: #ffffff;
|
|
6
|
-
--text-main: #111827;
|
|
7
|
-
--text-muted: #6b7280;
|
|
8
|
-
--success-color: #10b981;
|
|
9
|
-
--border-color: #e5e7eb;
|
|
10
|
-
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
11
|
-
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
body {
|
|
15
|
-
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
16
|
-
background-color: var(--bg-color);
|
|
17
|
-
color: var(--text-main);
|
|
18
|
-
margin: 0;
|
|
19
|
-
padding: 0;
|
|
20
|
-
line-height: 1.5;
|
|
21
|
-
display: flex;
|
|
22
|
-
justify-content: center;
|
|
23
|
-
min-height: 100vh;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.container {
|
|
27
|
-
width: 100%;
|
|
28
|
-
max-width: 800px;
|
|
29
|
-
padding: 40px 20px;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.header {
|
|
33
|
-
text-align: center;
|
|
34
|
-
margin-bottom: 40px;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.logo {
|
|
38
|
-
font-size: 3rem;
|
|
39
|
-
margin-bottom: 10px;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
h1 {
|
|
43
|
-
font-size: 2.5rem;
|
|
44
|
-
font-weight: 800;
|
|
45
|
-
color: var(--text-main);
|
|
46
|
-
margin: 0 0 10px 0;
|
|
47
|
-
letter-spacing: -0.025em;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.subtitle {
|
|
51
|
-
color: var(--text-muted);
|
|
52
|
-
font-size: 1.125rem;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.card-grid {
|
|
56
|
-
display: grid;
|
|
57
|
-
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
|
58
|
-
gap: 20px;
|
|
59
|
-
margin-bottom: 40px;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.card {
|
|
63
|
-
background: var(--card-bg);
|
|
64
|
-
padding: 24px;
|
|
65
|
-
border-radius: 12px;
|
|
66
|
-
box-shadow: var(--shadow-sm);
|
|
67
|
-
border: 1px solid var(--border-color);
|
|
68
|
-
transition: transform 0.2s, box-shadow 0.2s;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.card:hover {
|
|
72
|
-
transform: translateY(-2px);
|
|
73
|
-
box-shadow: var(--shadow-md);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.card h3 {
|
|
77
|
-
margin-top: 0;
|
|
78
|
-
font-size: 0.875rem;
|
|
79
|
-
text-transform: uppercase;
|
|
80
|
-
letter-spacing: 0.05em;
|
|
81
|
-
color: var(--text-muted);
|
|
82
|
-
font-weight: 600;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.card p {
|
|
86
|
-
font-size: 1.25rem;
|
|
87
|
-
font-weight: 600;
|
|
88
|
-
color: var(--text-main);
|
|
89
|
-
margin: 5px 0 0 0;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.status-card {
|
|
93
|
-
background: var(--card-bg);
|
|
94
|
-
border-radius: 12px;
|
|
95
|
-
padding: 24px;
|
|
96
|
-
box-shadow: var(--shadow-md);
|
|
97
|
-
border-left: 6px solid var(--success-color);
|
|
98
|
-
display: flex;
|
|
99
|
-
align-items: center;
|
|
100
|
-
gap: 20px;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.status-icon {
|
|
104
|
-
background: #d1fae5;
|
|
105
|
-
color: var(--success-color);
|
|
106
|
-
width: 48px;
|
|
107
|
-
height: 48px;
|
|
108
|
-
border-radius: 50%;
|
|
109
|
-
display: flex;
|
|
110
|
-
align-items: center;
|
|
111
|
-
justify-content: center;
|
|
112
|
-
font-size: 1.5rem;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.status-content h3 {
|
|
116
|
-
margin: 0;
|
|
117
|
-
font-size: 1.25rem;
|
|
118
|
-
font-weight: 700;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.status-content p {
|
|
122
|
-
margin: 5px 0 0 0;
|
|
123
|
-
color: var(--text-muted);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.action-btn {
|
|
127
|
-
display: inline-block;
|
|
128
|
-
margin-top: 40px;
|
|
129
|
-
background-color: var(--primary-color);
|
|
130
|
-
color: white;
|
|
131
|
-
padding: 12px 24px;
|
|
132
|
-
border-radius: 8px;
|
|
133
|
-
text-decoration: none;
|
|
134
|
-
font-weight: 600;
|
|
135
|
-
transition: background-color 0.2s;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.action-btn:hover {
|
|
139
|
-
background-color: var(--primary-hover);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
footer {
|
|
143
|
-
margin-top: 60px;
|
|
144
|
-
text-align: center;
|
|
145
|
-
color: var(--text-muted);
|
|
146
|
-
font-size: 0.875rem;
|
|
147
|
-
}
|
|
1
|
+
:root {
|
|
2
|
+
--primary-color: #4f46e5;
|
|
3
|
+
--primary-hover: #4338ca;
|
|
4
|
+
--bg-color: #f9fafb;
|
|
5
|
+
--card-bg: #ffffff;
|
|
6
|
+
--text-main: #111827;
|
|
7
|
+
--text-muted: #6b7280;
|
|
8
|
+
--success-color: #10b981;
|
|
9
|
+
--border-color: #e5e7eb;
|
|
10
|
+
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
11
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
16
|
+
background-color: var(--bg-color);
|
|
17
|
+
color: var(--text-main);
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
line-height: 1.5;
|
|
21
|
+
display: flex;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
min-height: 100vh;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.container {
|
|
27
|
+
width: 100%;
|
|
28
|
+
max-width: 800px;
|
|
29
|
+
padding: 40px 20px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.header {
|
|
33
|
+
text-align: center;
|
|
34
|
+
margin-bottom: 40px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.logo {
|
|
38
|
+
font-size: 3rem;
|
|
39
|
+
margin-bottom: 10px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
h1 {
|
|
43
|
+
font-size: 2.5rem;
|
|
44
|
+
font-weight: 800;
|
|
45
|
+
color: var(--text-main);
|
|
46
|
+
margin: 0 0 10px 0;
|
|
47
|
+
letter-spacing: -0.025em;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.subtitle {
|
|
51
|
+
color: var(--text-muted);
|
|
52
|
+
font-size: 1.125rem;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.card-grid {
|
|
56
|
+
display: grid;
|
|
57
|
+
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
|
58
|
+
gap: 20px;
|
|
59
|
+
margin-bottom: 40px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.card {
|
|
63
|
+
background: var(--card-bg);
|
|
64
|
+
padding: 24px;
|
|
65
|
+
border-radius: 12px;
|
|
66
|
+
box-shadow: var(--shadow-sm);
|
|
67
|
+
border: 1px solid var(--border-color);
|
|
68
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.card:hover {
|
|
72
|
+
transform: translateY(-2px);
|
|
73
|
+
box-shadow: var(--shadow-md);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.card h3 {
|
|
77
|
+
margin-top: 0;
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
text-transform: uppercase;
|
|
80
|
+
letter-spacing: 0.05em;
|
|
81
|
+
color: var(--text-muted);
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.card p {
|
|
86
|
+
font-size: 1.25rem;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
color: var(--text-main);
|
|
89
|
+
margin: 5px 0 0 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.status-card {
|
|
93
|
+
background: var(--card-bg);
|
|
94
|
+
border-radius: 12px;
|
|
95
|
+
padding: 24px;
|
|
96
|
+
box-shadow: var(--shadow-md);
|
|
97
|
+
border-left: 6px solid var(--success-color);
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 20px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.status-icon {
|
|
104
|
+
background: #d1fae5;
|
|
105
|
+
color: var(--success-color);
|
|
106
|
+
width: 48px;
|
|
107
|
+
height: 48px;
|
|
108
|
+
border-radius: 50%;
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
justify-content: center;
|
|
112
|
+
font-size: 1.5rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.status-content h3 {
|
|
116
|
+
margin: 0;
|
|
117
|
+
font-size: 1.25rem;
|
|
118
|
+
font-weight: 700;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.status-content p {
|
|
122
|
+
margin: 5px 0 0 0;
|
|
123
|
+
color: var(--text-muted);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.action-btn {
|
|
127
|
+
display: inline-block;
|
|
128
|
+
margin-top: 40px;
|
|
129
|
+
background-color: var(--primary-color);
|
|
130
|
+
color: white;
|
|
131
|
+
padding: 12px 24px;
|
|
132
|
+
border-radius: 8px;
|
|
133
|
+
text-decoration: none;
|
|
134
|
+
font-weight: 600;
|
|
135
|
+
transition: background-color 0.2s;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.action-btn:hover {
|
|
139
|
+
background-color: var(--primary-hover);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
footer {
|
|
143
|
+
margin-top: 60px;
|
|
144
|
+
text-align: center;
|
|
145
|
+
color: var(--text-muted);
|
|
146
|
+
font-size: 0.875rem;
|
|
147
|
+
}
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
const { execSync } = require('child_process');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
// Set a specific port for E2E tests to avoid collisions with local development
|
|
6
|
-
process.env.PORT = '3001';
|
|
7
|
-
const TEST_PORT = process.env.PORT;
|
|
8
|
-
|
|
9
|
-
const execute = (command) => {
|
|
10
|
-
console.log(`\n> ${command}`);
|
|
11
|
-
// Run commands from the project root instead of the scripts folder
|
|
12
|
-
execSync(command, { stdio: 'inherit', cwd: path.resolve(__dirname, '../') });
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
let composeCmd = 'docker-compose';
|
|
16
|
-
try {
|
|
17
|
-
execSync('docker compose version', { stdio: 'ignore' });
|
|
18
|
-
composeCmd = 'docker compose';
|
|
19
|
-
} catch (e) {
|
|
20
|
-
// fallback to docker-compose
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let currentProcessStartedDocker = false;
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
let isAlreadyUp = false;
|
|
27
|
-
try {
|
|
28
|
-
// Silently check if the endpoint is already live (1.5-second timeout)
|
|
29
|
-
execSync(`npx wait-on http-get://127.0.0.1:${TEST_PORT}/health -t 1500`, {
|
|
30
|
-
stdio: 'ignore',
|
|
31
|
-
cwd: path.resolve(__dirname, '../')
|
|
32
|
-
});
|
|
33
|
-
isAlreadyUp = true;
|
|
34
|
-
} catch (e) {
|
|
35
|
-
isAlreadyUp = false;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (isAlreadyUp) {
|
|
39
|
-
console.log('Infrastructure is already running! Skipping Docker spin-up...');
|
|
40
|
-
} else {
|
|
41
|
-
console.log(`Starting Docker Compose infrastructure using '${composeCmd}'...`);
|
|
42
|
-
execute(`${composeCmd} up -d --build`);
|
|
43
|
-
currentProcessStartedDocker = true;
|
|
44
|
-
|
|
45
|
-
console.log('Waiting for application healthcheck to turn green (120s timeout)...');
|
|
46
|
-
// Using wait-on to poll the universal /health endpoint injected into all architectures
|
|
47
|
-
execute(`npx wait-on http-get://127.0.0.1:${TEST_PORT}/health -t 120000`);
|
|
48
|
-
console.log('Infrastructure is healthy!');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
console.log('Running E2E tests...');
|
|
52
|
-
execute('npm run test:e2e:run');
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.error('E2E tests failed or infrastructure did not boot in time.');
|
|
55
|
-
process.exitCode = 1;
|
|
56
|
-
} finally {
|
|
57
|
-
if (currentProcessStartedDocker) {
|
|
58
|
-
console.log('Tearing down isolated Docker Compose infrastructure...');
|
|
59
|
-
execute(`${composeCmd} down`);
|
|
60
|
-
} else {
|
|
61
|
-
console.log('Leaving preexisting infrastructure running.');
|
|
62
|
-
}
|
|
63
|
-
}
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
// Set a specific port for E2E tests to avoid collisions with local development
|
|
6
|
+
process.env.PORT = '3001';
|
|
7
|
+
const TEST_PORT = process.env.PORT;
|
|
8
|
+
|
|
9
|
+
const execute = (command) => {
|
|
10
|
+
console.log(`\n> ${command}`);
|
|
11
|
+
// Run commands from the project root instead of the scripts folder
|
|
12
|
+
execSync(command, { stdio: 'inherit', cwd: path.resolve(__dirname, '../') });
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let composeCmd = 'docker-compose';
|
|
16
|
+
try {
|
|
17
|
+
execSync('docker compose version', { stdio: 'ignore' });
|
|
18
|
+
composeCmd = 'docker compose';
|
|
19
|
+
} catch (e) {
|
|
20
|
+
// fallback to docker-compose
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let currentProcessStartedDocker = false;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
let isAlreadyUp = false;
|
|
27
|
+
try {
|
|
28
|
+
// Silently check if the endpoint is already live (1.5-second timeout)
|
|
29
|
+
execSync(`npx wait-on http-get://127.0.0.1:${TEST_PORT}/health -t 1500`, {
|
|
30
|
+
stdio: 'ignore',
|
|
31
|
+
cwd: path.resolve(__dirname, '../')
|
|
32
|
+
});
|
|
33
|
+
isAlreadyUp = true;
|
|
34
|
+
} catch (e) {
|
|
35
|
+
isAlreadyUp = false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isAlreadyUp) {
|
|
39
|
+
console.log('Infrastructure is already running! Skipping Docker spin-up...');
|
|
40
|
+
} else {
|
|
41
|
+
console.log(`Starting Docker Compose infrastructure using '${composeCmd}'...`);
|
|
42
|
+
execute(`${composeCmd} up -d --build`);
|
|
43
|
+
currentProcessStartedDocker = true;
|
|
44
|
+
|
|
45
|
+
console.log('Waiting for application healthcheck to turn green (120s timeout)...');
|
|
46
|
+
// Using wait-on to poll the universal /health endpoint injected into all architectures
|
|
47
|
+
execute(`npx wait-on http-get://127.0.0.1:${TEST_PORT}/health -t 120000`);
|
|
48
|
+
console.log('Infrastructure is healthy!');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log('Running E2E tests...');
|
|
52
|
+
execute('npm run test:e2e:run');
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('E2E tests failed or infrastructure did not boot in time.');
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
} finally {
|
|
57
|
+
if (currentProcessStartedDocker) {
|
|
58
|
+
console.log('Tearing down isolated Docker Compose infrastructure...');
|
|
59
|
+
execute(`${composeCmd} down`);
|
|
60
|
+
} else {
|
|
61
|
+
console.log('Leaving preexisting infrastructure running.');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
# SonarCloud/SonarQube Project Configuration
|
|
2
|
-
# See https://docs.sonarqube.org/latest/analysis/analysis-parameters/
|
|
3
|
-
|
|
4
|
-
sonar.projectKey=your-org-key_<%= projectName %>
|
|
5
|
-
sonar.projectName=<%= projectName %>
|
|
6
|
-
sonar.organization=your-org-key
|
|
7
|
-
sonar.projectVersion=1.0.0
|
|
8
|
-
|
|
9
|
-
# Path to the source directories
|
|
10
|
-
sonar.sources=src
|
|
11
|
-
# Path to the test directories
|
|
12
|
-
sonar.tests=tests
|
|
13
|
-
|
|
14
|
-
# Language specific settings
|
|
15
|
-
sonar.javascript.environments=node
|
|
16
|
-
sonar.typescript.tsconfigPath=tsconfig.json
|
|
17
|
-
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
|
18
|
-
|
|
19
|
-
# Exclusions
|
|
20
|
-
sonar.exclusions=node_modules/**, dist/**, coverage/**, tests/**
|
|
21
|
-
|
|
22
|
-
# Quality Gates
|
|
23
|
-
sonar.qualitygate.wait=true
|
|
24
|
-
sonar.qualitygate.timeout=300
|
|
25
|
-
|
|
26
|
-
# Security Hotspots
|
|
27
|
-
sonar.security.reportPaths=snyk-report.json
|
|
1
|
+
# SonarCloud/SonarQube Project Configuration
|
|
2
|
+
# See https://docs.sonarqube.org/latest/analysis/analysis-parameters/
|
|
3
|
+
|
|
4
|
+
sonar.projectKey=your-org-key_<%= projectName %>
|
|
5
|
+
sonar.projectName=<%= projectName %>
|
|
6
|
+
sonar.organization=your-org-key
|
|
7
|
+
sonar.projectVersion=1.0.0
|
|
8
|
+
|
|
9
|
+
# Path to the source directories
|
|
10
|
+
sonar.sources=src
|
|
11
|
+
# Path to the test directories
|
|
12
|
+
sonar.tests=tests
|
|
13
|
+
|
|
14
|
+
# Language specific settings
|
|
15
|
+
sonar.javascript.environments=node
|
|
16
|
+
sonar.typescript.tsconfigPath=tsconfig.json
|
|
17
|
+
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
|
18
|
+
|
|
19
|
+
# Exclusions
|
|
20
|
+
sonar.exclusions=node_modules/**, dist/**, coverage/**, tests/**
|
|
21
|
+
|
|
22
|
+
# Quality Gates
|
|
23
|
+
sonar.qualitygate.wait=true
|
|
24
|
+
sonar.qualitygate.timeout=300
|
|
25
|
+
|
|
26
|
+
# Security Hotspots
|
|
27
|
+
sonar.security.reportPaths=snyk-report.json
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
const { errorMiddleware } = require('<% if (architecture === "MVC") { %>@/utils/errorMiddleware<% } else { %>@/infrastructure/webserver/middleware/errorMiddleware<% } %>');
|
|
2
|
-
const { ApiError } = require('@/errors/ApiError');
|
|
3
|
-
const HTTP_STATUS = require('@/utils/httpCodes');
|
|
4
|
-
const logger = require('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
|
|
5
|
-
|
|
6
|
-
jest.mock('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
|
|
7
|
-
|
|
8
|
-
describe('Error Middleware', () => {
|
|
9
|
-
let mockRequest;
|
|
10
|
-
let mockResponse;
|
|
11
|
-
let nextFunction;
|
|
12
|
-
const originalEnv = process.env.NODE_ENV;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
mockRequest = {
|
|
16
|
-
originalUrl: '/test',
|
|
17
|
-
method: 'GET',
|
|
18
|
-
ip: '127.0.0.1'
|
|
19
|
-
};
|
|
20
|
-
mockResponse = {
|
|
21
|
-
status: jest.fn().mockReturnThis(),
|
|
22
|
-
json: jest.fn()
|
|
23
|
-
};
|
|
24
|
-
nextFunction = jest.fn();
|
|
25
|
-
jest.clearAllMocks();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
afterEach(() => {
|
|
29
|
-
process.env.NODE_ENV = originalEnv;
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should handle standard Error by wrapping it in a 500 ApiError', () => {
|
|
33
|
-
const error = new Error('Standard Error');
|
|
34
|
-
errorMiddleware(error, mockRequest, mockResponse, nextFunction);
|
|
35
|
-
|
|
36
|
-
expect(logger.error).toHaveBeenCalled();
|
|
37
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.INTERNAL_SERVER_ERROR);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should handle custom ApiError directly', () => {
|
|
41
|
-
const customError = new ApiError(HTTP_STATUS.BAD_REQUEST, 'Bad Request Data', true);
|
|
42
|
-
errorMiddleware(customError, mockRequest, mockResponse, nextFunction);
|
|
43
|
-
|
|
44
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.BAD_REQUEST);
|
|
45
|
-
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
46
|
-
statusCode: HTTP_STATUS.BAD_REQUEST,
|
|
47
|
-
message: 'Bad Request Data'
|
|
48
|
-
}));
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should include stack trace in development environment', () => {
|
|
52
|
-
process.env.NODE_ENV = 'development';
|
|
53
|
-
const error = new Error('Test Error');
|
|
54
|
-
errorMiddleware(error, mockRequest, mockResponse, nextFunction);
|
|
55
|
-
|
|
56
|
-
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
57
|
-
stack: expect.any(String)
|
|
58
|
-
}));
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should omit stack trace in production environment', () => {
|
|
62
|
-
process.env.NODE_ENV = 'production';
|
|
63
|
-
const error = new Error('Test Error');
|
|
64
|
-
errorMiddleware(error, mockRequest, mockResponse, nextFunction);
|
|
65
|
-
|
|
66
|
-
const jsonArg = mockResponse.json.mock.calls[0][0];
|
|
67
|
-
expect(jsonArg.stack).toBeUndefined();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should handle error without stack trace', () => {
|
|
71
|
-
const { ApiError } = require('@/errors/ApiError');
|
|
72
|
-
const customError = new ApiError(500, 'No Stack', false);
|
|
73
|
-
delete customError.stack;
|
|
74
|
-
errorMiddleware(customError, mockRequest, mockResponse, nextFunction);
|
|
75
|
-
|
|
76
|
-
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('No Stack'));
|
|
77
|
-
expect(logger.error).toHaveBeenCalledWith('No stack trace');
|
|
78
|
-
});
|
|
79
|
-
});
|
|
1
|
+
const { errorMiddleware } = require('<% if (architecture === "MVC") { %>@/utils/errorMiddleware<% } else { %>@/infrastructure/webserver/middleware/errorMiddleware<% } %>');
|
|
2
|
+
const { ApiError } = require('@/errors/ApiError');
|
|
3
|
+
const HTTP_STATUS = require('@/utils/httpCodes');
|
|
4
|
+
const logger = require('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
|
|
5
|
+
|
|
6
|
+
jest.mock('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
|
|
7
|
+
|
|
8
|
+
describe('Error Middleware', () => {
|
|
9
|
+
let mockRequest;
|
|
10
|
+
let mockResponse;
|
|
11
|
+
let nextFunction;
|
|
12
|
+
const originalEnv = process.env.NODE_ENV;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
mockRequest = {
|
|
16
|
+
originalUrl: '/test',
|
|
17
|
+
method: 'GET',
|
|
18
|
+
ip: '127.0.0.1'
|
|
19
|
+
};
|
|
20
|
+
mockResponse = {
|
|
21
|
+
status: jest.fn().mockReturnThis(),
|
|
22
|
+
json: jest.fn()
|
|
23
|
+
};
|
|
24
|
+
nextFunction = jest.fn();
|
|
25
|
+
jest.clearAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
process.env.NODE_ENV = originalEnv;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should handle standard Error by wrapping it in a 500 ApiError', () => {
|
|
33
|
+
const error = new Error('Standard Error');
|
|
34
|
+
errorMiddleware(error, mockRequest, mockResponse, nextFunction);
|
|
35
|
+
|
|
36
|
+
expect(logger.error).toHaveBeenCalled();
|
|
37
|
+
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.INTERNAL_SERVER_ERROR);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should handle custom ApiError directly', () => {
|
|
41
|
+
const customError = new ApiError(HTTP_STATUS.BAD_REQUEST, 'Bad Request Data', true);
|
|
42
|
+
errorMiddleware(customError, mockRequest, mockResponse, nextFunction);
|
|
43
|
+
|
|
44
|
+
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.BAD_REQUEST);
|
|
45
|
+
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
46
|
+
statusCode: HTTP_STATUS.BAD_REQUEST,
|
|
47
|
+
message: 'Bad Request Data'
|
|
48
|
+
}));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should include stack trace in development environment', () => {
|
|
52
|
+
process.env.NODE_ENV = 'development';
|
|
53
|
+
const error = new Error('Test Error');
|
|
54
|
+
errorMiddleware(error, mockRequest, mockResponse, nextFunction);
|
|
55
|
+
|
|
56
|
+
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
57
|
+
stack: expect.any(String)
|
|
58
|
+
}));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should omit stack trace in production environment', () => {
|
|
62
|
+
process.env.NODE_ENV = 'production';
|
|
63
|
+
const error = new Error('Test Error');
|
|
64
|
+
errorMiddleware(error, mockRequest, mockResponse, nextFunction);
|
|
65
|
+
|
|
66
|
+
const jsonArg = mockResponse.json.mock.calls[0][0];
|
|
67
|
+
expect(jsonArg.stack).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should handle error without stack trace', () => {
|
|
71
|
+
const { ApiError } = require('@/errors/ApiError');
|
|
72
|
+
const customError = new ApiError(500, 'No Stack', false);
|
|
73
|
+
delete customError.stack;
|
|
74
|
+
errorMiddleware(customError, mockRequest, mockResponse, nextFunction);
|
|
75
|
+
|
|
76
|
+
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('No Stack'));
|
|
77
|
+
expect(logger.error).toHaveBeenCalledWith('No stack trace');
|
|
78
|
+
});
|
|
79
|
+
});
|