eva4j 1.0.16 → 1.0.18

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 (151) hide show
  1. package/AGENTS.md +220 -5
  2. package/DOMAIN_YAML_GUIDE.md +188 -3
  3. package/FUTURE_FEATURES.md +33 -52
  4. package/QUICK_REFERENCE.md +8 -4
  5. package/bin/eva4j.js +70 -2
  6. package/config/defaults.json +1 -0
  7. package/docs/CAMUNDA_DMN_GUIDE.md +1380 -0
  8. package/docs/KAFKA_PRODUCTION_CONFIG.md +441 -0
  9. package/docs/RABBITMQ_PRODUCTION_CONFIG.md +227 -0
  10. package/docs/commands/ADD_RABBITMQ_CLIENT.md +192 -0
  11. package/docs/commands/EVALUATE_SYSTEM.md +290 -10
  12. package/docs/commands/GENERATE_RABBITMQ_EVENT.md +341 -0
  13. package/docs/commands/GENERATE_RABBITMQ_LISTENER.md +595 -0
  14. package/docs/commands/GENERATE_TEMPORAL_FLOW.md +52 -12
  15. package/docs/commands/INDEX.md +27 -3
  16. package/docs/prototype/TEMPORAL_COMMUNICATION_PATTERNS.md +731 -0
  17. package/docs/prototype/TEMPORAL_DESIGN_METHODOLOGY.md +740 -0
  18. package/docs/prototype/system/RISKS.md +277 -0
  19. package/docs/prototype/system/customers.yaml +133 -0
  20. package/docs/prototype/system/inventory.yaml +109 -0
  21. package/docs/prototype/system/notifications.yaml +131 -0
  22. package/docs/prototype/system/orders.yaml +241 -0
  23. package/docs/prototype/system/payments.yaml +256 -0
  24. package/docs/prototype/system/products.yaml +168 -0
  25. package/docs/prototype/system/system.yaml +269 -0
  26. package/examples/domain-endpoints-multi-aggregate.yaml +140 -0
  27. package/examples/domain-events.yaml +26 -0
  28. package/examples/domain-read-models.yaml +113 -0
  29. package/examples/system/customer.yaml +89 -0
  30. package/examples/system/orders.yaml +119 -0
  31. package/examples/system/product.yaml +27 -0
  32. package/examples/system/system.yaml +80 -0
  33. package/package.json +1 -1
  34. package/read-model-spec.md +664 -0
  35. package/src/agents/design-gap-analyst-temporal.agent.md +452 -0
  36. package/src/agents/design-gap-analyst.agent.md +383 -0
  37. package/src/agents/design-reviewer-temporal.agent.md +412 -0
  38. package/src/agents/design-reviewer.agent.md +34 -5
  39. package/src/agents/implement-use-cases.prompt.md +179 -0
  40. package/src/agents/ux-gap-analyst.agent.md +412 -0
  41. package/src/commands/add-rabbitmq-client.js +261 -0
  42. package/src/commands/add-temporal-client.js +22 -2
  43. package/src/commands/build.js +267 -11
  44. package/src/commands/evaluate-system.js +700 -13
  45. package/src/commands/generate-entities.js +560 -24
  46. package/src/commands/generate-http-exchange.js +3 -0
  47. package/src/commands/generate-kafka-event.js +3 -0
  48. package/src/commands/generate-kafka-listener.js +3 -0
  49. package/src/commands/generate-rabbitmq-event.js +665 -0
  50. package/src/commands/generate-rabbitmq-listener.js +205 -0
  51. package/src/commands/generate-record.js +2 -2
  52. package/src/commands/generate-resource.js +4 -1
  53. package/src/commands/generate-temporal-activity.js +970 -33
  54. package/src/commands/generate-temporal-flow.js +98 -38
  55. package/src/commands/generate-temporal-system.js +708 -0
  56. package/src/commands/generate-usecase.js +4 -1
  57. package/src/skills/build-system-yaml/SKILL.md +343 -2
  58. package/src/skills/build-system-yaml/references/domain-yaml-spec.md +253 -26
  59. package/src/skills/build-system-yaml/references/module-spec.md +90 -9
  60. package/src/skills/build-system-yaml/references/system-yaml-spec.md +36 -0
  61. package/src/skills/build-temporal-system/SKILL.md +752 -0
  62. package/src/skills/build-temporal-system/references/temporal-communication-patterns.md +167 -0
  63. package/src/skills/build-temporal-system/references/temporal-domain-yaml-spec.md +449 -0
  64. package/src/skills/build-temporal-system/references/temporal-module-spec.md +353 -0
  65. package/src/skills/build-temporal-system/references/temporal-system-yaml-spec.md +326 -0
  66. package/src/skills/implement-use-case/SKILL.md +350 -0
  67. package/src/skills/implement-use-case/references/use-case-patterns.md +980 -0
  68. package/src/skills/requirements-elicitation/SKILL.md +228 -0
  69. package/src/skills/requirements-elicitation/references/interview-framework.md +260 -0
  70. package/src/skills/requirements-elicitation/references/output-templates.md +368 -0
  71. package/src/utils/bounded-context-diagram.js +844 -0
  72. package/src/utils/config-manager.js +4 -2
  73. package/src/utils/domain-validator.js +495 -17
  74. package/src/utils/naming.js +20 -0
  75. package/src/utils/system-validator.js +169 -11
  76. package/src/utils/system-yaml-parser.js +318 -0
  77. package/src/utils/temporal-validator.js +497 -0
  78. package/src/utils/validator.js +3 -1
  79. package/src/utils/yaml-to-entity.js +281 -9
  80. package/templates/aggregate/AggregateRepository.java.ejs +4 -0
  81. package/templates/aggregate/AggregateRepositoryImpl.java.ejs +8 -0
  82. package/templates/aggregate/AggregateRoot.java.ejs +38 -4
  83. package/templates/aggregate/DomainEventHandler.java.ejs +116 -22
  84. package/templates/aggregate/JpaAggregateRoot.java.ejs +4 -4
  85. package/templates/aggregate/JpaEntity.java.ejs +2 -2
  86. package/templates/base/docker/rabbitmq-services.yaml.ejs +12 -0
  87. package/templates/base/resources/parameters/develop/kafka.yaml.ejs +5 -0
  88. package/templates/base/resources/parameters/develop/rabbitmq.yaml.ejs +15 -0
  89. package/templates/base/resources/parameters/develop/temporal.yaml.ejs +0 -3
  90. package/templates/base/resources/parameters/local/kafka.yaml.ejs +5 -0
  91. package/templates/base/resources/parameters/local/rabbitmq.yaml.ejs +15 -0
  92. package/templates/base/resources/parameters/local/temporal.yaml.ejs +0 -3
  93. package/templates/base/resources/parameters/production/kafka.yaml.ejs +39 -8
  94. package/templates/base/resources/parameters/production/rabbitmq.yaml.ejs +32 -0
  95. package/templates/base/resources/parameters/production/temporal.yaml.ejs +0 -3
  96. package/templates/base/resources/parameters/test/kafka.yaml.ejs +12 -6
  97. package/templates/base/resources/parameters/test/rabbitmq.yaml.ejs +15 -0
  98. package/templates/base/resources/parameters/test/temporal.yaml.ejs +0 -3
  99. package/templates/base/root/AGENTS.md.ejs +1 -1
  100. package/templates/crud/DeleteCommandHandler.java.ejs +19 -1
  101. package/templates/crud/EndpointsController.java.ejs +1 -1
  102. package/templates/crud/ScaffoldCommand.java.ejs +5 -2
  103. package/templates/crud/ScaffoldCommandHandler.java.ejs +3 -1
  104. package/templates/crud/ScaffoldQuery.java.ejs +5 -2
  105. package/templates/crud/ScaffoldQueryHandler.java.ejs +3 -1
  106. package/templates/crud/SubEntityRemoveCommand.java.ejs +1 -1
  107. package/templates/crud/UpdateCommandHandler.java.ejs +53 -2
  108. package/templates/evaluate/report.html.ejs +1447 -90
  109. package/templates/kafka-event/KafkaConfigBean.java.ejs +1 -1
  110. package/templates/kafka-event/KafkaMessageBroker.java.ejs +3 -3
  111. package/templates/ports/PortAclMapper.java.ejs +35 -0
  112. package/templates/ports/PortFeignAdapter.java.ejs +7 -22
  113. package/templates/ports/PortFeignClient.java.ejs +4 -0
  114. package/templates/ports/PortResponseDto.java.ejs +1 -1
  115. package/templates/rabbitmq-event/RabbitConfigBean.java.ejs +33 -0
  116. package/templates/rabbitmq-event/RabbitConfigExchange.java.ejs +12 -0
  117. package/templates/rabbitmq-event/RabbitMessageBroker.java.ejs +35 -0
  118. package/templates/rabbitmq-event/RabbitMessageBrokerMethod.java.ejs +9 -0
  119. package/templates/rabbitmq-listener/RabbitConfigConsumerBean.java.ejs +33 -0
  120. package/templates/rabbitmq-listener/RabbitConfigConsumerExchange.java.ejs +12 -0
  121. package/templates/rabbitmq-listener/RabbitListenerClass.java.ejs +82 -0
  122. package/templates/rabbitmq-listener/RabbitListenerSimple.java.ejs +56 -0
  123. package/templates/read-model/ReadModelDomain.java.ejs +46 -0
  124. package/templates/read-model/ReadModelJpa.java.ejs +58 -0
  125. package/templates/read-model/ReadModelJpaRepository.java.ejs +13 -0
  126. package/templates/read-model/ReadModelKafkaListener.java.ejs +64 -0
  127. package/templates/read-model/ReadModelRabbitListener.java.ejs +71 -0
  128. package/templates/read-model/ReadModelRepository.java.ejs +42 -0
  129. package/templates/read-model/ReadModelRepositoryImpl.java.ejs +85 -0
  130. package/templates/read-model/ReadModelSyncHandler.java.ejs +54 -0
  131. package/templates/shared/configurations/kafkaConfig/KafkaConfig.java.ejs +18 -4
  132. package/templates/shared/configurations/rabbitmqConfig/RabbitMQConfig.java.ejs +100 -0
  133. package/templates/shared/configurations/temporalConfig/TemporalConfig.java.ejs +2 -64
  134. package/templates/shared/configurations/temporalConfig/TemporalWorkerFactoryLifecycle.java.ejs +41 -0
  135. package/templates/temporal-activity/ActivityImpl.java.ejs +68 -2
  136. package/templates/temporal-activity/ActivityInput.java.ejs +14 -0
  137. package/templates/temporal-activity/ActivityInterface.java.ejs +7 -1
  138. package/templates/temporal-activity/ActivityOutput.java.ejs +14 -0
  139. package/templates/temporal-activity/NestedType.java.ejs +12 -0
  140. package/templates/temporal-activity/SharedActivityInput.java.ejs +14 -0
  141. package/templates/temporal-activity/SharedActivityInterface.java.ejs +15 -0
  142. package/templates/temporal-activity/SharedActivityOutput.java.ejs +14 -0
  143. package/templates/temporal-activity/SharedNestedType.java.ejs +12 -0
  144. package/templates/temporal-flow/ModuleHeavyActivity.java.ejs +6 -0
  145. package/templates/temporal-flow/ModuleLightActivity.java.ejs +6 -0
  146. package/templates/temporal-flow/ModuleTemporalWorkerConfig.java.ejs +58 -0
  147. package/templates/temporal-flow/WorkFlowImpl.java.ejs +172 -12
  148. package/templates/temporal-flow/WorkFlowInput.java.ejs +11 -0
  149. package/templates/temporal-flow/WorkFlowInterface.java.ejs +5 -4
  150. package/templates/temporal-flow/WorkFlowService.java.ejs +42 -12
  151. package/COMMAND_EVALUATION.md +0 -911
