eva4j 1.0.13 → 1.0.14

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 (44) hide show
  1. package/AGENTS.md +51 -9
  2. package/DOMAIN_YAML_GUIDE.md +150 -0
  3. package/bin/eva4j.js +31 -1
  4. package/design-system.md +797 -0
  5. package/docs/commands/EVALUATE_SYSTEM.md +542 -0
  6. package/docs/commands/GENERATE_ENTITIES.md +196 -0
  7. package/docs/commands/INDEX.md +10 -1
  8. package/examples/domain-endpoints-relations.yaml +353 -0
  9. package/examples/domain-endpoints-versioned.yaml +144 -0
  10. package/examples/domain-endpoints.yaml +135 -0
  11. package/examples/system.yaml +289 -0
  12. package/package.json +1 -1
  13. package/src/commands/create.js +6 -3
  14. package/src/commands/evaluate-system.js +384 -0
  15. package/src/commands/generate-entities.js +677 -14
  16. package/src/commands/generate-kafka-event.js +59 -5
  17. package/src/commands/generate-system.js +243 -0
  18. package/src/generators/base-generator.js +9 -1
  19. package/src/utils/naming.js +3 -2
  20. package/src/utils/system-validator.js +314 -0
  21. package/src/utils/yaml-to-entity.js +31 -2
  22. package/templates/aggregate/AggregateRepository.java.ejs +5 -0
  23. package/templates/aggregate/AggregateRepositoryImpl.java.ejs +9 -0
  24. package/templates/aggregate/DomainEventHandler.java.ejs +24 -20
  25. package/templates/aggregate/JpaRepository.java.ejs +5 -0
  26. package/templates/base/root/skill-build-domain-yaml-references-generate-entities.md.ejs +1103 -0
  27. package/templates/base/root/skill-build-domain-yaml.ejs +292 -0
  28. package/templates/base/root/skill-build-system-yaml.ejs +252 -0
  29. package/templates/base/root/system.yaml.ejs +97 -0
  30. package/templates/crud/EndpointsController.java.ejs +178 -0
  31. package/templates/crud/FindByQuery.java.ejs +17 -0
  32. package/templates/crud/FindByQueryHandler.java.ejs +57 -0
  33. package/templates/crud/ScaffoldCommand.java.ejs +12 -0
  34. package/templates/crud/ScaffoldCommandHandler.java.ejs +43 -0
  35. package/templates/crud/ScaffoldQuery.java.ejs +12 -0
  36. package/templates/crud/ScaffoldQueryHandler.java.ejs +40 -0
  37. package/templates/crud/SubEntityAddCommand.java.ejs +17 -0
  38. package/templates/crud/SubEntityAddCommandHandler.java.ejs +43 -0
  39. package/templates/crud/SubEntityRemoveCommand.java.ejs +9 -0
  40. package/templates/crud/SubEntityRemoveCommandHandler.java.ejs +42 -0
  41. package/templates/crud/TransitionCommand.java.ejs +9 -0
  42. package/templates/crud/TransitionCommandHandler.java.ejs +39 -0
  43. package/templates/evaluate/report.html.ejs +971 -0
  44. package/templates/kafka-event/Event.java.ejs +7 -0
