eva4j 1.0.13 → 1.0.15
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/AGENTS.md +314 -10
- package/COMMAND_EVALUATION.md +15 -16
- package/DOMAIN_YAML_GUIDE.md +576 -10
- package/FUTURE_FEATURES.md +1627 -1168
- package/README.md +318 -13
- package/bin/eva4j.js +34 -0
- package/config/defaults.json +1 -0
- package/design-system.md +797 -0
- package/docs/commands/EVALUATE_SYSTEM.md +994 -0
- package/docs/commands/GENERATE_ENTITIES.md +795 -6
- package/docs/commands/INDEX.md +10 -1
- package/examples/domain-endpoints-relations.yaml +353 -0
- package/examples/domain-endpoints-versioned.yaml +144 -0
- package/examples/domain-endpoints.yaml +135 -0
- package/examples/domain-events.yaml +166 -20
- package/examples/domain-listeners.yaml +212 -0
- package/examples/domain-one-to-many.yaml +1 -0
- package/examples/domain-one-to-one.yaml +1 -0
- package/examples/domain-ports.yaml +414 -0
- package/examples/domain-soft-delete.yaml +47 -44
- package/examples/system/notification.yaml +147 -0
- package/examples/system/product.yaml +185 -0
- package/examples/system/system.yaml +112 -0
- package/examples/system-report.html +971 -0
- package/examples/system.yaml +332 -0
- package/package.json +2 -1
- package/src/commands/build.js +714 -0
- package/src/commands/create.js +7 -3
- package/src/commands/detach.js +1 -0
- package/src/commands/evaluate-system.js +610 -0
- package/src/commands/generate-entities.js +1331 -49
- package/src/commands/generate-http-exchange.js +2 -0
- package/src/commands/generate-kafka-event.js +98 -11
- package/src/generators/base-generator.js +8 -1
- package/src/generators/postman-generator.js +188 -0
- package/src/generators/shared-generator.js +10 -0
- package/src/utils/config-manager.js +54 -0
- package/src/utils/context-builder.js +1 -0
- package/src/utils/domain-diagram.js +192 -0
- package/src/utils/domain-validator.js +970 -0
- package/src/utils/fake-data.js +376 -0
- package/src/utils/naming.js +3 -2
- package/src/utils/system-validator.js +434 -0
- package/src/utils/yaml-to-entity.js +302 -8
- package/templates/aggregate/AggregateMapper.java.ejs +3 -2
- package/templates/aggregate/AggregateRepository.java.ejs +8 -2
- package/templates/aggregate/AggregateRepositoryImpl.java.ejs +13 -3
- package/templates/aggregate/AggregateRoot.java.ejs +60 -2
- package/templates/aggregate/DomainEventHandler.java.ejs +27 -20
- package/templates/aggregate/DomainEventRecord.java.ejs +24 -8
- package/templates/aggregate/DomainEventSnapshot.java.ejs +46 -0
- package/templates/aggregate/JpaAggregateRoot.java.ejs +6 -0
- package/templates/aggregate/JpaRepository.java.ejs +5 -0
- package/templates/base/gradle/build.gradle.ejs +3 -2
- package/templates/base/root/AGENTS.md.ejs +306 -45
- package/templates/base/root/skill-build-domain-yaml-references-generate-entities.md.ejs +1663 -0
- package/templates/base/root/skill-build-system-yaml.ejs +1446 -0
- package/templates/base/root/system.yaml.ejs +97 -0
- package/templates/crud/ApplicationMapper.java.ejs +4 -0
- package/templates/crud/Controller.java.ejs +4 -4
- package/templates/crud/CreateCommand.java.ejs +4 -0
- package/templates/crud/CreateItemDto.java.ejs +4 -0
- package/templates/crud/CreateValueObjectDto.java.ejs +4 -0
- package/templates/crud/DeleteCommandHandler.java.ejs +10 -2
- package/templates/crud/EndpointsController.java.ejs +178 -0
- package/templates/crud/FindByQuery.java.ejs +17 -0
- package/templates/crud/FindByQueryHandler.java.ejs +57 -0
- package/templates/crud/ListQuery.java.ejs +1 -1
- package/templates/crud/ListQueryHandler.java.ejs +8 -8
- package/templates/crud/ScaffoldCommand.java.ejs +12 -0
- package/templates/crud/ScaffoldCommandHandler.java.ejs +43 -0
- package/templates/crud/ScaffoldQuery.java.ejs +13 -0
- package/templates/crud/ScaffoldQueryHandler.java.ejs +41 -0
- package/templates/crud/SubEntityAddCommand.java.ejs +21 -0
- package/templates/crud/SubEntityAddCommandHandler.java.ejs +43 -0
- package/templates/crud/SubEntityRemoveCommand.java.ejs +9 -0
- package/templates/crud/SubEntityRemoveCommandHandler.java.ejs +42 -0
- package/templates/crud/TransitionCommand.java.ejs +9 -0
- package/templates/crud/TransitionCommandHandler.java.ejs +39 -0
- package/templates/crud/UpdateCommand.java.ejs +4 -0
- package/templates/evaluate/report.html.ejs +1363 -0
- package/templates/kafka-event/DomainEventHandlerMethod.ejs +3 -1
- package/templates/kafka-event/Event.java.ejs +16 -0
- package/templates/kafka-listener/KafkaController.java.ejs +1 -1
- package/templates/kafka-listener/KafkaListenerClass.java.ejs +1 -1
- package/templates/kafka-listener/ListenerClass.java.ejs +65 -0
- package/templates/kafka-listener/ListenerCommand.java.ejs +31 -0
- package/templates/kafka-listener/ListenerCommandHandler.java.ejs +23 -0
- package/templates/kafka-listener/ListenerIntegrationEvent.java.ejs +37 -0
- package/templates/kafka-listener/ListenerMethod.java.ejs +1 -1
- package/templates/kafka-listener/ListenerNestedType.java.ejs +28 -0
- package/templates/mock/MockEvent.java.ejs +10 -0
- package/templates/mock/MockMessageBrokerImpl.java.ejs +35 -0
- package/templates/mock/MockMessageBrokerImplMethod.java.ejs +6 -0
- package/templates/mock/SpringEventListener.java.ejs +61 -0
- package/templates/ports/PortDomainModel.java.ejs +35 -0
- package/templates/ports/PortFeignAdapter.java.ejs +67 -0
- package/templates/ports/PortFeignClient.java.ejs +45 -0
- package/templates/ports/PortFeignConfig.java.ejs +24 -0
- package/templates/ports/PortInterface.java.ejs +45 -0
- package/templates/ports/PortNestedType.java.ejs +28 -0
- package/templates/ports/PortRequestDto.java.ejs +30 -0
- package/templates/ports/PortResponseDto.java.ejs +28 -0
- package/templates/postman/Collection.json.ejs +1 -1
- package/templates/postman/UnifiedCollection.json.ejs +185 -0
- package/templates/shared/configurations/eventPublicationConfig/EventPublicationSchemaConfig.java.ejs +109 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# EJEMPLO: PORTS — clientes HTTP hacia servicios internos o externos
|
|
2
|
+
# Complemento de listeners: (consumo async), ports: es para comunicación síncrona HTTP.
|
|
3
|
+
#
|
|
4
|
+
# La sección ports: vive en el NIVEL RAÍZ del domain.yaml,
|
|
5
|
+
# como sibling de aggregates: y listeners:.
|
|
6
|
+
#
|
|
7
|
+
# Formato: plano, un método = una entrada (igual que listeners:).
|
|
8
|
+
# Entradas con el mismo service: se agrupan en UN solo cliente Feign.
|
|
9
|
+
#
|
|
10
|
+
# Generación:
|
|
11
|
+
# eva4j g entities reservations
|
|
12
|
+
#
|
|
13
|
+
# ─── PATRÓN ACL (Anti-Corruption Layer) ──────────────────────────────────────
|
|
14
|
+
#
|
|
15
|
+
# Los DTOs de infraestructura (forma exacta de la API externa) viven en:
|
|
16
|
+
# infrastructure/adapters/{service}/{MethodPascal}Dto.java
|
|
17
|
+
#
|
|
18
|
+
# Los modelos de dominio (abstracción interna) viven en:
|
|
19
|
+
# domain/models/{service}/{DomainType}.java
|
|
20
|
+
#
|
|
21
|
+
# La interfaz del puerto devuelve modelos de dominio.
|
|
22
|
+
# El FeignAdapter mapea Dto → modelo de dominio de forma inline.
|
|
23
|
+
# Si la API externa cambia, sólo hay que actualizar el adaptador.
|
|
24
|
+
#
|
|
25
|
+
# El tipo de dominio se deriva automáticamente del nombre del método
|
|
26
|
+
# (ej: findScreeningById → Screening). Se puede sobrescribir con domainType:.
|
|
27
|
+
#
|
|
28
|
+
# ─── ARCHIVOS GENERADOS ──────────────────────────────────────────────────────
|
|
29
|
+
#
|
|
30
|
+
# Por cada service: único:
|
|
31
|
+
# domain/repositories/{ServiceName}.java ← interfaz del puerto
|
|
32
|
+
# infrastructure/adapters/{service}/{ServiceName}FeignClient.java
|
|
33
|
+
# infrastructure/adapters/{service}/{ServiceName}FeignAdapter.java
|
|
34
|
+
# infrastructure/adapters/{service}/{ServiceName}FeignConfig.java
|
|
35
|
+
# parameters/*/urls.yaml ← base-url parametrizada
|
|
36
|
+
#
|
|
37
|
+
# Por cada modelo de dominio único derivado de los métodos con fields:
|
|
38
|
+
# domain/models/{service}/{DomainType}.java ← modelo de dominio (ACL)
|
|
39
|
+
#
|
|
40
|
+
# Por cada método con fields:
|
|
41
|
+
# infrastructure/adapters/{service}/{MethodPascal}Dto.java ← DTO infra (forma externa)
|
|
42
|
+
#
|
|
43
|
+
# Por cada método con body: (POST/PUT/PATCH)
|
|
44
|
+
# application/dtos/{MethodPascal}RequestDto.java
|
|
45
|
+
#
|
|
46
|
+
# Por cada nestedTypes:
|
|
47
|
+
# application/dtos/{NestedTypePascal}.java
|
|
48
|
+
#
|
|
49
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
50
|
+
#
|
|
51
|
+
# ARCHIVOS GENERADOS EN ESTE EJEMPLO
|
|
52
|
+
#
|
|
53
|
+
# ScreeningService (módulo interno: screenings)
|
|
54
|
+
# ─────────────────────────────────────────────
|
|
55
|
+
# domain/repositories/ScreeningService.java ← devuelve Screening, Seat, etc.
|
|
56
|
+
# domain/models/screeningService/Screening.java ← modelo de dominio (ACL)
|
|
57
|
+
# domain/models/screeningService/Seat.java ← modelo de dominio (ACL, domainType override)
|
|
58
|
+
# domain/models/screeningService/PrivateEventAvailability.java ← modelo de dominio (ACL)
|
|
59
|
+
# infrastructure/adapters/screeningService/ScreeningServiceFeignClient.java
|
|
60
|
+
# infrastructure/adapters/screeningService/ScreeningServiceFeignAdapter.java
|
|
61
|
+
# infrastructure/adapters/screeningService/ScreeningServiceFeignConfig.java
|
|
62
|
+
# infrastructure/adapters/screeningService/FindScreeningByIdDto.java
|
|
63
|
+
# infrastructure/adapters/screeningService/FindAvailableSeatDto.java
|
|
64
|
+
# infrastructure/adapters/screeningService/CheckPrivateEventAvailabilityDto.java
|
|
65
|
+
#
|
|
66
|
+
# CustomerService (módulo interno: customers)
|
|
67
|
+
# ─────────────────────────────────────────────
|
|
68
|
+
# domain/repositories/CustomerService.java
|
|
69
|
+
# domain/models/customerService/Customer.java ← modelo de dominio (ACL)
|
|
70
|
+
# infrastructure/adapters/customerService/CustomerServiceFeignClient.java
|
|
71
|
+
# infrastructure/adapters/customerService/CustomerServiceFeignAdapter.java
|
|
72
|
+
# infrastructure/adapters/customerService/CustomerServiceFeignConfig.java
|
|
73
|
+
# infrastructure/adapters/customerService/FindCustomerByIdDto.java ← DTO infra
|
|
74
|
+
#
|
|
75
|
+
# PaymentGateway (servicio externo)
|
|
76
|
+
# ─────────────────────────────────────────────
|
|
77
|
+
# domain/repositories/PaymentGateway.java
|
|
78
|
+
# domain/models/paymentGateway/Payment.java ← modelo de dominio (ACL)
|
|
79
|
+
# domain/models/paymentGateway/PaymentStatus.java ← modelo de dominio (ACL)
|
|
80
|
+
# infrastructure/adapters/paymentGateway/PaymentGatewayFeignClient.java
|
|
81
|
+
# infrastructure/adapters/paymentGateway/PaymentGatewayFeignAdapter.java
|
|
82
|
+
# infrastructure/adapters/paymentGateway/PaymentGatewayFeignConfig.java
|
|
83
|
+
# application/dtos/PaymentMethodInput.java ← nestedType del body
|
|
84
|
+
# application/dtos/ProcessPaymentRequestDto.java ← body del POST
|
|
85
|
+
# infrastructure/adapters/paymentGateway/ProcessPaymentDto.java ← response DTO infra
|
|
86
|
+
# infrastructure/adapters/paymentGateway/FindPaymentStatusDto.java ← response DTO infra
|
|
87
|
+
# → cancelPayment: void, sin DTO de respuesta
|
|
88
|
+
#
|
|
89
|
+
# parameters/*/urls.yaml:
|
|
90
|
+
# reservations:
|
|
91
|
+
# screening-service:
|
|
92
|
+
# base-url: http://localhost:8081
|
|
93
|
+
# customer-service:
|
|
94
|
+
# base-url: http://localhost:8082
|
|
95
|
+
# payment-gateway:
|
|
96
|
+
# base-url: https://api.payments.example.com
|
|
97
|
+
#
|
|
98
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
99
|
+
#
|
|
100
|
+
# CÓDIGO GENERADO — ScreeningService.java (domain/repositories/)
|
|
101
|
+
# [ACL: retorna modelos de dominio, no DTOs de infraestructura]
|
|
102
|
+
#
|
|
103
|
+
# public interface ScreeningService {
|
|
104
|
+
# Screening findScreeningById(String id);
|
|
105
|
+
# List<Seat> findAvailableSeats(String id);
|
|
106
|
+
# PrivateEventAvailability checkPrivateEventAvailability(String id);
|
|
107
|
+
# }
|
|
108
|
+
#
|
|
109
|
+
# CÓDIGO GENERADO — ScreeningServiceFeignClient.java
|
|
110
|
+
# [FeignClient: devuelve DTOs de infra, no modelos de dominio]
|
|
111
|
+
#
|
|
112
|
+
# @FeignClient(
|
|
113
|
+
# name = "reservations-screening-service",
|
|
114
|
+
# url = "${reservations.screening-service.base-url}",
|
|
115
|
+
# configuration = ScreeningServiceFeignConfig.class
|
|
116
|
+
# )
|
|
117
|
+
# public interface ScreeningServiceFeignClient {
|
|
118
|
+
#
|
|
119
|
+
# @GetMapping("/screenings/{id}")
|
|
120
|
+
# FindScreeningByIdDto findScreeningById(@PathVariable("id") String id);
|
|
121
|
+
#
|
|
122
|
+
# @GetMapping("/screenings/{id}/seats")
|
|
123
|
+
# List<FindAvailableSeatDto> findAvailableSeats(@PathVariable("id") String id);
|
|
124
|
+
#
|
|
125
|
+
# @GetMapping("/screenings/{id}/private-event-availability")
|
|
126
|
+
# CheckPrivateEventAvailabilityDto checkPrivateEventAvailability(
|
|
127
|
+
# @PathVariable("id") String id);
|
|
128
|
+
# }
|
|
129
|
+
#
|
|
130
|
+
# CÓDIGO GENERADO — ScreeningServiceFeignAdapter.java (fragment)
|
|
131
|
+
# [Adapter: actúa como ACL, convierte DTOs infra → modelos de dominio]
|
|
132
|
+
#
|
|
133
|
+
# @Override
|
|
134
|
+
# public Screening findScreeningById(String id) {
|
|
135
|
+
# return toScreening(feignClient.findScreeningById(id));
|
|
136
|
+
# }
|
|
137
|
+
#
|
|
138
|
+
# // ── ACL Mappers ──────────────────────────────────────────────────────────
|
|
139
|
+
# private Screening toScreening(FindScreeningByIdDto dto) {
|
|
140
|
+
# if (dto == null) return null;
|
|
141
|
+
# return new Screening(dto.id(), dto.movieId(), dto.theaterId(), ...);
|
|
142
|
+
# }
|
|
143
|
+
#
|
|
144
|
+
# CÓDIGO GENERADO — PaymentGatewayFeignClient.java
|
|
145
|
+
#
|
|
146
|
+
# @FeignClient(
|
|
147
|
+
# name = "reservations-payment-gateway",
|
|
148
|
+
# url = "${reservations.payment-gateway.base-url}",
|
|
149
|
+
# configuration = PaymentGatewayFeignConfig.class
|
|
150
|
+
# )
|
|
151
|
+
# public interface PaymentGatewayFeignClient {
|
|
152
|
+
#
|
|
153
|
+
# @PostMapping("/payments")
|
|
154
|
+
# ProcessPaymentDto processPayment(@RequestBody ProcessPaymentRequestDto body);
|
|
155
|
+
#
|
|
156
|
+
# @GetMapping("/payments/{id}")
|
|
157
|
+
# FindPaymentStatusDto findPaymentStatus(@PathVariable("id") String id);
|
|
158
|
+
#
|
|
159
|
+
# @DeleteMapping("/payments/{id}")
|
|
160
|
+
# void cancelPayment(@PathVariable("id") String id);
|
|
161
|
+
# }
|
|
162
|
+
#
|
|
163
|
+
# CÓDIGO GENERADO — ProcessPaymentRequestDto.java (application/dtos/)
|
|
164
|
+
#
|
|
165
|
+
# public record ProcessPaymentRequestDto(
|
|
166
|
+
# String reservationId,
|
|
167
|
+
# String customerId,
|
|
168
|
+
# BigDecimal amount,
|
|
169
|
+
# String currency,
|
|
170
|
+
# PaymentMethodInput paymentMethod
|
|
171
|
+
# ) {}
|
|
172
|
+
#
|
|
173
|
+
# CÓDIGO GENERADO — PaymentMethodInput.java (application/dtos/)
|
|
174
|
+
#
|
|
175
|
+
# public record PaymentMethodInput(
|
|
176
|
+
# String type,
|
|
177
|
+
# String cardToken,
|
|
178
|
+
# String cardLastFour
|
|
179
|
+
# ) {}
|
|
180
|
+
#
|
|
181
|
+
# ─── REGLAS ───────────────────────────────────────────────────────────────────
|
|
182
|
+
#
|
|
183
|
+
# domainType: (opcional)
|
|
184
|
+
# • Sobreescribe el nombre del modelo de dominio derivado automáticamente.
|
|
185
|
+
# • Auto-derivación: elimina prefijo de verbo (Find/Get/...) y sufijo By{X}.
|
|
186
|
+
# Ej: findAvailableSeats → Seat (elimina Available + Seats→Seat no, por eso se usa override)
|
|
187
|
+
# • Declarar explícitamente cuando la derivación automática no es adecuada.
|
|
188
|
+
#
|
|
189
|
+
# baseUrl:
|
|
190
|
+
# • Se declara en la PRIMERA entrada de cada service:.
|
|
191
|
+
# • Entradas posteriores del mismo service: la ignoran.
|
|
192
|
+
# • Si se omite en todas las entradas, se usa http://localhost:8080 + warning.
|
|
193
|
+
# • Siempre se escribe en parameters/*/urls.yaml.
|
|
194
|
+
#
|
|
195
|
+
# body: (POST / PUT / PATCH)
|
|
196
|
+
# • Campos de tipo objeto → declarar en nestedTypes:.
|
|
197
|
+
# • En GET o DELETE: emit warning, se ignora.
|
|
198
|
+
# • Omitido → sin @RequestBody en el FeignClient.
|
|
199
|
+
#
|
|
200
|
+
# returnList: true
|
|
201
|
+
# • Solo aplica cuando fields: está presente.
|
|
202
|
+
# • Genera List<{DomainType}> en la interfaz, List<{InfraDto}> en el FeignClient.
|
|
203
|
+
# • Default: false.
|
|
204
|
+
#
|
|
205
|
+
# fields: omitidos → retorno void en la interfaz y en el FeignClient.
|
|
206
|
+
#
|
|
207
|
+
# nestedTypes:
|
|
208
|
+
# • Genera un record auxiliar en application/dtos/ por cada entrada.
|
|
209
|
+
# • Se deduplican globalmente dentro del mismo service:.
|
|
210
|
+
# • Misma sintaxis que en listeners:.
|
|
211
|
+
#
|
|
212
|
+
# ─── CONTRASTE: async vs sync ────────────────────────────────────────────────
|
|
213
|
+
#
|
|
214
|
+
# domain.yaml
|
|
215
|
+
# ├── aggregates:
|
|
216
|
+
# │ └── events: → Domain Events que PRODUCE (async, broker)
|
|
217
|
+
# ├── listeners: → Integration Events que CONSUME (async, broker)
|
|
218
|
+
# └── ports: → Servicios HTTP que LLAMA (sync, Feign)
|
|
219
|
+
|
|
220
|
+
aggregates:
|
|
221
|
+
- name: Reservation
|
|
222
|
+
entities:
|
|
223
|
+
- name: reservation
|
|
224
|
+
isRoot: true
|
|
225
|
+
tableName: reservations
|
|
226
|
+
audit:
|
|
227
|
+
enabled: true
|
|
228
|
+
fields:
|
|
229
|
+
- name: id
|
|
230
|
+
type: String
|
|
231
|
+
- name: screeningId
|
|
232
|
+
type: String
|
|
233
|
+
- name: customerId
|
|
234
|
+
type: String
|
|
235
|
+
- name: status
|
|
236
|
+
type: ReservationStatus
|
|
237
|
+
readOnly: true
|
|
238
|
+
- name: totalAmount
|
|
239
|
+
type: BigDecimal
|
|
240
|
+
readOnly: true
|
|
241
|
+
defaultValue: "0.00"
|
|
242
|
+
|
|
243
|
+
enums:
|
|
244
|
+
- name: ReservationStatus
|
|
245
|
+
initialValue: PENDING
|
|
246
|
+
values: [PENDING, CONFIRMED, CANCELLED, EXPIRED]
|
|
247
|
+
transitions:
|
|
248
|
+
- from: PENDING
|
|
249
|
+
to: CONFIRMED
|
|
250
|
+
method: confirm
|
|
251
|
+
- from: PENDING
|
|
252
|
+
to: CANCELLED
|
|
253
|
+
method: cancel
|
|
254
|
+
- from: PENDING
|
|
255
|
+
to: EXPIRED
|
|
256
|
+
method: expire
|
|
257
|
+
|
|
258
|
+
events:
|
|
259
|
+
- name: ReservationConfirmed
|
|
260
|
+
fields:
|
|
261
|
+
- name: reservationId
|
|
262
|
+
type: String
|
|
263
|
+
- name: confirmedAt
|
|
264
|
+
type: LocalDateTime
|
|
265
|
+
|
|
266
|
+
- name: ReservationCancelled
|
|
267
|
+
fields:
|
|
268
|
+
- name: reservationId
|
|
269
|
+
type: String
|
|
270
|
+
- name: reason
|
|
271
|
+
type: String
|
|
272
|
+
|
|
273
|
+
# ─── Servicios HTTP que este módulo LLAMA ─────────────────────────────────────
|
|
274
|
+
# Nivel raíz, sibling de aggregates: y listeners:
|
|
275
|
+
# baseUrl: se declara en la primera entrada de cada service:.
|
|
276
|
+
|
|
277
|
+
ports:
|
|
278
|
+
|
|
279
|
+
# ── ScreeningService (módulo interno: screenings) ─────────────────────────
|
|
280
|
+
|
|
281
|
+
- name: findScreeningById # nombre del método en la interfaz (camelCase)
|
|
282
|
+
service: ScreeningService # agrupa en un solo FeignClient (PascalCase)
|
|
283
|
+
target: screenings # módulo o servicio destino (referencia documental)
|
|
284
|
+
baseUrl: http://localhost:8081 # base URL → parameters/*/urls.yaml (primera entrada del service)
|
|
285
|
+
http: GET /screenings/{id} # verbo HTTP + path
|
|
286
|
+
fields: # campos de respuesta → FindScreeningByIdResponseDto.java
|
|
287
|
+
- name: id
|
|
288
|
+
type: String
|
|
289
|
+
- name: movieId
|
|
290
|
+
type: String
|
|
291
|
+
- name: theaterId
|
|
292
|
+
type: String
|
|
293
|
+
- name: startTime
|
|
294
|
+
type: LocalDateTime
|
|
295
|
+
- name: endTime
|
|
296
|
+
type: LocalDateTime
|
|
297
|
+
- name: basePrice
|
|
298
|
+
type: BigDecimal
|
|
299
|
+
- name: status
|
|
300
|
+
type: String
|
|
301
|
+
- name: isPrivateEvent
|
|
302
|
+
type: Boolean
|
|
303
|
+
|
|
304
|
+
- name: findAvailableSeats
|
|
305
|
+
service: ScreeningService # misma interfaz y FeignClient que arriba
|
|
306
|
+
target: screenings
|
|
307
|
+
# baseUrl omitida — ya declarada en la primera entrada de este service
|
|
308
|
+
http: GET /screenings/{id}/seats
|
|
309
|
+
returnList: true # → List<Seat> en la interfaz, List<FindAvailableSeatDto> en Feign
|
|
310
|
+
domainType: Seat # sobrescribe la derivación automática (findAvailableSeats → Seat)
|
|
311
|
+
fields:
|
|
312
|
+
- name: seatId
|
|
313
|
+
type: String
|
|
314
|
+
- name: seatRow
|
|
315
|
+
type: String
|
|
316
|
+
- name: seatNumber
|
|
317
|
+
type: Integer
|
|
318
|
+
- name: seatType
|
|
319
|
+
type: String
|
|
320
|
+
- name: availabilityStatus
|
|
321
|
+
type: String
|
|
322
|
+
|
|
323
|
+
- name: checkPrivateEventAvailability
|
|
324
|
+
service: ScreeningService
|
|
325
|
+
target: screenings
|
|
326
|
+
http: GET /screenings/{id}/private-event-availability
|
|
327
|
+
fields:
|
|
328
|
+
- name: screeningId
|
|
329
|
+
type: String
|
|
330
|
+
- name: isAvailable
|
|
331
|
+
type: Boolean
|
|
332
|
+
- name: totalCapacity
|
|
333
|
+
type: Integer
|
|
334
|
+
- name: unavailableSeatsCount
|
|
335
|
+
type: Integer
|
|
336
|
+
|
|
337
|
+
# ── CustomerService (módulo interno: customers) ───────────────────────────
|
|
338
|
+
|
|
339
|
+
- name: findCustomerById
|
|
340
|
+
service: CustomerService
|
|
341
|
+
target: customers
|
|
342
|
+
baseUrl: http://localhost:8082
|
|
343
|
+
http: GET /customers/{id}
|
|
344
|
+
fields:
|
|
345
|
+
- name: id
|
|
346
|
+
type: String
|
|
347
|
+
- name: firstName
|
|
348
|
+
type: String
|
|
349
|
+
- name: lastName
|
|
350
|
+
type: String
|
|
351
|
+
- name: email
|
|
352
|
+
type: String
|
|
353
|
+
- name: status
|
|
354
|
+
type: String
|
|
355
|
+
|
|
356
|
+
# ── PaymentGateway (servicio externo) ─────────────────────────────────────
|
|
357
|
+
|
|
358
|
+
- name: processPayment
|
|
359
|
+
service: PaymentGateway
|
|
360
|
+
target: payment-gateway-external
|
|
361
|
+
baseUrl: https://api.payments.example.com
|
|
362
|
+
http: POST /payments
|
|
363
|
+
body: # @RequestBody → ProcessPaymentRequestDto.java
|
|
364
|
+
- name: reservationId
|
|
365
|
+
type: String
|
|
366
|
+
- name: customerId
|
|
367
|
+
type: String
|
|
368
|
+
- name: amount
|
|
369
|
+
type: BigDecimal
|
|
370
|
+
- name: currency
|
|
371
|
+
type: String
|
|
372
|
+
- name: paymentMethod
|
|
373
|
+
type: PaymentMethodInput # tipo objeto → declarar en nestedTypes:
|
|
374
|
+
nestedTypes: # genera PaymentMethodInput.java en application/dtos/
|
|
375
|
+
- name: paymentMethodInput # camelCase → normalizado a PaymentMethodInput
|
|
376
|
+
fields:
|
|
377
|
+
- name: type
|
|
378
|
+
type: String
|
|
379
|
+
- name: cardToken
|
|
380
|
+
type: String
|
|
381
|
+
- name: cardLastFour
|
|
382
|
+
type: String
|
|
383
|
+
fields: # infra DTO → infrastructure/adapters/paymentGateway/ProcessPaymentDto.java
|
|
384
|
+
- name: paymentId
|
|
385
|
+
type: String
|
|
386
|
+
- name: status
|
|
387
|
+
type: String
|
|
388
|
+
- name: processedAt
|
|
389
|
+
type: LocalDateTime
|
|
390
|
+
- name: transactionCode
|
|
391
|
+
type: String
|
|
392
|
+
|
|
393
|
+
- name: findPaymentStatus
|
|
394
|
+
service: PaymentGateway
|
|
395
|
+
target: payment-gateway-external
|
|
396
|
+
# baseUrl omitida — ya declarada en processPayment (misma entrada de service)
|
|
397
|
+
http: GET /payments/{id}
|
|
398
|
+
domainType: PaymentStatus # override: sin esto, deriveDomainType elimina "Status" y colisiona con Payment
|
|
399
|
+
fields:
|
|
400
|
+
- name: paymentId
|
|
401
|
+
type: String
|
|
402
|
+
- name: status
|
|
403
|
+
type: String
|
|
404
|
+
- name: processedAt
|
|
405
|
+
type: LocalDateTime
|
|
406
|
+
- name: amount
|
|
407
|
+
type: BigDecimal
|
|
408
|
+
|
|
409
|
+
- name: cancelPayment
|
|
410
|
+
service: PaymentGateway
|
|
411
|
+
target: payment-gateway-external
|
|
412
|
+
http: DELETE /payments/{id}
|
|
413
|
+
# body: omitido — sin @RequestBody
|
|
414
|
+
# fields: omitido — retorno void en la interfaz y en el FeignClient
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# EJEMPLO 8: DOMINIO CON SOFT DELETE Y AUDITORÍA
|
|
2
|
-
#
|
|
3
|
-
# Ideal para:
|
|
1
|
+
# EJEMPLO 8: DOMINIO CON SOFT DELETE Y AUDITORÍA
|
|
2
|
+
# Validar borrado lógico: registros marcados como eliminados no aparecen en queries.
|
|
3
|
+
# Ideal para: sistemas con normativa de retención de datos o restauración de registros.
|
|
4
4
|
|
|
5
5
|
aggregates:
|
|
6
6
|
- name: Document
|
|
@@ -8,7 +8,9 @@ aggregates:
|
|
|
8
8
|
- name: Document
|
|
9
9
|
isRoot: true
|
|
10
10
|
tableName: documents
|
|
11
|
-
|
|
11
|
+
hasSoftDelete: true # ✅ Activa borrado lógico (deletedAt)
|
|
12
|
+
audit:
|
|
13
|
+
enabled: true
|
|
12
14
|
fields:
|
|
13
15
|
- name: id
|
|
14
16
|
type: String
|
|
@@ -24,14 +26,6 @@ aggregates:
|
|
|
24
26
|
type: Integer
|
|
25
27
|
- name: authorId
|
|
26
28
|
type: String
|
|
27
|
-
- name: lastModifiedBy
|
|
28
|
-
type: String
|
|
29
|
-
- name: isDeleted
|
|
30
|
-
type: Boolean
|
|
31
|
-
- name: deletedAt
|
|
32
|
-
type: LocalDateTime
|
|
33
|
-
- name: deletedBy
|
|
34
|
-
type: String
|
|
35
29
|
- name: metadata
|
|
36
30
|
type: DocumentMetadata
|
|
37
31
|
- name: tags
|
|
@@ -42,15 +36,11 @@ aggregates:
|
|
|
42
36
|
mappedBy: document
|
|
43
37
|
cascade: [PERSIST, MERGE]
|
|
44
38
|
fetch: LAZY
|
|
45
|
-
- type: OneToMany
|
|
46
|
-
target: Attachment
|
|
47
|
-
mappedBy: document
|
|
48
|
-
cascade: [PERSIST, MERGE, REMOVE]
|
|
49
|
-
fetch: LAZY
|
|
50
39
|
|
|
51
40
|
- name: Revision
|
|
52
41
|
tableName: document_revisions
|
|
53
|
-
|
|
42
|
+
audit:
|
|
43
|
+
enabled: true
|
|
54
44
|
fields:
|
|
55
45
|
- name: id
|
|
56
46
|
type: Long
|
|
@@ -64,27 +54,6 @@ aggregates:
|
|
|
64
54
|
type: String
|
|
65
55
|
- name: comment
|
|
66
56
|
type: String
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- name: Attachment
|
|
70
|
-
tableName: document_attachments
|
|
71
|
-
auditable: true
|
|
72
|
-
fields:
|
|
73
|
-
- name: id
|
|
74
|
-
type: Long
|
|
75
|
-
- name: fileName
|
|
76
|
-
type: String
|
|
77
|
-
- name: fileSize
|
|
78
|
-
type: Long
|
|
79
|
-
- name: mimeType
|
|
80
|
-
type: String
|
|
81
|
-
- name: storageUrl
|
|
82
|
-
type: String
|
|
83
|
-
- name: uploadedBy
|
|
84
|
-
type: String
|
|
85
|
-
- name: isDeleted
|
|
86
|
-
type: Boolean
|
|
87
|
-
|
|
88
57
|
|
|
89
58
|
valueObjects:
|
|
90
59
|
- name: DocumentMetadata
|
|
@@ -97,8 +66,6 @@ aggregates:
|
|
|
97
66
|
type: String
|
|
98
67
|
- name: expirationDate
|
|
99
68
|
type: LocalDate
|
|
100
|
-
- name: reviewDate
|
|
101
|
-
type: LocalDate
|
|
102
69
|
|
|
103
70
|
enums:
|
|
104
71
|
- name: DocumentType
|
|
@@ -107,16 +74,52 @@ aggregates:
|
|
|
107
74
|
- INVOICE
|
|
108
75
|
- REPORT
|
|
109
76
|
- PROPOSAL
|
|
110
|
-
- MEMO
|
|
111
|
-
- POLICY
|
|
112
|
-
- PROCEDURE
|
|
113
77
|
- OTHER
|
|
114
78
|
|
|
115
79
|
- name: DocumentStatus
|
|
80
|
+
initialValue: DRAFT
|
|
81
|
+
transitions:
|
|
82
|
+
- from: DRAFT
|
|
83
|
+
to: IN_REVIEW
|
|
84
|
+
method: submitForReview
|
|
85
|
+
- from: IN_REVIEW
|
|
86
|
+
to: APPROVED
|
|
87
|
+
method: approve
|
|
88
|
+
- from: IN_REVIEW
|
|
89
|
+
to: DRAFT
|
|
90
|
+
method: returnToDraft
|
|
91
|
+
- from: APPROVED
|
|
92
|
+
to: PUBLISHED
|
|
93
|
+
method: publish
|
|
116
94
|
values:
|
|
117
95
|
- DRAFT
|
|
118
96
|
- IN_REVIEW
|
|
119
97
|
- APPROVED
|
|
120
98
|
- PUBLISHED
|
|
99
|
+
|
|
100
|
+
# Comportamiento generado por hasSoftDelete: true
|
|
101
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
102
|
+
# Entidad de dominio (Document.java):
|
|
103
|
+
# - Campo private LocalDateTime deletedAt; (inyectado automáticamente)
|
|
104
|
+
# - Métodos softDelete() e isDeleted() generados
|
|
105
|
+
# - deletedAt excluido del constructor de creación y de CreateDocumentCommand
|
|
106
|
+
# - deletedAt NO aparece en DocumentResponseDto
|
|
107
|
+
#
|
|
108
|
+
# Entidad JPA (DocumentJpa.java):
|
|
109
|
+
# - @SQLRestriction("deleted_at IS NULL") → Hibernate filtra eliminados en TODAS las queries
|
|
110
|
+
# - Campo @Column(name = "deleted_at") private LocalDateTime deletedAt;
|
|
111
|
+
#
|
|
112
|
+
# Repositorio (DocumentRepository.java):
|
|
113
|
+
# - Sin deleteById() — la eliminación física no está disponible
|
|
114
|
+
#
|
|
115
|
+
# Handler (DeleteDocumentCommandHandler.java):
|
|
116
|
+
# - findById → entity.softDelete() → repository.save(entity)
|
|
117
|
+
# - Nunca llama deleteById()
|
|
118
|
+
#
|
|
119
|
+
# Resultado en API:
|
|
120
|
+
# DELETE /documents/{id} → 200 OK, deletedAt seteado, registro invisible
|
|
121
|
+
# GET /documents/{id} → 404 Not Found (filtrado por @SQLRestriction)
|
|
122
|
+
# GET /documents → no retorna documentos eliminados
|
|
123
|
+
|
|
121
124
|
- ARCHIVED
|
|
122
125
|
- OBSOLETE
|