@@ -0,0 +1,241 @@
1
+ # =============================================================================
2
+ # PROTOTYPE: orders.yaml — versión Temporal (sin Kafka, sin Read Models)
3
+ # =============================================================================
4
+ # Cambios vs original:
5
+ # - ELIMINA listeners[] — el workflow ya integra la respuesta del pago
6
+ # - ELIMINA ports[] — la reserva de stock es una Activity del workflow
7
+ # - ELIMINA readModels[] — datos cross-module se obtienen on-demand via
8
+ # Remote Activities de lectura (GetCustomerById)
9
+ # - ELIMINA saga: — la saga se define en system.yaml workflows
10
+ # - events[].notifies referencia workflows definidos en system.yaml
11
+ # =============================================================================
12
+
13
+ aggregates:
14
+ - name: Order
15
+ entities:
16
+ - name: order
17
+ isRoot: true
18
+ tableName: orders
19
+ audit:
20
+ enabled: true
21
+ trackUser: true
22
+ fields:
23
+ - name: id
24
+ type: String
25
+ - name: customerId
26
+ type: String
27
+ reference:
28
+ aggregate: Customer
29
+ module: customers
30
+ validations:
31
+ - type: NotBlank
32
+ message: "Customer ID is required"
33
+ - name: status
34
+ type: OrderStatus
35
+ readOnly: true
36
+ - name: totalAmount
37
+ type: BigDecimal
38
+ readOnly: true
39
+ defaultValue: "0.00"
40
+ - name: itemCount
41
+ type: Integer
42
+ readOnly: true
43
+ defaultValue: 0
44
+ - name: shippingAddress
45
+ type: ShippingAddress
46
+ - name: notes
47
+ type: String
48
+ relationships:
49
+ - type: OneToMany
50
+ target: OrderItem
51
+ mappedBy: order
52
+ cascade: [PERSIST, MERGE, REMOVE]
53
+ fetch: LAZY
54
+
55
+ - name: orderItem
56
+ tableName: order_items
57
+ audit:
58
+ enabled: true
59
+ fields:
60
+ - name: id
61
+ type: String
62
+ - name: productId
63
+ type: String
64
+ reference:
65
+ aggregate: Product
66
+ module: products
67
+ - name: productName
68
+ type: String
69
+ - name: quantity
70
+ type: Integer
71
+ validations:
72
+ - type: Min
73
+ value: 1
74
+ message: "Quantity must be at least 1"
75
+ - name: unitPrice
76
+ type: BigDecimal
77
+ validations:
78
+ - type: Positive
79
+ message: "Unit price must be positive"
80
+ - name: subtotal
81
+ type: BigDecimal
82
+ readOnly: true
83
+
84
+ valueObjects:
85
+ - name: ShippingAddress
86
+ fields:
87
+ - name: street
88
+ type: String
89
+ - name: city
90
+ type: String
91
+ - name: department
92
+ type: String
93
+ - name: zipCode
94
+ type: String
95
+ - name: neighborhood
96
+ type: String
97
+ methods:
98
+ - name: format
99
+ returnType: String
100
+ parameters: []
101
+ body: "return street + \", \" + neighborhood + \", \" + city + \" (\" + department + \") \" + zipCode;"
102
+
103
+ enums:
104
+ - name: OrderStatus
105
+ initialValue: PENDING
106
+ transitions:
107
+ - from: PENDING
108
+ to: CONFIRMED
109
+ method: confirm
110
+ - from: PENDING
111
+ to: CANCELLED
112
+ method: cancel
113
+ - from: PENDING
114
+ to: PAYMENT_FAILED
115
+ method: failPayment
116
+ values: [PENDING, CONFIRMED, CANCELLED, PAYMENT_FAILED]
117
+
118
+ events:
119
+ - name: OrderPlacedEvent
120
+ lifecycle: create
121
+ fields:
122
+ - name: orderId
123
+ type: String
124
+ - name: placedAt
125
+ type: LocalDateTime
126
+ notifies:
127
+ - workflow: PlaceOrderWorkflow # ← La saga completa
128
+
129
+ - name: OrderCancelledEvent
130
+ triggers:
131
+ - cancel
132
+ fields:
133
+ - name: orderId
134
+ type: String
135
+ notifies:
136
+ - workflow: CancelOrderWorkflow
137
+
138
+ # ─── ELIMINADO: listeners[] ──────────────────────────────────────────────────
139
+ # PaymentApprovedEvent y PaymentFailedEvent ya no llegan como eventos Kafka.
140
+ # El PlaceOrderWorkflow espera el resultado de ProcessOrderPayment directamente
141
+ # (paso sync en la saga). Si falla → compensa. Si aprueba → confirma.
142
+
143
+ # ─── ELIMINADO: ports[] ─────────────────────────────────────────────────────
144
+ # ReserveStock y ReleaseStock ya no son Feign calls.
145
+ # Son Activities ejecutadas por el worker de inventory via Temporal.
146
+
147
+ # ─── ELIMINADO: readModels[] ────────────────────────────────────────────────
148
+ # CustomerReadModel y ProductReadModel ELIMINADOS.
149
+ # Datos cross-module se obtienen ON-DEMAND en los workflows:
150
+ # - PlaceOrderWorkflow: GetCustomerById → customers (Remote Activity)
151
+ # Valida existencia, obtiene email/nombre para notificaciones.
152
+ # - CancelOrderWorkflow: GetCustomerById → customers
153
+ # Obtiene email para notificación de cancelación.
154
+ #
155
+ # Productos se validan al crear la orden; no se re-validan en la saga.
156
+
157
+ # ─── ELIMINADO: saga: ───────────────────────────────────────────────────────
158
+ # La saga (PlaceOrderWorkflow) se define en system.yaml, no en el módulo.
159
+ # El CreateOrderCommandHandler persiste la orden y lanza el workflow.
160
+
161
+ # ─── Activities del módulo ───────────────────────────────────────────────────
162
+ # Activities LOCALES — invocadas por workflows cross-module (system.yaml)
163
+ # y workflows single-module (definidos abajo).
164
+ activities:
165
+ - name: GetOrderDetails
166
+ type: light
167
+ description: "Obtiene los detalles completos de una orden (items, totales, IDs relacionados)"
168
+ input:
169
+ - name: orderId
170
+ type: String
171
+ output:
172
+ - name: customerId
173
+ type: String
174
+ - name: items
175
+ type: List<OrderItemDetail>
176
+ - name: totalAmount
177
+ type: BigDecimal
178
+ - name: paymentId
179
+ type: String
180
+ nestedTypes:
181
+ - name: OrderItemDetail
182
+ fields:
183
+ - name: productId
184
+ type: String
185
+ - name: productName
186
+ type: String
187
+ - name: quantity
188
+ type: Integer
189
+ - name: unitPrice
190
+ type: BigDecimal
191
+ - name: subtotal
192
+ type: BigDecimal
193
+ timeout: 5s
194
+
195
+ - name: ConfirmOrder
196
+ type: light
197
+ description: "Confirma la orden tras pago exitoso (invocada por PlaceOrderWorkflow)"
198
+ input:
199
+ - name: orderId
200
+ type: String
201
+ timeout: 5s
202
+
203
+ - name: CancelExpiredOrder
204
+ type: light
205
+ description: "Cancela orden pendiente que no recibió pago a tiempo"
206
+ input:
207
+ - name: orderId
208
+ type: String
209
+ timeout: 5s
210
+
211
+ # ─── Workflows single-module ────────────────────────────────────────────────
212
+ # Flujos que NO cruzan fronteras de módulo → se definen aquí, no en system.yaml.
213
+ workflows:
214
+ - name: ExpireOrderWorkflow
215
+ description: "Cancela la orden si no se recibe pago dentro del timeout"
216
+ trigger:
217
+ on: orderCreated
218
+ taskQueue: ORDER_WORKFLOW_QUEUE
219
+ steps:
220
+ - wait: paymentCompleted
221
+ timeout: 30m
222
+ - activity: CancelExpiredOrder
223
+ timeout: 5s
224
+
225
+ endpoints:
226
+ basePath: /orders
227
+ versions:
228
+ - version: v1
229
+ operations:
230
+ - useCase: CreateOrder
231
+ method: POST
232
+ path: /
233
+ - useCase: GetOrder
234
+ method: GET
235
+ path: /{id}
236
+ - useCase: FindAllOrders
237
+ method: GET
238
+ path: /
239
+ - useCase: CancelOrder
240
+ method: PUT
241
+ path: /{id}/cancel
@@ -0,0 +1,256 @@
1
+ # =============================================================================
2
+ # PROTOTYPE: payments.yaml — versión Temporal (sin Kafka)
3
+ # =============================================================================
4
+ # Cambios vs original:
5
+ # - ELIMINA listeners[] — ya no consume OrderPlacedEvent por Kafka
6
+ # - ELIMINA events[] con topic: — ya no publica por Kafka
7
+ # - Los eventos internos siguen existiendo para lógica de dominio
8
+ # - ports[] SE MANTIENE — PaymentGateway es un servicio EXTERNO (no Temporal)
9
+ # - ProcessOrderPayment es ahora una Activity invocada por PlaceOrderWorkflow
10
+ # =============================================================================
11
+
12
+ aggregates:
13
+ - name: Payment
14
+ entities:
15
+ - name: payment
16
+ isRoot: true
17
+ tableName: payments
18
+ audit:
19
+ enabled: true
20
+ fields:
21
+ - name: id
22
+ type: String
23
+ - name: orderId
24
+ type: String
25
+ reference:
26
+ aggregate: Order
27
+ module: orders
28
+ validations:
29
+ - type: NotBlank
30
+ message: "Order ID is required"
31
+ - name: customerId
32
+ type: String
33
+ reference:
34
+ aggregate: Customer
35
+ module: customers
36
+ - name: amount
37
+ type: BigDecimal
38
+ validations:
39
+ - type: Positive
40
+ message: "Amount must be positive"
41
+ - type: NotNull
42
+ message: "Amount is required"
43
+ - name: currency
44
+ type: String
45
+ readOnly: true
46
+ defaultValue: "COP"
47
+ - name: status
48
+ type: PaymentStatus
49
+ readOnly: true
50
+ - name: paymentMethod
51
+ type: PaymentMethod
52
+ - name: transactionId
53
+ type: String
54
+ readOnly: true
55
+ hidden: true
56
+ - name: gatewayResponse
57
+ type: String
58
+ readOnly: true
59
+ hidden: true
60
+
61
+ enums:
62
+ - name: PaymentStatus
63
+ initialValue: PENDING
64
+ transitions:
65
+ - from: PENDING
66
+ to: APPROVED
67
+ method: approve
68
+ - from: PENDING
69
+ to: FAILED
70
+ method: fail
71
+ - from: APPROVED
72
+ to: REFUNDED
73
+ method: refund
74
+ values: [PENDING, APPROVED, FAILED, REFUNDED]
75
+
76
+ - name: PaymentMethod
77
+ values:
78
+ - CREDIT_CARD
79
+ - DEBIT_CARD
80
+ - PSE
81
+ - NEQUI
82
+ - CASH_ON_DELIVERY
83
+
84
+ events:
85
+ # Domain Events internos — siguen existiendo para la entidad.
86
+ # PERO ya no generan IntegrationEvent ni MessageBroker.
87
+ # El resultado del pago lo retorna la Activity directamente al workflow.
88
+ - name: PaymentApprovedEvent
89
+ triggers:
90
+ - approve
91
+ fields:
92
+ - name: paymentId
93
+ type: String
94
+ - name: orderId
95
+ type: String
96
+ - name: customerId
97
+ type: String
98
+ - name: amount
99
+ type: BigDecimal
100
+ - name: approvedAt
101
+ type: LocalDateTime
102
+ # ⚠️ SIN notifies: — el resultado viaja como retorno de Activity,
103
+ # no como evento. El workflow ya sabe qué hacer.
104
+
105
+ - name: PaymentFailedEvent
106
+ triggers:
107
+ - fail
108
+ fields:
109
+ - name: paymentId
110
+ type: String
111
+ - name: orderId
112
+ type: String
113
+ - name: customerId
114
+ type: String
115
+ - name: reason
116
+ type: String
117
+
118
+ # ─── Activities que este módulo EXPONE a workflows de otros módulos ──────────
119
+ # Concepto nuevo: en Kafka, payments "escuchaba" OrderPlacedEvent.
120
+ # Con Temporal, payments "ofrece" una Activity que el workflow de orders invoca.
121
+ activities:
122
+ - name: ProcessOrderPayment
123
+ type: heavy # Puede tardar (gateway externo)
124
+ description: "Crea un pago y cobra al gateway externo"
125
+ input:
126
+ - name: orderId
127
+ type: String
128
+ - name: customerId
129
+ type: String
130
+ - name: totalAmount
131
+ type: BigDecimal
132
+ output:
133
+ - name: paymentId
134
+ type: String
135
+ - name: status
136
+ type: String # APPROVED | FAILED
137
+ - name: reason
138
+ type: String # null si APPROVED
139
+ timeout: 30s
140
+ retryPolicy:
141
+ maxAttempts: 3
142
+ initialInterval: 1s
143
+ backoffCoefficient: 2.0
144
+
145
+ - name: RefundPayment
146
+ type: heavy
147
+ description: "Reembolsa un pago aprobado (compensación de saga)"
148
+ input:
149
+ - name: paymentId
150
+ type: String
151
+ output:
152
+ - name: refundId
153
+ type: String
154
+ - name: status
155
+ type: String
156
+
157
+ # Activities INTERNAS — solo usadas por workflows single-module de payments
158
+ - name: RetryCharge
159
+ type: heavy
160
+ description: "Reintenta cobro al gateway externo"
161
+ input:
162
+ - name: paymentId
163
+ type: String
164
+ output:
165
+ - name: status
166
+ type: String
167
+ - name: reason
168
+ type: String
169
+ timeout: 30s
170
+
171
+ - name: MarkPaymentFailed
172
+ type: light
173
+ description: "Marca el pago como fallido definitivamente tras agotar reintentos"
174
+ input:
175
+ - name: paymentId
176
+ type: String
177
+ timeout: 5s
178
+
179
+ # ─── Workflows single-module ────────────────────────────────────────────────
180
+ # Flujos internos que NO cruzan fronteras de módulo.
181
+ workflows:
182
+ - name: RetryChargeWorkflow
183
+ description: "Reintenta cobro fallido con backoff exponencial"
184
+ trigger:
185
+ on: chargeFailed
186
+ taskQueue: PAYMENT_WORKFLOW_QUEUE
187
+ steps:
188
+ - activity: RetryCharge
189
+ retryPolicy:
190
+ maxAttempts: 3
191
+ initialInterval: 2s
192
+ backoffCoefficient: 2.0
193
+ - activity: MarkPaymentFailed
194
+ timeout: 5s
195
+
196
+ # ─── ELIMINADOS: listeners[] ─────────────────────────────────────────────────
197
+ # OrderPlacedEvent ya no se consume. ProcessOrderPayment es una Activity.
198
+
199
+ # ─── ports[] SE MANTIENE para servicios EXTERNOS (no-Temporal) ───────────────
200
+ # PaymentGateway es un proveedor externo — no corre workers Temporal.
201
+ # Para servicios externos, HTTP sigue siendo necesario.
202
+ ports:
203
+ - name: processCharge
204
+ service: PaymentGatewayService
205
+ target: payment-gateway
206
+ baseUrl: https://api.payments.example.com
207
+ http: POST /charges
208
+ body:
209
+ - name: amount
210
+ type: BigDecimal
211
+ - name: currency
212
+ type: String
213
+ - name: paymentMethod
214
+ type: String
215
+ - name: description
216
+ type: String
217
+ fields:
218
+ - name: transactionId
219
+ type: String
220
+ - name: status
221
+ type: String
222
+ - name: message
223
+ type: String
224
+
225
+ - name: processRefund
226
+ service: PaymentGatewayService
227
+ target: payment-gateway
228
+ http: POST /refunds
229
+ body:
230
+ - name: transactionId
231
+ type: String
232
+ - name: amount
233
+ type: BigDecimal
234
+ fields:
235
+ - name: refundId
236
+ type: String
237
+ - name: status
238
+ type: String
239
+
240
+ endpoints:
241
+ basePath: /payments
242
+ versions:
243
+ - version: v1
244
+ operations:
245
+ - useCase: CreatePayment
246
+ method: POST
247
+ path: /
248
+ - useCase: GetPayment
249
+ method: GET
250
+ path: /{id}
251
+ - useCase: FindAllPayments
252
+ method: GET
253
+ path: /
254
+ - useCase: RefundPayment
255
+ method: POST
256
+ path: /{id}/refund
@@ -0,0 +1,168 @@
1
+ # =============================================================================
2
+ # PROTOTYPE: products.yaml — versión Temporal (sin Kafka)
3
+ # =============================================================================
4
+ # Cambios vs original:
5
+ # - events[] MANTIENE los Domain Events internos (raise() sigue funcionando)
6
+ # - ELIMINA topic: — ya no hay topics Kafka
7
+ # - AGREGA notifies: — lista de activities que el workflow debe invocar
8
+ # - endpoints, aggregates, enums → SIN CAMBIOS
9
+ # =============================================================================
10
+
11
+ aggregates:
12
+ - name: Product
13
+ entities:
14
+ - name: product
15
+ isRoot: true
16
+ tableName: products
17
+ hasSoftDelete: true
18
+ audit:
19
+ enabled: true
20
+ fields:
21
+ - name: id
22
+ type: String
23
+ - name: name
24
+ type: String
25
+ validations:
26
+ - type: NotBlank
27
+ message: "Product name is required"
28
+ - name: description
29
+ type: String
30
+ - name: price
31
+ type: BigDecimal
32
+ validations:
33
+ - type: Positive
34
+ message: "Price must be positive"
35
+ - type: NotNull
36
+ message: "Price is required"
37
+ - name: category
38
+ type: ProductCategory
39
+ - name: imageUrl
40
+ type: String
41
+ - name: sku
42
+ type: String
43
+ validations:
44
+ - type: NotBlank
45
+ message: "SKU is required"
46
+ - name: active
47
+ type: Boolean
48
+ readOnly: true
49
+ defaultValue: true
50
+
51
+ enums:
52
+ - name: ProductCategory
53
+ values:
54
+ - GRAINS
55
+ - DAIRY
56
+ - MEAT
57
+ - FRUITS
58
+ - VEGETABLES
59
+ - BEVERAGES
60
+ - CLEANING
61
+ - PERSONAL_CARE
62
+ - SNACKS
63
+ - OTHER
64
+
65
+ events:
66
+ # Domain Events internos se mantienen (raise() en la entidad).
67
+ # La diferencia: ya no generan IntegrationEvent ni MessageBroker.
68
+ # En su lugar, un WorkflowService los intercepta y lanza el workflow.
69
+ - name: ProductCreatedEvent
70
+ lifecycle: create
71
+ fields:
72
+ - name: productId
73
+ type: String
74
+ - name: name
75
+ type: String
76
+ - name: price
77
+ type: BigDecimal
78
+ - name: category
79
+ type: String
80
+ notifies:
81
+ - workflow: ProductCreatedWorkflow # → InitializeStock en inventory
82
+
83
+ - name: ProductUpdatedEvent
84
+ lifecycle: update
85
+ fields:
86
+ - name: productId
87
+ type: String
88
+ - name: name
89
+ type: String
90
+ - name: price
91
+ type: BigDecimal
92
+ - name: category
93
+ type: String
94
+ # SIN notifies → Domain Event interno.
95
+ # Sin read models, no hay consumers cross-module para updates.
96
+ # Los workflows que necesitan datos de producto los obtienen
97
+ # on-demand via GetProductById / GetProductsByIds.
98
+
99
+ - name: ProductDeactivatedEvent
100
+ lifecycle: softDelete
101
+ fields:
102
+ - name: productId
103
+ type: String
104
+ # SIN notifies → Domain Event interno.
105
+ # Mismo razonamiento: sin read models, no hay consumers.
106
+
107
+ # ─── Activities que este módulo EXPONE ───────────────────────────────────────
108
+ # Activities de lectura: permiten a workflows de otros módulos obtener datos
109
+ # de producto on-demand (Remote Activity), eliminando la necesidad de read models.
110
+ activities:
111
+ - name: GetProductById
112
+ type: light
113
+ description: "Obtiene un producto por su ID"
114
+ input:
115
+ - name: productId
116
+ type: String
117
+ output:
118
+ - name: id
119
+ type: String
120
+ - name: name
121
+ type: String
122
+ - name: price
123
+ type: BigDecimal
124
+ - name: category
125
+ type: String
126
+ - name: sku
127
+ type: String
128
+ timeout: 5s
129
+
130
+ - name: GetProductsByIds
131
+ type: light
132
+ description: "Obtiene múltiples productos por sus IDs (batch)"
133
+ input:
134
+ - name: productIds
135
+ type: List<String>
136
+ output:
137
+ - name: products
138
+ type: List<String> # List<{id, name, price, category, sku}>
139
+ timeout: 10s
140
+
141
+ endpoints:
142
+ basePath: /products
143
+ versions:
144
+ - version: v1
145
+ operations:
146
+ - useCase: GetProduct
147
+ method: GET
148
+ path: /{id}
149
+ - useCase: FindAllProducts
150
+ method: GET
151
+ path: /
152
+ - useCase: CreateProduct
153
+ method: POST
154
+ path: /
155
+ - useCase: UpdateProduct
156
+ method: PUT
157
+ path: /{id}
158
+ - useCase: DeleteProduct
159
+ method: DELETE
160
+ path: /{id}
161
+
162
+ # ─── ELIMINADO: No hay listeners (products no consume eventos) ───────────────
163
+ # ─── ELIMINADO: No hay ports (products no llama a otros servicios) ────────────
164
+ # ─── ELIMINADO: No hay readModels (products no proyecta datos ajenos) ─────────
165
+ # ─── DESACOPLAMIENTO: products ya no necesita saber quién consume sus datos ──
166
+ # ProductUpdatedEvent y ProductDeactivatedEvent son Domain Events internos.
167
+ # Solo ProductCreatedEvent notifica ProductCreatedWorkflow (→ InitializeStock)
168
+ # porque es un efecto de negocio real, no sincronización de datos.