@@ -0,0 +1,144 @@
1
+ # EJEMPLO: ENDPOINTS CON VERSIONADO MÚLTIPLE (v1 + v2)
2
+ # Demuestra cómo v1 y v2 coexisten generando controladores independientes.
3
+ #
4
+ # REGLA ANTI-DUPLICADO:
5
+ # Si un useCase declarado en v2 ya fue generado en v1, el generador
6
+ # omite la creación del Command/Query + Handler y SOLO agrega la
7
+ # referencia en el controlador de v2.
8
+ #
9
+ # RESULTADO:
10
+ # - 1 controlador por versión (ProductV1Controller, ProductV2Controller)
11
+ # - Use cases propios de cada versión generados una sola vez
12
+ # - Use cases compartidos referenciados sin regenerar
13
+
14
+ aggregates:
15
+ - name: Product
16
+ entities:
17
+ - name: product
18
+ isRoot: true
19
+ tableName: products
20
+ audit:
21
+ enabled: true
22
+ fields:
23
+ - name: id
24
+ type: String
25
+ - name: name
26
+ type: String
27
+ validations:
28
+ - type: NotBlank
29
+ - name: description
30
+ type: String
31
+ - name: price
32
+ type: BigDecimal
33
+ validations:
34
+ - type: Positive
35
+ - name: stock
36
+ type: Integer
37
+ readOnly: true
38
+ defaultValue: 0
39
+ - name: active
40
+ type: Boolean
41
+ readOnly: true
42
+ defaultValue: true
43
+
44
+ endpoints:
45
+ basePath: /products
46
+ versions:
47
+ # ── v1: CRUD estándar ──────────────────────────────────────────────────
48
+ - version: v1
49
+ operations:
50
+ - method: GET
51
+ path: /{id}
52
+ description: "Obtener producto por ID"
53
+ useCase: FindProductById # completo
54
+
55
+ - method: GET
56
+ path: /
57
+ description: "Listar productos activos"
58
+ useCase: FindAllProducts # completo
59
+
60
+ - method: POST
61
+ path: /
62
+ description: "Crear producto"
63
+ useCase: CreateProduct # completo
64
+
65
+ - method: PUT
66
+ path: /{id}
67
+ description: "Actualizar datos del producto"
68
+ useCase: UpdateProduct # completo
69
+
70
+ - method: DELETE
71
+ path: /{id}
72
+ description: "Eliminar producto"
73
+ useCase: DeleteProduct # completo
74
+
75
+ # ── v2: nuevas operaciones + reuso de use cases de v1 ─────────────────
76
+ - version: v2
77
+ operations:
78
+ - method: GET
79
+ path: /{id}
80
+ description: "Producto con categorías y variantes embebidas"
81
+ useCase: FindProductByIdV2 # NUEVO handler — shape de respuesta distinto
82
+
83
+ - method: GET
84
+ path: /
85
+ description: "Listado con filtros avanzados y metadata extendida"
86
+ useCase: FindAllProductsV2 # NUEVO handler — parámetros de búsqueda distintos
87
+
88
+ - method: POST
89
+ path: /
90
+ description: "Crear producto (misma lógica que v1)"
91
+ useCase: CreateProduct # REUTILIZA v1 — no regenera handler
92
+
93
+ - method: PUT
94
+ path: /{id}
95
+ description: "Actualizar producto (misma lógica que v1)"
96
+ useCase: UpdateProduct # REUTILIZA v1 — no regenera handler
97
+
98
+ - method: DELETE
99
+ path: /{id}
100
+ description: "Eliminar producto (misma lógica que v1)"
101
+ useCase: DeleteProduct # REUTILIZA v1 — no regenera handler
102
+
103
+ - method: PUT
104
+ path: /{id}/activate
105
+ description: "Activar un producto desactivado"
106
+ useCase: ActivateProduct # NUEVO scaffold — TODO: product.activate()
107
+
108
+ - method: PUT
109
+ path: /{id}/deactivate
110
+ description: "Desactivar un producto activo"
111
+ useCase: DeactivateProduct # NUEVO scaffold — TODO: product.deactivate()
112
+
113
+ # Archivos generados:
114
+ #
115
+ # infrastructure/rest/controllers/product/
116
+ # ├── v1/ProductV1Controller.java ← 5 endpoints (v1)
117
+ # └── v2/ProductV2Controller.java ← 7 endpoints (v2)
118
+ #
119
+ # application/commands/ (solo use cases ÚNICOS — sin duplicados)
120
+ # ├── CreateProductCommand.java
121
+ # ├── UpdateProductCommand.java
122
+ # ├── DeleteProductCommand.java
123
+ # ├── ActivateProductCommand.java ← solo v2
124
+ # └── DeactivateProductCommand.java ← solo v2
125
+ #
126
+ # application/queries/ (solo use cases ÚNICOS)
127
+ # ├── FindProductByIdQuery.java
128
+ # ├── FindAllProductsQuery.java
129
+ # ├── FindProductByIdV2Query.java ← solo v2
130
+ # └── FindAllProductsV2Query.java ← solo v2
131
+ #
132
+ # application/usecases/
133
+ # ├── CreateProductCommandHandler.java ← completo
134
+ # ├── UpdateProductCommandHandler.java ← completo
135
+ # ├── DeleteProductCommandHandler.java ← completo
136
+ # ├── ActivateProductCommandHandler.java ← scaffold + TODO
137
+ # ├── DeactivateProductCommandHandler.java ← scaffold + TODO
138
+ # ├── FindProductByIdQueryHandler.java ← completo
139
+ # ├── FindAllProductsQueryHandler.java ← completo
140
+ # ├── FindProductByIdV2QueryHandler.java ← completo (shape distinto)
141
+ # └── FindAllProductsV2QueryHandler.java ← completo (filtros extendidos)
142
+ #
143
+ # CreateProduct, UpdateProduct, DeleteProduct aparecen en v2 pero ya
144
+ # existen de v1 → ProductV2Controller los inyecta sin regenerar handlers.
@@ -0,0 +1,135 @@
1
+ # EJEMPLO: ENDPOINTS DECLARATIVOS — CASO BÁSICO (una versión)
2
+ # Módulo de pedidos con operaciones específicas del negocio.
3
+ #
4
+ # COMPORTAMIENTO CONDICIONAL:
5
+ #
6
+ # SIN sección endpoints: → genera 5 CRUD fijos por defecto:
7
+ # CreateOrder, UpdateOrder, DeleteOrder,
8
+ # FindOrderById, FindAllOrders
9
+ #
10
+ # CON sección endpoints: → genera ÚNICAMENTE las operaciones
11
+ # declaradas en operations[] — ni más, ni menos.
12
+ #
13
+ # TYPE INFERIDO desde method:
14
+ # GET → query
15
+ # POST/PUT/DELETE/PATCH → command
16
+ #
17
+ # SCAFFOLD vs COMPLETO:
18
+ # Use cases estándar (Create*, Update*, Delete*, FindById*, FindAll*):
19
+ # → implementación completa con lógica de repositorio
20
+ # Use cases custom (ConfirmOrder, CancelOrder, etc.):
21
+ # → scaffold con // TODO apuntando al método de negocio sugerido
22
+
23
+ aggregates:
24
+ - name: Order
25
+ entities:
26
+ - name: order
27
+ isRoot: true
28
+ tableName: orders
29
+ audit:
30
+ enabled: true
31
+ trackUser: true
32
+ fields:
33
+ - name: id
34
+ type: String
35
+ - name: orderNumber
36
+ type: String
37
+ validations:
38
+ - type: NotBlank
39
+ message: "Order number is required"
40
+ - name: customerId
41
+ type: String
42
+ reference:
43
+ aggregate: Customer
44
+ module: customers
45
+ - name: status
46
+ type: OrderStatus
47
+ readOnly: true
48
+ - name: totalAmount
49
+ type: BigDecimal
50
+ readOnly: true
51
+ defaultValue: "0.00"
52
+
53
+ enums:
54
+ - name: OrderStatus
55
+ initialValue: PENDING
56
+ transitions:
57
+ - from: PENDING
58
+ to: CONFIRMED
59
+ method: confirm
60
+ - from: [PENDING, CONFIRMED]
61
+ to: CANCELLED
62
+ method: cancel
63
+ values: [PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED]
64
+
65
+ events:
66
+ - name: OrderPlacedEvent
67
+ fields:
68
+ - name: orderId
69
+ type: String
70
+ - name: customerId
71
+ type: String
72
+ kafka: true
73
+
74
+ # ─── Sección endpoints ─────────────────────────────────────────────────────
75
+ # Presente → genera solo los use cases declarados
76
+ # Ausente → comportamiento actual (5 CRUD por defecto)
77
+ # ──────────────────────────────────────────────────────────────────────────
78
+
79
+ endpoints:
80
+ basePath: /orders
81
+ versions:
82
+ - version: v1
83
+ operations:
84
+ - method: GET
85
+ path: /{id}
86
+ description: "Obtener detalle de un pedido"
87
+ useCase: FindOrderById # completo: FindOrderByIdQuery + Handler
88
+
89
+ - method: GET
90
+ path: /
91
+ description: "Listar pedidos con paginación"
92
+ useCase: FindAllOrders # completo: FindAllOrdersQuery + Handler
93
+
94
+ - method: POST
95
+ path: /
96
+ description: "Crear nuevo pedido"
97
+ useCase: CreateOrder # completo: CreateOrderCommand + Handler
98
+
99
+ - method: PUT
100
+ path: /{id}/confirm
101
+ description: "Confirmar pedido pendiente — PENDING → CONFIRMED"
102
+ useCase: ConfirmOrder # scaffold: TODO → order.confirm(); repo.save(order)
103
+
104
+ - method: PUT
105
+ path: /{id}/cancel
106
+ description: "Cancelar pedido — [PENDING, CONFIRMED] → CANCELLED"
107
+ useCase: CancelOrder # scaffold: TODO → order.cancel(); repo.save(order)
108
+
109
+ - method: DELETE
110
+ path: /{id}
111
+ description: "Eliminar pedido"
112
+ useCase: DeleteOrder # completo: DeleteOrderCommand + Handler
113
+
114
+ # Archivos generados con esta configuración:
115
+ #
116
+ # infrastructure/rest/controllers/order/v1/
117
+ # └── OrderV1Controller.java ← 6 métodos exactos
118
+ #
119
+ # application/commands/
120
+ # ├── CreateOrderCommand.java
121
+ # ├── ConfirmOrderCommand.java
122
+ # ├── CancelOrderCommand.java
123
+ # └── DeleteOrderCommand.java
124
+ #
125
+ # application/queries/
126
+ # ├── FindOrderByIdQuery.java
127
+ # └── FindAllOrdersQuery.java
128
+ #
129
+ # application/usecases/
130
+ # ├── CreateOrderCommandHandler.java ← implementación completa
131
+ # ├── ConfirmOrderCommandHandler.java ← scaffold + TODO
132
+ # ├── CancelOrderCommandHandler.java ← scaffold + TODO
133
+ # ├── DeleteOrderCommandHandler.java ← implementación completa
134
+ # ├── FindOrderByIdQueryHandler.java ← implementación completa
135
+ # └── FindAllOrdersQueryHandler.java ← implementación completa
@@ -0,0 +1,289 @@
1
+ system:
2
+ name: test-eva
3
+ groupId: com.example
4
+ javaVersion: 21
5
+ springBootVersion: 3.5.5
6
+ database: postgresql
7
+
8
+ messaging:
9
+ enabled: true
10
+ broker: kafka
11
+ kafka:
12
+ bootstrapServers: localhost:9092
13
+ defaultGroupId: test-eva
14
+ topicPrefix: cinema
15
+
16
+ modules:
17
+
18
+ # ─────────────────────────────────────────────
19
+ # CATÁLOGO
20
+ # ─────────────────────────────────────────────
21
+
22
+ - name: movies
23
+ description: "Catálogo de películas: títulos, géneros, clasificaciones, sinopsis y duración"
24
+ exposes:
25
+ - method: GET
26
+ path: /movies
27
+ useCase: FindAllMovies
28
+ description: "Listar películas con filtros por género, clasificación y estado de estreno"
29
+ - method: GET
30
+ path: /movies/{id}
31
+ useCase: GetMovie
32
+ description: "Obtener detalle completo de una película"
33
+ - method: POST
34
+ path: /movies
35
+ useCase: CreateMovie
36
+ description: "Registrar nueva película en el catálogo"
37
+ - method: PUT
38
+ path: /movies/{id}
39
+ useCase: UpdateMovie
40
+ description: "Actualizar información de una película"
41
+ - method: DELETE
42
+ path: /movies/{id}
43
+ useCase: DeleteMovie
44
+ description: "Retirar una película del catálogo"
45
+
46
+ - name: theaters
47
+ description: "Salas de cine: configuración de capacidad, tipo de sala (2D, 3D, IMAX) y mapa de asientos"
48
+ exposes:
49
+ - method: GET
50
+ path: /theaters
51
+ useCase: FindAllTheaters
52
+ description: "Listar todas las salas disponibles"
53
+ - method: GET
54
+ path: /theaters/{id}
55
+ useCase: GetTheater
56
+ description: "Obtener configuración y capacidad de una sala"
57
+ - method: POST
58
+ path: /theaters
59
+ useCase: CreateTheater
60
+ description: "Registrar nueva sala de cine"
61
+ - method: PUT
62
+ path: /theaters/{id}
63
+ useCase: UpdateTheater
64
+ description: "Actualizar configuración de una sala"
65
+
66
+ # ─────────────────────────────────────────────
67
+ # PROGRAMACIÓN
68
+ # ─────────────────────────────────────────────
69
+
70
+ - name: screenings
71
+ description: "Funciones programadas: asocia película + sala + horario, gestiona disponibilidad, precios y bloqueo exclusivo para eventos privados"
72
+ exposes:
73
+ - method: GET
74
+ path: /screenings
75
+ useCase: FindAllScreenings
76
+ description: "Listar funciones con filtros por película, sala y fecha"
77
+ - method: GET
78
+ path: /screenings/{id}
79
+ useCase: GetScreening
80
+ description: "Obtener detalle de una función (película, sala, horario, precio base)"
81
+ - method: GET
82
+ path: /screenings/{id}/seats
83
+ useCase: GetAvailableSeats
84
+ description: "Consultar mapa de asientos con disponibilidad en tiempo real"
85
+ - method: POST
86
+ path: /screenings
87
+ useCase: ScheduleScreening
88
+ description: "Programar una nueva función"
89
+ - method: PUT
90
+ path: /screenings/{id}/cancel
91
+ useCase: CancelScreening
92
+ description: "Cancelar una función programada y liberar todas las reservas"
93
+ - method: GET
94
+ path: /screenings/{id}/private-event-availability
95
+ useCase: CheckPrivateEventAvailability
96
+ description: "Verificar si la sala completa está libre de reservas individuales y puede ser bloqueada para un evento privado" # ★ NUEVO
97
+ - method: PUT
98
+ path: /screenings/{id}/lock
99
+ useCase: LockScreeningForPrivateEvent
100
+ description: "Bloquear toda la sala para un evento privado, impidiendo nuevas reservas individuales sobre esa función" # ★ NUEVO
101
+
102
+ # ─────────────────────────────────────────────
103
+ # CLIENTES
104
+ # ─────────────────────────────────────────────
105
+
106
+ - name: customers
107
+ description: "Registro y perfil de clientes: datos personales, historial de compras e historial de puntos"
108
+ exposes:
109
+ - method: POST
110
+ path: /customers
111
+ useCase: CreateCustomer
112
+ description: "Registrar nuevo cliente"
113
+ - method: GET
114
+ path: /customers/{id}
115
+ useCase: GetCustomer
116
+ description: "Obtener perfil del cliente"
117
+ - method: GET
118
+ path: /customers
119
+ useCase: FindAllCustomers
120
+ description: "Listar clientes con filtros"
121
+ - method: PUT
122
+ path: /customers/{id}
123
+ useCase: UpdateCustomer
124
+ description: "Actualizar datos personales del cliente"
125
+
126
+ # ─────────────────────────────────────────────
127
+ # RESERVAS
128
+ # ─────────────────────────────────────────────
129
+
130
+ - name: reservations
131
+ description: "Ciclo de vida de la reserva: selección y bloqueo de asientos, confirmación, cancelación y reserva exclusiva de sala completa para eventos privados"
132
+ exposes:
133
+ - method: POST
134
+ path: /reservations
135
+ useCase: CreateReservation
136
+ description: "Iniciar reserva: seleccionar función y asientos, bloqueo temporal (15 min)"
137
+ - method: GET
138
+ path: /reservations/{id}
139
+ useCase: GetReservation
140
+ description: "Consultar estado e información de una reserva"
141
+ - method: GET
142
+ path: /reservations
143
+ useCase: FindAllReservations
144
+ description: "Listar reservas con filtros por cliente, función y estado"
145
+ - method: PUT
146
+ path: /reservations/{id}/confirm
147
+ useCase: ConfirmReservation
148
+ description: "Confirmar la reserva después de recibir pago aprobado"
149
+ - method: PUT
150
+ path: /reservations/{id}/cancel
151
+ useCase: CancelReservation
152
+ description: "Cancelar la reserva y liberar los asientos seleccionados"
153
+ - method: PUT
154
+ path: /reservations/{id}/expire
155
+ useCase: ExpireReservation
156
+ description: "Expirar reserva no pagada dentro del tiempo límite de bloqueo"
157
+ - method: POST
158
+ path: /reservations/private-events
159
+ useCase: CreatePrivateEventReservation
160
+ description: "Reservar toda la sala para un evento privado: ocupa la capacidad total de la función de forma exclusiva" # ★ NUEVO
161
+
162
+ # ─────────────────────────────────────────────
163
+ # PAGOS
164
+ # ─────────────────────────────────────────────
165
+
166
+ - name: payments
167
+ description: "Procesamiento de pagos: integración con pasarela externa, aprobaciones y reembolsos"
168
+ exposes:
169
+ - method: POST
170
+ path: /payments
171
+ useCase: InitiatePayment
172
+ description: "Iniciar proceso de pago vinculado a una reserva"
173
+ - method: GET
174
+ path: /payments/{id}
175
+ useCase: GetPayment
176
+ description: "Consultar estado de un pago"
177
+ - method: GET
178
+ path: /payments
179
+ useCase: FindAllPayments
180
+ description: "Listar pagos con filtros por estado y fecha"
181
+ - method: PUT
182
+ path: /payments/{id}/approve
183
+ useCase: ApprovePayment
184
+ description: "Registrar aprobación de pago recibida desde la pasarela"
185
+ - method: PUT
186
+ path: /payments/{id}/reject
187
+ useCase: RejectPayment
188
+ description: "Registrar rechazo de pago recibido desde la pasarela"
189
+ - method: PUT
190
+ path: /payments/{id}/refund
191
+ useCase: ProcessRefund
192
+ description: "Procesar reembolso por cancelación de reserva o función"
193
+
194
+ # ─────────────────────────────────────────────
195
+ # NOTIFICACIONES
196
+ # ─────────────────────────────────────────────
197
+
198
+ - name: notifications
199
+ description: "Envío de notificaciones por email y SMS: confirmaciones, tickets QR, recordatorios y alertas de cancelación"
200
+
201
+ integrations:
202
+ async:
203
+ # Reserva creada → pago espera cobro; notificación informa el bloqueo de asientos
204
+ - event: ReservationCreatedEvent
205
+ producer: reservations
206
+ topic: RESERVATION_CREATED
207
+ consumers:
208
+ - module: payments
209
+ - module: notifications
210
+
211
+ # Pago aprobado → reserva debe confirmarse; cliente recibe confirmación
212
+ - event: PaymentApprovedEvent
213
+ producer: payments
214
+ topic: PAYMENT_APPROVED
215
+ consumers:
216
+ - module: reservations
217
+ - module: notifications
218
+
219
+ # Pago rechazado → reserva debe expirar y liberar asientos; cliente recibe aviso
220
+ - event: PaymentRejectedEvent
221
+ producer: payments
222
+ topic: PAYMENT_REJECTED
223
+ consumers:
224
+ - module: reservations
225
+ - module: notifications
226
+
227
+ # Reserva confirmada → se emiten los tickets QR y se envían al cliente
228
+ - event: ReservationConfirmedEvent
229
+ producer: reservations
230
+ topic: RESERVATION_CONFIRMED
231
+ consumers:
232
+ - module: notifications
233
+
234
+ # Reserva cancelada → pagos evalúa reembolso; cliente recibe notificación
235
+ - event: ReservationCancelledEvent
236
+ producer: reservations
237
+ topic: RESERVATION_CANCELLED
238
+ consumers:
239
+ - module: payments
240
+ - module: notifications
241
+
242
+ # Función cancelada → reservas libera asientos y expira reservas activas; clientes notificados
243
+ - event: ScreeningCancelledEvent
244
+ producer: screenings
245
+ topic: SCREENING_CANCELLED
246
+ consumers:
247
+ - module: reservations
248
+ - module: notifications
249
+
250
+ # ★ NUEVO — Reserva de evento privado creada → screenings bloquea la sala; payments inicia cobro total; notifications avisa
251
+ - event: PrivateEventReservationCreatedEvent
252
+ producer: reservations
253
+ topic: PRIVATE_EVENT_RESERVATION_CREATED
254
+ consumers:
255
+ - module: screenings
256
+ - module: payments
257
+ - module: notifications
258
+
259
+ # ★ NUEVO — Sala bloqueada exitosamente → notifications confirma al organizador del evento
260
+ - event: TheaterLockedForPrivateEventEvent
261
+ producer: screenings
262
+ topic: THEATER_LOCKED_FOR_PRIVATE_EVENT
263
+ consumers:
264
+ - module: notifications
265
+
266
+ sync:
267
+ # Al crear una reserva se consulta la función para validar disponibilidad y precio
268
+ # ★ MODIFICADO — se agrega consulta de disponibilidad para evento privado
269
+ - caller: reservations
270
+ calls: screenings
271
+ port: ScreeningService
272
+ using:
273
+ - GET /screenings/{id}
274
+ - GET /screenings/{id}/seats
275
+ - GET /screenings/{id}/private-event-availability # ★ NUEVO
276
+
277
+ # Al crear una reserva se verifica que el cliente exista y esté activo
278
+ - caller: reservations
279
+ calls: customers
280
+ port: CustomerService
281
+ using:
282
+ - GET /customers/{id}
283
+
284
+ # Al iniciar un pago se obtiene el detalle de la reserva para calcular el monto
285
+ - caller: payments
286
+ calls: reservations
287
+ port: ReservationService
288
+ using:
289
+ - GET /reservations/{id}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eva4j",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "A powerful Node.js CLI for generating Spring Boot projects with modular architecture that enables efficient monolith-first development with seamless transition to microservices",
5
5
  "main": "bin/eva4j.js",
