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,350 @@
1
+ ---
2
+ name: implement-use-case
3
+ description: "Implementar casos de uso (use cases) en proyectos generados por eva4j siguiendo arquitectura hexagonal, DDD y código limpio. USAR SIEMPRE cuando el usuario pida: implementar un handler con UnsupportedOperationException, resolver un TODO en un QueryHandler o CommandHandler, implementar lógica de negocio en un use case, agregar filtros/búsquedas personalizadas al repositorio, implementar actividades de Temporal, o resolver cualquier caso de uso descrito en los archivos .md del directorio system/. También aplica cuando el usuario menciona: 'implementar', 'resolver', 'completar el handler', 'quitar el UnsupportedOperationException', 'agregar lógica', 'filtrar por', 'buscar por', o cualquier referencia a casos de uso pendientes."
4
+ ---
5
+
6
+ # Implement Use Case
7
+
8
+ Eres un desarrollador senior experto en DDD, arquitectura hexagonal y Spring Boot. Tu misión es implementar casos de uso en proyectos generados por **eva4j** de forma que:
9
+
10
+ - Respeten estrictamente la arquitectura de capas (domain → application → infrastructure)
11
+ - Sigan los principios de código limpio y DDD
12
+ - Sean consistentes con los patrones ya establecidos por el generador
13
+ - No rompan invariantes ni violen las convenciones del proyecto
14
+
15
+ > **Regla de oro:** El dominio NUNCA conoce la infraestructura. La aplicación orquesta. La infraestructura adapta.
16
+
17
+ ---
18
+
19
+ ## Descubrimiento del contexto
20
+
21
+ Antes de escribir una sola línea, recopila contexto del proyecto. El orden importa:
22
+
23
+ ### Paso 1 — Identificar el bounded context
24
+
25
+ 1. Lee el directorio `system/` del proyecto para localizar el archivo `{module}.md` correspondiente al bounded context
26
+ 2. Lee el `.md` del módulo — contiene: rol del módulo, invariantes, máquina de estados, diagramas de interacción, secuencia, y la **descripción detallada de cada caso de uso** (tipo, precondiciones, postcondiciones, validaciones, eventos emitidos)
27
+ 3. Si existe `system/system.md`, léelo para entender las integraciones entre módulos
28
+
29
+ ### Paso 2 — Leer el código generado
30
+
31
+ Lee los archivos del módulo en este orden (todos conviven bajo `src/main/java/{package}/{module}/`):
32
+
33
+ 1. **`domain.yaml`** — la fuente de verdad del modelo: entidades, campos, relaciones, enums con transiciones, auditoría, eventos, soft delete, readOnly, hidden
34
+ 2. **Entidad de dominio** (`domain/models/entities/{Entity}.java`) — constructores, métodos de negocio existentes, campos
35
+ 3. **Repositorio de dominio** (`domain/repositories/{Entity}Repository.java`) — métodos ya definidos en la interfaz
36
+ 4. **Handler scaffold** (`application/usecases/{UseCase}Handler.java`) — el archivo que contiene el `UnsupportedOperationException` que vas a reemplazar
37
+ 5. **Command o Query** (`application/commands/` o `application/queries/`) — el record con los campos de entrada
38
+ 6. **DTO de respuesta** (`application/dtos/{Entity}ResponseDto.java`) — campos que devuelve la API
39
+ 7. **Application Mapper** (`application/mappers/{Entity}ApplicationMapper.java`) — métodos `toDto()` y `fromCommand()` existentes
40
+ 8. **Aggregate Mapper** (`infrastructure/database/mappers/{Entity}Mapper.java`) — mapeo domain ↔ JPA
41
+ 9. **JPA Repository** (`infrastructure/database/repositories/{Entity}JpaRepository.java`) — métodos Spring Data ya definidos
42
+ 10. **Repository Impl** (`infrastructure/database/repositories/{Entity}RepositoryImpl.java`) — implementación del puerto
43
+
44
+ ### Paso 2b — Si hay Temporal workflows
45
+
46
+ Detecta si el módulo tiene archivos `*WorkFlowImpl.java` en `application/usecases/`. Si existen, el módulo **orquesta** workflows que invocan activities distribuidas en múltiples bounded contexts.
47
+
48
+ **Lee en este orden:**
49
+
50
+ 1. **`*WorkFlowImpl.java`** — identifica todas las activity stubs: nombre de la activity, su task queue (indica el módulo), input/output esperado, y si tiene compensación (Saga). Este archivo es la **spec funcional implícita** de cada activity: qué datos le llegan y qué retorna.
51
+ 2. **Contratos cross-module** — Para cada activity de otro módulo, lee el contrato en `shared/domain/contracts/{targetModule}/`:
52
+ - `{Activity}Activity.java` — interfaz `@ActivityInterface` (firma del método)
53
+ - `{Activity}Input.java` — record con los campos de entrada
54
+ - `{Activity}Output.java` — record con los campos de retorno (si existe)
55
+ 3. **Contratos locales** — Para activities del propio módulo, lee:
56
+ - `{module}/application/ports/{Activity}Activity.java` — interfaz
57
+ - `{module}/application/dtos/temporal/{Activity}Input.java` / `{Activity}Output.java`
58
+ 4. **Implementaciones** — Lee cada `{Activity}ActivityImpl.java` en `{targetModule}/infrastructure/adapters/activities/` para saber si tiene lógica real o está pendiente (`UnsupportedOperationException` o `//todo`)
59
+ 5. **`system/{module}.md`** — busca la sección del workflow que describe cada paso, precondiciones, y compensaciones
60
+
61
+ **Mapa de activities a construir:**
62
+
63
+ ```
64
+ WorkFlowImpl → activity stub → task queue → módulo destino
65
+
66
+ {module}/infrastructure/adapters/activities/{Activity}ActivityImpl.java
67
+
68
+ ¿Tiene UnsupportedOperationException o //todo? → PENDIENTE
69
+ ```
70
+
71
+ > **Regla cross-module:** Para implementar activity `X` que pertenece al módulo `Y`, necesitas leer también la entidad de dominio, repositorio y enums del módulo `Y` — la activity accede **solo** a la BD de su propio módulo.
72
+
73
+ ### Paso 3 — Entender el caso de uso
74
+
75
+ Del archivo `.md` del módulo, extrae para el caso de uso concreto:
76
+ - **Tipo:** HTTP (endpoint REST) o Activity (invocado por Temporal)
77
+ - **Qué hace:** descripción funcional
78
+ - **Precondiciones:** qué debe cumplirse antes de ejecutar
79
+ - **Postcondiciones:** estado del sistema después de la ejecución
80
+ - **Invariantes verificados:** IDs de los invariantes del módulo que este caso de uso protege
81
+ - **Validaciones y errores:** excepciones específicas y códigos HTTP
82
+ - **Eventos emitidos:** domain events que se publican
83
+
84
+ ---
85
+
86
+ ## Anatomía de un Use Case handler
87
+
88
+ Todo handler sigue esta estructura:
89
+
90
+ ```java
91
+ @ApplicationComponent
92
+ public class {UseCase}Handler implements CommandHandler<{Command}> | QueryHandler<{Query}, {Response}> {
93
+
94
+ // 1. Dependencias — solo repositorios de dominio y mappers
95
+ private final {Entity}Repository repository;
96
+ private final {Entity}ApplicationMapper mapper; // solo si necesita mapear DTOs
97
+
98
+ // 2. Constructor — inyección por constructor
99
+ public {UseCase}Handler({Entity}Repository repository, ...) { ... }
100
+
101
+ // 3. handle() — la lógica del caso de uso
102
+ @Override
103
+ @Transactional // comandos: @Transactional; queries: @Transactional(readOnly = true)
104
+ @LogExceptions
105
+ public {ReturnType} handle({CommandOrQuery} input) {
106
+ // Lógica del caso de uso
107
+ }
108
+ }
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Patrones de implementación por tipo de caso de uso
114
+
115
+ Lee el archivo `references/use-case-patterns.md` para los patrones detallados con código de ejemplo para cada tipo de caso de uso:
116
+
117
+ - **Query por ID** (GetEntity) — busca, mapea, retorna
118
+ - **Query con paginación** (FindAll) — Sort, Pageable, Page, PagedResponse
119
+ - **Query con filtros** (FindBy...) — métodos custom de repositorio
120
+ - **Command de estado** (Confirm, Cancel, Activate) — transición de estado vía método de negocio
121
+ - **Command de validación** (Create con unicidad) — buscar duplicados antes de crear
122
+ - **Command de actualización** (Update con merge) — PATCH semántica sin setters
123
+ - **Command con soft delete** (Delete) — `entity.softDelete()` + save
124
+ - **Activity de Temporal** — lógica similar pero invocada por workflow, no por REST
125
+ - **Command que emite eventos** — `raise()` dentro del método de negocio
126
+ - **Activity cross-module** — cómo leer el WorkFlowImpl como spec + implementar en módulo destino
127
+ - **Activity de compensación** — revertir operación previa (ReleaseStock, RefundPayment)
128
+ - **Activity void** — buscar + transicionar estado + persistir, sin retorno
129
+
130
+ ---
131
+
132
+ ## Reglas inviolables
133
+
134
+ ### Capa de dominio
135
+
136
+ 1. **NUNCA** agregar setters a entidades de dominio — usar métodos de negocio con nombre descriptivo
137
+ 2. **NUNCA** agregar constructor vacío a entidades de dominio
138
+ 3. **NUNCA** importar clases de Spring, JPA o infraestructura en el dominio
139
+ 4. **NUNCA** usar anotaciones JSR-303 en entidades de dominio — las validaciones van en Commands/Queries
140
+ 5. Las transiciones de estado se hacen vía `this.status.transitionTo(TargetStatus)` — el enum valida la transición
141
+
142
+ ### Capa de aplicación
143
+
144
+ 6. **NUNCA** inyectar `JpaRepository` directamente — usar la interfaz de dominio `{Entity}Repository`
145
+ 7. **NUNCA** devolver entidades de dominio desde un handler — siempre mapear a DTO
146
+ 8. **NUNCA** mapear campos de auditoría (`createdBy`, `updatedBy`) en DTOs de respuesta
147
+ 9. **NUNCA** mapear campos `hidden: true` en DTOs de respuesta
148
+ 10. **NUNCA** incluir campos `readOnly: true` en constructores de creación ni en `CreateCommand`
149
+ 11. Usar `@Transactional` para commands y `@Transactional(readOnly = true)` para queries
150
+
151
+ ### Capa de infraestructura
152
+
153
+ 12. Nuevos métodos de repositorio se agregan **en 3 lugares**: interfaz de dominio → JPA Repository → RepositoryImpl
154
+ 13. **NUNCA** mapear campos de auditoría heredados en el builder JPA — JPA Auditing los gestiona
155
+ 14. Cuando hay soft delete, **NUNCA** usar `deleteById()` — usar `softDelete()` + `save()`
156
+
157
+ ### Excepciones
158
+
159
+ 15. Usar `NotFoundException` para recursos no encontrados → 404
160
+ 16. Usar `BusinessException` para violaciones de reglas de negocio → 422
161
+ 17. Usar `InvalidStateTransitionException` para transiciones inválidas → 409
162
+ 18. Crear excepciones custom (e.g., `DuplicateSkuException`) solo cuando el `.md` las define explícitamente
163
+
164
+ ### Temporal Activities
165
+
166
+ 19. Cada activity accede **SOLO** a la base de datos de su propio módulo — nunca inyectar repositorios de otro bounded context
167
+ 20. **NUNCA** agregar `@Transactional` en activities — Temporal gestiona reintentos y compensación
168
+ 21. La implementación vive en `{module}/infrastructure/adapters/activities/` — implementa la interfaz `@ActivityInterface` + el marker `{Module}LightActivity` o `{Module}HeavyActivity`
169
+ 22. Activities cross-module: el contrato (interfaz + Input + Output) está en `shared/domain/contracts/{module}/` — **no lo modifiques**, solo implementa el `ActivityImpl`
170
+ 23. Activities locales: el contrato está en `{module}/application/ports/` + `{module}/application/dtos/temporal/`
171
+ 24. Para activities de compensación (rollback): la lógica es el **inverso exacto** de la activity principal — si `ReserveStock` decrementa, `ReleaseStock` incrementa
172
+ 25. El `WorkFlowImpl` es la **spec funcional implícita**: los datos que pasa como Input son los que la activity recibe, y el Output que extrae es lo que debe retornar
173
+
174
+ ---
175
+
176
+ ## Flujo de implementación paso a paso
177
+
178
+ ### Para una Query custom (ej: FindProductsByCategory)
179
+
180
+ 1. **Leer** el Query record — identificar los parámetros de entrada
181
+ 2. **Agregar** el método al repositorio de dominio:
182
+ ```java
183
+ // En {Entity}Repository.java
184
+ Page<Product> findByCategoryId(String categoryId, Pageable pageable);
185
+ ```
186
+ 3. **Agregar** el método al JPA Repository:
187
+ ```java
188
+ // En {Entity}JpaRepository.java
189
+ Page<ProductJpa> findByCategoryId(String categoryId, Pageable pageable);
190
+ ```
191
+ 4. **Agregar** la implementación en RepositoryImpl:
192
+ ```java
193
+ // En {Entity}RepositoryImpl.java
194
+ @Override
195
+ public Page<Product> findByCategoryId(String categoryId, Pageable pageable) {
196
+ return jpaRepository.findByCategoryId(categoryId, pageable).map(mapper::toDomain);
197
+ }
198
+ ```
199
+ 5. **Implementar** el handler:
200
+ ```java
201
+ @Override
202
+ @Transactional(readOnly = true)
203
+ @LogExceptions
204
+ public PagedResponse<ProductResponseDto> handle(FindProductsByCategoryQuery query) {
205
+ Pageable pageable = PageRequest.of(query.page(), query.size(),
206
+ Sort.by(Sort.Direction.fromString(query.sortDirection()), query.sortBy()));
207
+
208
+ Page<Product> page = repository.findByCategoryId(query.categoryId(), pageable);
209
+ List<ProductResponseDto> content = page.getContent().stream()
210
+ .map(mapper::toDto)
211
+ .toList();
212
+
213
+ return PagedResponse.of(content, page.getNumber(), page.getSize(), page.getTotalElements());
214
+ }
215
+ ```
216
+
217
+ ### Para un Command de transición de estado (ej: CancelOrder)
218
+
219
+ 1. **Leer** el Command record — identificar los parámetros
220
+ 2. **Verificar** que el método de negocio existe en la entidad de dominio (ej: `cancel()`)
221
+ 3. **Verificar** que la transición existe en el enum de estado
222
+ 4. **Implementar** el handler:
223
+ ```java
224
+ @Override
225
+ @Transactional
226
+ @LogExceptions
227
+ public void handle(CancelOrderCommand command) {
228
+ Order entity = repository.findById(command.id())
229
+ .orElseThrow(() -> new NotFoundException("Order not found with id: " + command.id()));
230
+
231
+ entity.cancel(); // Método de negocio — valida la transición internamente
232
+ repository.save(entity);
233
+ }
234
+ ```
235
+
236
+ ### Para un Command con validación de unicidad (ej: CreateProduct con SKU único)
237
+
238
+ 1. **Agregar** método de búsqueda al repositorio (3 archivos):
239
+ ```java
240
+ Optional<Product> findBySku(String sku);
241
+ ```
242
+ 2. **Implementar** el handler con verificación previa:
243
+ ```java
244
+ @Override
245
+ @Transactional
246
+ @LogExceptions
247
+ public void handle(CreateProductCommand command) {
248
+ repository.findBySku(command.sku()).ifPresent(existing -> {
249
+ throw new DuplicateSkuException("Product with SKU '" + command.sku() + "' already exists");
250
+ });
251
+
252
+ Product entity = new Product(
253
+ command.name(), command.description(), command.sku(),
254
+ command.categoryId(), command.price(), command.unit(), command.imageUrl()
255
+ );
256
+ repository.save(entity);
257
+ }
258
+ ```
259
+
260
+ ### Para una Temporal Activity (ej: CreateOrderFromCart en módulo orders)
261
+
262
+ 1. **Leer** el contrato de la activity — interfaz + Input + Output en `shared/domain/contracts/{module}/` o `{module}/application/ports/`
263
+ 2. **Leer** el `WorkFlowImpl` que la invoca — entender qué datos le pasa como input y qué espera como output
264
+ 3. **Leer** la entidad de dominio del módulo **donde vive la implementación** (no del módulo orquestador)
265
+ 4. **Leer** el repositorio de dominio del módulo destino
266
+ 5. **Implementar** la lógica:
267
+ ```java
268
+ @Component
269
+ @RequiredArgsConstructor
270
+ public class CreateOrderFromCartActivityImpl
271
+ implements CreateOrderFromCartActivity, OrdersLightActivity {
272
+
273
+ private final OrderRepository repository;
274
+
275
+ @Override
276
+ public CreateOrderFromCartOutput execute(CreateOrderFromCartInput input) {
277
+ // Construir entidad de dominio desde el input del workflow
278
+ Order order = new Order(
279
+ input.customerId(), input.totalAmount(),
280
+ new ShippingAddress(input.street(), input.city(), ...)
281
+ );
282
+ Order saved = repository.save(order);
283
+ return new CreateOrderFromCartOutput(saved.getId());
284
+ }
285
+ }
286
+ ```
287
+
288
+ **Diferencias clave con handlers CQRS:**
289
+ - Anotado con `@Component` + `@RequiredArgsConstructor` (no `@ApplicationComponent`)
290
+ - Implementa dos interfaces: el contrato `{Activity}Activity` + el marker `{Module}Light/HeavyActivity`
291
+ - No usa `@Transactional` ni `@LogExceptions`
292
+ - Input/Output son records del contrato Temporal, no Commands/Queries
293
+ - Puede lanzar excepciones que Temporal captura para compensación (Saga)
294
+
295
+ ### Para una Activity de compensación (ej: ReleaseStock — reverso de ReserveStock)
296
+
297
+ 1. **Leer** la activity principal que compensa (ej: `ReserveStockActivityImpl`)
298
+ 2. **Implementar** la lógica inversa:
299
+ ```java
300
+ @Component
301
+ @RequiredArgsConstructor
302
+ public class ReleaseStockActivityImpl
303
+ implements ReleaseStockActivity, InventoryLightActivity {
304
+
305
+ private final ProductRepository repository;
306
+
307
+ @Override
308
+ public void execute(ReleaseStockInput input) {
309
+ // Inverso de ReserveStock: incrementar stock de cada item
310
+ for (StockReservationItem item : input.items()) {
311
+ Product product = repository.findById(item.productId())
312
+ .orElseThrow(() -> new NotFoundException("Product not found: " + item.productId()));
313
+ product.releaseStock(item.quantity());
314
+ repository.save(product);
315
+ }
316
+ }
317
+ }
318
+ ```
319
+ 3. **Verificar** que el método de negocio inverso existe en la entidad de dominio (ej: `releaseStock()` si `reserveStock()` existe)
320
+
321
+ ### Para implementar activities de múltiples módulos (workflow cross-module)
322
+
323
+ Cuando un workflow orquesta activities de N módulos, la implementación pendiente puede estar dispersa en cualquiera de ellos. Sigue este flujo:
324
+
325
+ 1. **Lee** el `WorkFlowImpl` completo — extrae la lista de todas las activities y su task queue
326
+ 2. **Agrupa** por módulo destino (la task queue indica el módulo: `ORDERS_LIGHT_TASK_QUEUE` → módulo `orders`)
327
+ 3. **Para cada módulo**, lee su entidad de dominio, repositorio, y enums antes de implementar las activities de ese módulo
328
+ 4. **Implementa** las activities de un módulo antes de pasar al siguiente — así el contexto del dominio está fresco
329
+ 5. **Nunca** asumas los datos del input — verifica leyendo el record `{Activity}Input.java`
330
+
331
+ ---
332
+
333
+ ## Checklist antes de entregar
334
+
335
+ Después de implementar, verifica:
336
+
337
+ - [ ] El handler compila sin errores
338
+ - [ ] No queda `UnsupportedOperationException` ni `TODO` sin resolver
339
+ - [ ] Los imports son correctos (no hay imports de capas incorrectas)
340
+ - [ ] Si agregaste métodos al repositorio: están en los 3 archivos (interfaz, JPA, impl)
341
+ - [ ] Las excepciones usadas corresponden a las del `.md` del módulo
342
+ - [ ] Los campos de auditoría no se mapean en DTOs de respuesta
343
+ - [ ] Queries usan `@Transactional(readOnly = true)`
344
+ - [ ] Commands usan `@Transactional`
345
+ - [ ] El handler mantiene `@ApplicationComponent` y `@LogExceptions`
346
+ - [ ] Activities Temporal: usan `@Component` + `@RequiredArgsConstructor` (no `@ApplicationComponent`)
347
+ - [ ] Activities Temporal: implementan interfaz del contrato + marker `{Module}Light/HeavyActivity`
348
+ - [ ] Activities Temporal: no tienen `@Transactional`
349
+ - [ ] Activities Temporal: acceden solo al repositorio de su propio módulo
350
+ - [ ] Activities de compensación: lógica es el inverso exacto de la activity principal