@corbat-tech/coding-standards-mcp 1.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/LICENSE +21 -0
- package/README.md +371 -0
- package/assets/demo.gif +0 -0
- package/dist/agent.d.ts +53 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +629 -0
- package/dist/agent.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +651 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/config.d.ts +73 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +105 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/profiles.d.ts +39 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +526 -0
- package/dist/profiles.js.map +1 -0
- package/dist/prompts-legacy.d.ts +25 -0
- package/dist/prompts-legacy.d.ts.map +1 -0
- package/dist/prompts-legacy.js +600 -0
- package/dist/prompts-legacy.js.map +1 -0
- package/dist/prompts-v2.d.ts +30 -0
- package/dist/prompts-v2.d.ts.map +1 -0
- package/dist/prompts-v2.js +310 -0
- package/dist/prompts-v2.js.map +1 -0
- package/dist/prompts.d.ts +30 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +310 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +18 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +95 -0
- package/dist/resources.js.map +1 -0
- package/dist/tools-legacy.d.ts +196 -0
- package/dist/tools-legacy.d.ts.map +1 -0
- package/dist/tools-legacy.js +1230 -0
- package/dist/tools-legacy.js.map +1 -0
- package/dist/tools-v2.d.ts +92 -0
- package/dist/tools-v2.d.ts.map +1 -0
- package/dist/tools-v2.js +410 -0
- package/dist/tools-v2.js.map +1 -0
- package/dist/tools.d.ts +92 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +410 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +3054 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +515 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/retry.d.ts +44 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +74 -0
- package/dist/utils/retry.js.map +1 -0
- package/package.json +79 -0
- package/profiles/README.md +199 -0
- package/profiles/custom/.gitkeep +2 -0
- package/profiles/templates/_template.yaml +159 -0
- package/profiles/templates/angular.yaml +494 -0
- package/profiles/templates/java-spring-backend.yaml +512 -0
- package/profiles/templates/minimal.yaml +102 -0
- package/profiles/templates/nodejs.yaml +338 -0
- package/profiles/templates/python.yaml +340 -0
- package/profiles/templates/react.yaml +331 -0
- package/profiles/templates/vue.yaml +598 -0
- package/standards/architecture/ddd.md +173 -0
- package/standards/architecture/hexagonal.md +97 -0
- package/standards/cicd/github-actions.md +567 -0
- package/standards/clean-code/naming.md +175 -0
- package/standards/clean-code/principles.md +179 -0
- package/standards/containerization/dockerfile.md +419 -0
- package/standards/database/selection-guide.md +443 -0
- package/standards/documentation/guidelines.md +189 -0
- package/standards/event-driven/domain-events.md +527 -0
- package/standards/kubernetes/deployment.md +518 -0
- package/standards/observability/guidelines.md +665 -0
- package/standards/project-setup/initialization-checklist.md +650 -0
- package/standards/spring-boot/best-practices.md +598 -0
- package/standards/testing/guidelines.md +559 -0
- package/standards/workflow/llm-development-workflow.md +542 -0
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
# Project Initialization Checklist
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This checklist guides the complete setup of a new Spring Boot backend application following Corbat standards.
|
|
6
|
+
|
|
7
|
+
## Project Creation Steps
|
|
8
|
+
|
|
9
|
+
### 1. Project Structure
|
|
10
|
+
|
|
11
|
+
Create the following directory structure:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
project-name/
|
|
15
|
+
├── src/
|
|
16
|
+
│ ├── main/
|
|
17
|
+
│ │ ├── java/
|
|
18
|
+
│ │ │ └── com/example/projectname/
|
|
19
|
+
│ │ │ ├── domain/
|
|
20
|
+
│ │ │ │ ├── model/
|
|
21
|
+
│ │ │ │ ├── event/
|
|
22
|
+
│ │ │ │ ├── exception/
|
|
23
|
+
│ │ │ │ ├── port/
|
|
24
|
+
│ │ │ │ │ ├── in/
|
|
25
|
+
│ │ │ │ │ └── out/
|
|
26
|
+
│ │ │ │ └── service/
|
|
27
|
+
│ │ │ ├── application/
|
|
28
|
+
│ │ │ │ ├── usecase/
|
|
29
|
+
│ │ │ │ ├── command/
|
|
30
|
+
│ │ │ │ └── query/
|
|
31
|
+
│ │ │ └── infrastructure/
|
|
32
|
+
│ │ │ ├── adapter/
|
|
33
|
+
│ │ │ │ ├── in/
|
|
34
|
+
│ │ │ │ │ └── rest/
|
|
35
|
+
│ │ │ │ └── out/
|
|
36
|
+
│ │ │ │ ├── persistence/
|
|
37
|
+
│ │ │ │ ├── messaging/
|
|
38
|
+
│ │ │ │ └── http/
|
|
39
|
+
│ │ │ └── config/
|
|
40
|
+
│ │ └── resources/
|
|
41
|
+
│ │ ├── application.yml
|
|
42
|
+
│ │ ├── application-local.yml
|
|
43
|
+
│ │ ├── application-production.yml
|
|
44
|
+
│ │ └── db/
|
|
45
|
+
│ │ └── migration/
|
|
46
|
+
│ └── test/
|
|
47
|
+
│ └── java/
|
|
48
|
+
│ └── com/example/projectname/
|
|
49
|
+
│ ├── domain/
|
|
50
|
+
│ ├── application/
|
|
51
|
+
│ ├── infrastructure/
|
|
52
|
+
│ ├── architecture/
|
|
53
|
+
│ └── integration/
|
|
54
|
+
├── infrastructure/
|
|
55
|
+
│ ├── docker/
|
|
56
|
+
│ │ ├── Dockerfile
|
|
57
|
+
│ │ └── docker-compose.yml
|
|
58
|
+
│ ├── kubernetes/
|
|
59
|
+
│ │ ├── base/
|
|
60
|
+
│ │ └── overlays/
|
|
61
|
+
│ └── prometheus/
|
|
62
|
+
│ └── prometheus.yml
|
|
63
|
+
├── .github/
|
|
64
|
+
│ └── workflows/
|
|
65
|
+
│ ├── ci.yml
|
|
66
|
+
│ └── cd.yml
|
|
67
|
+
├── pom.xml
|
|
68
|
+
├── .gitignore
|
|
69
|
+
├── .dockerignore
|
|
70
|
+
├── README.md
|
|
71
|
+
└── CHANGELOG.md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Dependencies (pom.xml)
|
|
75
|
+
|
|
76
|
+
```xml
|
|
77
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
78
|
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
79
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
80
|
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
|
81
|
+
https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
82
|
+
<modelVersion>4.0.0</modelVersion>
|
|
83
|
+
|
|
84
|
+
<parent>
|
|
85
|
+
<groupId>org.springframework.boot</groupId>
|
|
86
|
+
<artifactId>spring-boot-starter-parent</artifactId>
|
|
87
|
+
<version>3.2.0</version>
|
|
88
|
+
</parent>
|
|
89
|
+
|
|
90
|
+
<groupId>com.example</groupId>
|
|
91
|
+
<artifactId>project-name</artifactId>
|
|
92
|
+
<version>0.0.1-SNAPSHOT</version>
|
|
93
|
+
<name>Project Name</name>
|
|
94
|
+
<description>Description of the project</description>
|
|
95
|
+
|
|
96
|
+
<properties>
|
|
97
|
+
<java.version>21</java.version>
|
|
98
|
+
<mapstruct.version>1.5.5.Final</mapstruct.version>
|
|
99
|
+
<archunit.version>1.2.0</archunit.version>
|
|
100
|
+
<testcontainers.version>1.19.3</testcontainers.version>
|
|
101
|
+
</properties>
|
|
102
|
+
|
|
103
|
+
<dependencies>
|
|
104
|
+
<!-- Core -->
|
|
105
|
+
<dependency>
|
|
106
|
+
<groupId>org.springframework.boot</groupId>
|
|
107
|
+
<artifactId>spring-boot-starter-web</artifactId>
|
|
108
|
+
</dependency>
|
|
109
|
+
<dependency>
|
|
110
|
+
<groupId>org.springframework.boot</groupId>
|
|
111
|
+
<artifactId>spring-boot-starter-validation</artifactId>
|
|
112
|
+
</dependency>
|
|
113
|
+
|
|
114
|
+
<!-- Persistence -->
|
|
115
|
+
<dependency>
|
|
116
|
+
<groupId>org.springframework.boot</groupId>
|
|
117
|
+
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
118
|
+
</dependency>
|
|
119
|
+
<dependency>
|
|
120
|
+
<groupId>org.postgresql</groupId>
|
|
121
|
+
<artifactId>postgresql</artifactId>
|
|
122
|
+
<scope>runtime</scope>
|
|
123
|
+
</dependency>
|
|
124
|
+
<dependency>
|
|
125
|
+
<groupId>org.flywaydb</groupId>
|
|
126
|
+
<artifactId>flyway-core</artifactId>
|
|
127
|
+
</dependency>
|
|
128
|
+
|
|
129
|
+
<!-- Messaging (optional) -->
|
|
130
|
+
<dependency>
|
|
131
|
+
<groupId>org.springframework.kafka</groupId>
|
|
132
|
+
<artifactId>spring-kafka</artifactId>
|
|
133
|
+
</dependency>
|
|
134
|
+
|
|
135
|
+
<!-- Caching (optional) -->
|
|
136
|
+
<dependency>
|
|
137
|
+
<groupId>org.springframework.boot</groupId>
|
|
138
|
+
<artifactId>spring-boot-starter-data-redis</artifactId>
|
|
139
|
+
</dependency>
|
|
140
|
+
<dependency>
|
|
141
|
+
<groupId>org.springframework.boot</groupId>
|
|
142
|
+
<artifactId>spring-boot-starter-cache</artifactId>
|
|
143
|
+
</dependency>
|
|
144
|
+
|
|
145
|
+
<!-- Security -->
|
|
146
|
+
<dependency>
|
|
147
|
+
<groupId>org.springframework.boot</groupId>
|
|
148
|
+
<artifactId>spring-boot-starter-security</artifactId>
|
|
149
|
+
</dependency>
|
|
150
|
+
|
|
151
|
+
<!-- Observability -->
|
|
152
|
+
<dependency>
|
|
153
|
+
<groupId>org.springframework.boot</groupId>
|
|
154
|
+
<artifactId>spring-boot-starter-actuator</artifactId>
|
|
155
|
+
</dependency>
|
|
156
|
+
<dependency>
|
|
157
|
+
<groupId>io.micrometer</groupId>
|
|
158
|
+
<artifactId>micrometer-registry-prometheus</artifactId>
|
|
159
|
+
</dependency>
|
|
160
|
+
<dependency>
|
|
161
|
+
<groupId>io.micrometer</groupId>
|
|
162
|
+
<artifactId>micrometer-tracing-bridge-brave</artifactId>
|
|
163
|
+
</dependency>
|
|
164
|
+
<dependency>
|
|
165
|
+
<groupId>io.zipkin.reporter2</groupId>
|
|
166
|
+
<artifactId>zipkin-reporter-brave</artifactId>
|
|
167
|
+
</dependency>
|
|
168
|
+
|
|
169
|
+
<!-- API Documentation -->
|
|
170
|
+
<dependency>
|
|
171
|
+
<groupId>org.springdoc</groupId>
|
|
172
|
+
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
|
173
|
+
<version>2.3.0</version>
|
|
174
|
+
</dependency>
|
|
175
|
+
|
|
176
|
+
<!-- Utilities -->
|
|
177
|
+
<dependency>
|
|
178
|
+
<groupId>org.projectlombok</groupId>
|
|
179
|
+
<artifactId>lombok</artifactId>
|
|
180
|
+
<optional>true</optional>
|
|
181
|
+
</dependency>
|
|
182
|
+
<dependency>
|
|
183
|
+
<groupId>org.mapstruct</groupId>
|
|
184
|
+
<artifactId>mapstruct</artifactId>
|
|
185
|
+
<version>${mapstruct.version}</version>
|
|
186
|
+
</dependency>
|
|
187
|
+
|
|
188
|
+
<!-- Testing -->
|
|
189
|
+
<dependency>
|
|
190
|
+
<groupId>org.springframework.boot</groupId>
|
|
191
|
+
<artifactId>spring-boot-starter-test</artifactId>
|
|
192
|
+
<scope>test</scope>
|
|
193
|
+
</dependency>
|
|
194
|
+
<dependency>
|
|
195
|
+
<groupId>org.springframework.security</groupId>
|
|
196
|
+
<artifactId>spring-security-test</artifactId>
|
|
197
|
+
<scope>test</scope>
|
|
198
|
+
</dependency>
|
|
199
|
+
<dependency>
|
|
200
|
+
<groupId>com.tngtech.archunit</groupId>
|
|
201
|
+
<artifactId>archunit-junit5</artifactId>
|
|
202
|
+
<version>${archunit.version}</version>
|
|
203
|
+
<scope>test</scope>
|
|
204
|
+
</dependency>
|
|
205
|
+
<dependency>
|
|
206
|
+
<groupId>org.testcontainers</groupId>
|
|
207
|
+
<artifactId>junit-jupiter</artifactId>
|
|
208
|
+
<scope>test</scope>
|
|
209
|
+
</dependency>
|
|
210
|
+
<dependency>
|
|
211
|
+
<groupId>org.testcontainers</groupId>
|
|
212
|
+
<artifactId>postgresql</artifactId>
|
|
213
|
+
<scope>test</scope>
|
|
214
|
+
</dependency>
|
|
215
|
+
<dependency>
|
|
216
|
+
<groupId>org.testcontainers</groupId>
|
|
217
|
+
<artifactId>kafka</artifactId>
|
|
218
|
+
<scope>test</scope>
|
|
219
|
+
</dependency>
|
|
220
|
+
</dependencies>
|
|
221
|
+
|
|
222
|
+
<dependencyManagement>
|
|
223
|
+
<dependencies>
|
|
224
|
+
<dependency>
|
|
225
|
+
<groupId>org.testcontainers</groupId>
|
|
226
|
+
<artifactId>testcontainers-bom</artifactId>
|
|
227
|
+
<version>${testcontainers.version}</version>
|
|
228
|
+
<type>pom</type>
|
|
229
|
+
<scope>import</scope>
|
|
230
|
+
</dependency>
|
|
231
|
+
</dependencies>
|
|
232
|
+
</dependencyManagement>
|
|
233
|
+
|
|
234
|
+
<build>
|
|
235
|
+
<plugins>
|
|
236
|
+
<plugin>
|
|
237
|
+
<groupId>org.springframework.boot</groupId>
|
|
238
|
+
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
239
|
+
<configuration>
|
|
240
|
+
<excludes>
|
|
241
|
+
<exclude>
|
|
242
|
+
<groupId>org.projectlombok</groupId>
|
|
243
|
+
<artifactId>lombok</artifactId>
|
|
244
|
+
</exclude>
|
|
245
|
+
</excludes>
|
|
246
|
+
<layers>
|
|
247
|
+
<enabled>true</enabled>
|
|
248
|
+
</layers>
|
|
249
|
+
</configuration>
|
|
250
|
+
</plugin>
|
|
251
|
+
<plugin>
|
|
252
|
+
<groupId>org.apache.maven.plugins</groupId>
|
|
253
|
+
<artifactId>maven-compiler-plugin</artifactId>
|
|
254
|
+
<configuration>
|
|
255
|
+
<annotationProcessorPaths>
|
|
256
|
+
<path>
|
|
257
|
+
<groupId>org.projectlombok</groupId>
|
|
258
|
+
<artifactId>lombok</artifactId>
|
|
259
|
+
<version>${lombok.version}</version>
|
|
260
|
+
</path>
|
|
261
|
+
<path>
|
|
262
|
+
<groupId>org.mapstruct</groupId>
|
|
263
|
+
<artifactId>mapstruct-processor</artifactId>
|
|
264
|
+
<version>${mapstruct.version}</version>
|
|
265
|
+
</path>
|
|
266
|
+
</annotationProcessorPaths>
|
|
267
|
+
</configuration>
|
|
268
|
+
</plugin>
|
|
269
|
+
<plugin>
|
|
270
|
+
<groupId>org.apache.maven.plugins</groupId>
|
|
271
|
+
<artifactId>maven-failsafe-plugin</artifactId>
|
|
272
|
+
<executions>
|
|
273
|
+
<execution>
|
|
274
|
+
<goals>
|
|
275
|
+
<goal>integration-test</goal>
|
|
276
|
+
<goal>verify</goal>
|
|
277
|
+
</goals>
|
|
278
|
+
</execution>
|
|
279
|
+
</executions>
|
|
280
|
+
</plugin>
|
|
281
|
+
<plugin>
|
|
282
|
+
<groupId>org.jacoco</groupId>
|
|
283
|
+
<artifactId>jacoco-maven-plugin</artifactId>
|
|
284
|
+
<version>0.8.11</version>
|
|
285
|
+
<executions>
|
|
286
|
+
<execution>
|
|
287
|
+
<goals>
|
|
288
|
+
<goal>prepare-agent</goal>
|
|
289
|
+
</goals>
|
|
290
|
+
</execution>
|
|
291
|
+
<execution>
|
|
292
|
+
<id>report</id>
|
|
293
|
+
<phase>test</phase>
|
|
294
|
+
<goals>
|
|
295
|
+
<goal>report</goal>
|
|
296
|
+
</goals>
|
|
297
|
+
</execution>
|
|
298
|
+
</executions>
|
|
299
|
+
</plugin>
|
|
300
|
+
</plugins>
|
|
301
|
+
</build>
|
|
302
|
+
</project>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 3. Application Configuration
|
|
306
|
+
|
|
307
|
+
```yaml
|
|
308
|
+
# application.yml
|
|
309
|
+
spring:
|
|
310
|
+
application:
|
|
311
|
+
name: project-name
|
|
312
|
+
|
|
313
|
+
datasource:
|
|
314
|
+
url: ${DATABASE_URL:jdbc:postgresql://localhost:5432/projectdb}
|
|
315
|
+
username: ${DATABASE_USERNAME:postgres}
|
|
316
|
+
password: ${DATABASE_PASSWORD:postgres}
|
|
317
|
+
hikari:
|
|
318
|
+
maximum-pool-size: 10
|
|
319
|
+
minimum-idle: 5
|
|
320
|
+
|
|
321
|
+
jpa:
|
|
322
|
+
hibernate:
|
|
323
|
+
ddl-auto: validate
|
|
324
|
+
open-in-view: false
|
|
325
|
+
|
|
326
|
+
flyway:
|
|
327
|
+
enabled: true
|
|
328
|
+
locations: classpath:db/migration
|
|
329
|
+
|
|
330
|
+
jackson:
|
|
331
|
+
default-property-inclusion: non_null
|
|
332
|
+
serialization:
|
|
333
|
+
write-dates-as-timestamps: false
|
|
334
|
+
|
|
335
|
+
management:
|
|
336
|
+
endpoints:
|
|
337
|
+
web:
|
|
338
|
+
exposure:
|
|
339
|
+
include: health,info,metrics,prometheus
|
|
340
|
+
endpoint:
|
|
341
|
+
health:
|
|
342
|
+
show-details: when_authorized
|
|
343
|
+
probes:
|
|
344
|
+
enabled: true
|
|
345
|
+
tracing:
|
|
346
|
+
sampling:
|
|
347
|
+
probability: ${TRACING_SAMPLING_PROBABILITY:1.0}
|
|
348
|
+
|
|
349
|
+
server:
|
|
350
|
+
shutdown: graceful
|
|
351
|
+
|
|
352
|
+
logging:
|
|
353
|
+
level:
|
|
354
|
+
root: INFO
|
|
355
|
+
com.example: DEBUG
|
|
356
|
+
pattern:
|
|
357
|
+
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId:-},%X{spanId:-}] %-5level %logger{36} - %msg%n"
|
|
358
|
+
|
|
359
|
+
springdoc:
|
|
360
|
+
api-docs:
|
|
361
|
+
path: /api-docs
|
|
362
|
+
swagger-ui:
|
|
363
|
+
path: /swagger-ui.html
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 4. Core Classes to Create
|
|
367
|
+
|
|
368
|
+
#### Domain Layer
|
|
369
|
+
|
|
370
|
+
```java
|
|
371
|
+
// domain/model/OrderId.java - Value Object
|
|
372
|
+
public record OrderId(String value) {
|
|
373
|
+
public OrderId {
|
|
374
|
+
Objects.requireNonNull(value, "Order ID cannot be null");
|
|
375
|
+
if (value.isBlank()) {
|
|
376
|
+
throw new IllegalArgumentException("Order ID cannot be blank");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
public static OrderId generate() {
|
|
381
|
+
return new OrderId(UUID.randomUUID().toString());
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
public static OrderId of(String value) {
|
|
385
|
+
return new OrderId(value);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// domain/model/Order.java - Aggregate
|
|
390
|
+
public class Order extends AggregateRoot {
|
|
391
|
+
private OrderId id;
|
|
392
|
+
private CustomerId customerId;
|
|
393
|
+
private OrderStatus status;
|
|
394
|
+
private List<OrderLine> lines;
|
|
395
|
+
private Instant createdAt;
|
|
396
|
+
|
|
397
|
+
public static Order create(CustomerId customerId, List<OrderLine> lines) {
|
|
398
|
+
Order order = new Order();
|
|
399
|
+
order.id = OrderId.generate();
|
|
400
|
+
order.customerId = customerId;
|
|
401
|
+
order.status = OrderStatus.PENDING;
|
|
402
|
+
order.lines = new ArrayList<>(lines);
|
|
403
|
+
order.createdAt = Instant.now();
|
|
404
|
+
|
|
405
|
+
order.registerEvent(new OrderCreatedEvent(order.id.value(), customerId.value()));
|
|
406
|
+
return order;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Business methods...
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// domain/port/out/OrderRepository.java - Output Port
|
|
413
|
+
public interface OrderRepository {
|
|
414
|
+
Optional<Order> findById(OrderId id);
|
|
415
|
+
void save(Order order);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// domain/port/in/PlaceOrderUseCase.java - Input Port
|
|
419
|
+
public interface PlaceOrderUseCase {
|
|
420
|
+
OrderId execute(PlaceOrderCommand command);
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
#### Application Layer
|
|
425
|
+
|
|
426
|
+
```java
|
|
427
|
+
// application/command/PlaceOrderCommand.java
|
|
428
|
+
public record PlaceOrderCommand(
|
|
429
|
+
String customerId,
|
|
430
|
+
List<OrderLineData> lines
|
|
431
|
+
) {
|
|
432
|
+
public record OrderLineData(String productId, int quantity) {}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// application/usecase/PlaceOrderUseCaseImpl.java
|
|
436
|
+
@Service
|
|
437
|
+
@RequiredArgsConstructor
|
|
438
|
+
@Transactional
|
|
439
|
+
public class PlaceOrderUseCaseImpl implements PlaceOrderUseCase {
|
|
440
|
+
|
|
441
|
+
private final OrderRepository orderRepository;
|
|
442
|
+
private final DomainEventPublisher eventPublisher;
|
|
443
|
+
|
|
444
|
+
@Override
|
|
445
|
+
public OrderId execute(PlaceOrderCommand command) {
|
|
446
|
+
Order order = Order.create(
|
|
447
|
+
CustomerId.of(command.customerId()),
|
|
448
|
+
command.lines().stream()
|
|
449
|
+
.map(line -> OrderLine.of(ProductId.of(line.productId()), line.quantity()))
|
|
450
|
+
.toList()
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
orderRepository.save(order);
|
|
454
|
+
eventPublisher.publishAll(order.getDomainEvents());
|
|
455
|
+
order.clearDomainEvents();
|
|
456
|
+
|
|
457
|
+
return order.getId();
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
#### Infrastructure Layer
|
|
463
|
+
|
|
464
|
+
```java
|
|
465
|
+
// infrastructure/adapter/in/rest/OrderController.java
|
|
466
|
+
@RestController
|
|
467
|
+
@RequestMapping("/api/v1/orders")
|
|
468
|
+
@RequiredArgsConstructor
|
|
469
|
+
@Tag(name = "Orders")
|
|
470
|
+
public class OrderController {
|
|
471
|
+
|
|
472
|
+
private final PlaceOrderUseCase placeOrderUseCase;
|
|
473
|
+
private final GetOrderUseCase getOrderUseCase;
|
|
474
|
+
|
|
475
|
+
@PostMapping
|
|
476
|
+
@ResponseStatus(HttpStatus.CREATED)
|
|
477
|
+
@Operation(summary = "Create a new order")
|
|
478
|
+
public OrderResponse createOrder(@Valid @RequestBody CreateOrderRequest request) {
|
|
479
|
+
OrderId orderId = placeOrderUseCase.execute(request.toCommand());
|
|
480
|
+
return getOrderUseCase.execute(orderId)
|
|
481
|
+
.map(OrderResponse::from)
|
|
482
|
+
.orElseThrow();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// infrastructure/adapter/out/persistence/JpaOrderRepository.java
|
|
487
|
+
@Repository
|
|
488
|
+
@RequiredArgsConstructor
|
|
489
|
+
public class JpaOrderRepository implements OrderRepository {
|
|
490
|
+
|
|
491
|
+
private final OrderJpaRepository jpaRepository;
|
|
492
|
+
private final OrderMapper mapper;
|
|
493
|
+
|
|
494
|
+
@Override
|
|
495
|
+
public Optional<Order> findById(OrderId id) {
|
|
496
|
+
return jpaRepository.findById(id.value())
|
|
497
|
+
.map(mapper::toDomain);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
@Override
|
|
501
|
+
public void save(Order order) {
|
|
502
|
+
jpaRepository.save(mapper.toEntity(order));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### 5. Testing Structure
|
|
508
|
+
|
|
509
|
+
```java
|
|
510
|
+
// test/architecture/HexagonalArchTest.java
|
|
511
|
+
@AnalyzeClasses(packages = "com.example.projectname")
|
|
512
|
+
class HexagonalArchTest {
|
|
513
|
+
|
|
514
|
+
@ArchTest
|
|
515
|
+
static final ArchRule domain_should_not_depend_on_infrastructure =
|
|
516
|
+
noClasses()
|
|
517
|
+
.that().resideInAPackage("..domain..")
|
|
518
|
+
.should().dependOnClassesThat()
|
|
519
|
+
.resideInAPackage("..infrastructure..");
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// test/integration/OrderControllerIT.java
|
|
523
|
+
@SpringBootTest
|
|
524
|
+
@AutoConfigureMockMvc
|
|
525
|
+
@Testcontainers
|
|
526
|
+
class OrderControllerIT {
|
|
527
|
+
|
|
528
|
+
@Container
|
|
529
|
+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine");
|
|
530
|
+
|
|
531
|
+
@DynamicPropertySource
|
|
532
|
+
static void configureProperties(DynamicPropertyRegistry registry) {
|
|
533
|
+
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
534
|
+
registry.add("spring.datasource.username", postgres::getUsername);
|
|
535
|
+
registry.add("spring.datasource.password", postgres::getPassword);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
@Autowired
|
|
539
|
+
private MockMvc mockMvc;
|
|
540
|
+
|
|
541
|
+
@Test
|
|
542
|
+
void should_CreateOrder_When_ValidRequest() throws Exception {
|
|
543
|
+
// Test implementation
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
## Initialization Checklist
|
|
549
|
+
|
|
550
|
+
### Project Setup
|
|
551
|
+
- [ ] Create project structure (hexagonal architecture)
|
|
552
|
+
- [ ] Configure pom.xml with all dependencies
|
|
553
|
+
- [ ] Set up application.yml for all environments
|
|
554
|
+
- [ ] Create .gitignore and .dockerignore
|
|
555
|
+
- [ ] Initialize Git repository
|
|
556
|
+
|
|
557
|
+
### Domain Layer
|
|
558
|
+
- [ ] Define value objects (IDs, Money, etc.)
|
|
559
|
+
- [ ] Define aggregate roots
|
|
560
|
+
- [ ] Define domain events
|
|
561
|
+
- [ ] Define domain exceptions
|
|
562
|
+
- [ ] Define repository interfaces (ports)
|
|
563
|
+
- [ ] Define use case interfaces (ports)
|
|
564
|
+
|
|
565
|
+
### Application Layer
|
|
566
|
+
- [ ] Implement commands and queries
|
|
567
|
+
- [ ] Implement use cases
|
|
568
|
+
- [ ] Define DTOs
|
|
569
|
+
|
|
570
|
+
### Infrastructure Layer
|
|
571
|
+
- [ ] Implement REST controllers
|
|
572
|
+
- [ ] Implement JPA entities and repositories
|
|
573
|
+
- [ ] Implement mappers (MapStruct)
|
|
574
|
+
- [ ] Configure security
|
|
575
|
+
- [ ] Configure Kafka (if needed)
|
|
576
|
+
- [ ] Configure Redis (if needed)
|
|
577
|
+
- [ ] Create database migrations
|
|
578
|
+
|
|
579
|
+
### Testing
|
|
580
|
+
- [ ] Create ArchUnit tests
|
|
581
|
+
- [ ] Create unit tests for domain
|
|
582
|
+
- [ ] Create unit tests for use cases
|
|
583
|
+
- [ ] Create integration tests (*IT.java)
|
|
584
|
+
- [ ] Configure test coverage (JaCoCo)
|
|
585
|
+
- [ ] Set up Testcontainers
|
|
586
|
+
|
|
587
|
+
### Observability
|
|
588
|
+
- [ ] Configure structured logging
|
|
589
|
+
- [ ] Configure metrics (Micrometer)
|
|
590
|
+
- [ ] Configure tracing
|
|
591
|
+
- [ ] Create custom health indicators
|
|
592
|
+
- [ ] Set up Prometheus endpoint
|
|
593
|
+
|
|
594
|
+
### CI/CD
|
|
595
|
+
- [ ] Create Dockerfile
|
|
596
|
+
- [ ] Create docker-compose.yml
|
|
597
|
+
- [ ] Create GitHub Actions CI workflow
|
|
598
|
+
- [ ] Create GitHub Actions CD workflow
|
|
599
|
+
- [ ] Create Kubernetes manifests
|
|
600
|
+
|
|
601
|
+
### Documentation
|
|
602
|
+
- [ ] Write README.md
|
|
603
|
+
- [ ] Configure OpenAPI/Swagger
|
|
604
|
+
- [ ] Document API endpoints
|
|
605
|
+
- [ ] Create CHANGELOG.md
|
|
606
|
+
|
|
607
|
+
### Verification
|
|
608
|
+
- [ ] Run all tests (`./mvnw verify`)
|
|
609
|
+
- [ ] Check test coverage (80%+)
|
|
610
|
+
- [ ] Build Docker image
|
|
611
|
+
- [ ] Run application locally
|
|
612
|
+
- [ ] Test with docker-compose
|
|
613
|
+
- [ ] Verify health endpoints
|
|
614
|
+
- [ ] Verify metrics endpoint
|
|
615
|
+
- [ ] Verify API documentation
|
|
616
|
+
|
|
617
|
+
## Quick Commands
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
# Create project with Spring Initializr
|
|
621
|
+
curl https://start.spring.io/starter.zip \
|
|
622
|
+
-d type=maven-project \
|
|
623
|
+
-d language=java \
|
|
624
|
+
-d bootVersion=3.2.0 \
|
|
625
|
+
-d baseDir=project-name \
|
|
626
|
+
-d groupId=com.example \
|
|
627
|
+
-d artifactId=project-name \
|
|
628
|
+
-d name=ProjectName \
|
|
629
|
+
-d javaVersion=21 \
|
|
630
|
+
-d dependencies=web,validation,data-jpa,postgresql,flyway,actuator,security \
|
|
631
|
+
-o project-name.zip
|
|
632
|
+
|
|
633
|
+
# Build
|
|
634
|
+
./mvnw clean verify
|
|
635
|
+
|
|
636
|
+
# Run tests
|
|
637
|
+
./mvnw test
|
|
638
|
+
|
|
639
|
+
# Run integration tests
|
|
640
|
+
./mvnw verify -Pfailsafe
|
|
641
|
+
|
|
642
|
+
# Build Docker image
|
|
643
|
+
docker build -t project-name:latest .
|
|
644
|
+
|
|
645
|
+
# Run with Docker Compose
|
|
646
|
+
docker-compose up -d
|
|
647
|
+
|
|
648
|
+
# Check application health
|
|
649
|
+
curl http://localhost:8080/actuator/health
|
|
650
|
+
```
|