6
6
  "bin": {
@@ -55,7 +55,10 @@ async function createCommand(projectName, options) {
55
55
 
56
56
  // Set all required dependencies
57
57
  answers.dependencies = ['web', 'data-jpa', 'security', 'validation', 'actuator'];
58
-
58
+
59
+ // Preserve CLI name as project directory name (independent of artifactId)
60
+ answers.projectName = projectName || answers.artifactId;
61
+
59
62
  // Build context
60
63
  const context = buildBaseContext(answers);
61
64
 
@@ -69,7 +72,7 @@ async function createCommand(projectName, options) {
69
72
  spinner.succeed(chalk.green('Project created successfully! ✨'));
70
73
 
71
74
  console.log(chalk.blue('\n📦 Project structure:'));
72
- console.log(chalk.gray(` ${context.artifactId}/`));
75
+ console.log(chalk.gray(` ${context.projectName}/`));
73
76
  console.log(chalk.gray(` ├── src/main/java/${context.packagePath.replace(/\//g, '.')}`));
74
77
  console.log(chalk.gray(` │ ├── ${context.applicationClassName}.java`));
75
78
  console.log(chalk.gray(` │ └── common/`));
@@ -77,7 +80,7 @@ async function createCommand(projectName, options) {
77
80
  console.log(chalk.gray(` └── README.md`));
78
81
 
79
82
  console.log(chalk.blue('\n🚀 Next steps:'));
80
- console.log(chalk.white(` cd ${context.artifactId}`));
83
+ console.log(chalk.white(` cd ${context.projectName}`));
81
84
  console.log(chalk.white(` eva4j add module user # Add your first module`));
82
85
  console.log(chalk.white(` ./gradlew bootRun # Run the application`));
83
86
  console.log();