eva4j 1.0.17 → 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 (134) hide show
  1. package/AGENTS.md +2 -0
  2. package/DOMAIN_YAML_GUIDE.md +3 -1
  3. package/QUICK_REFERENCE.md +8 -4
  4. package/bin/eva4j.js +70 -2
  5. package/config/defaults.json +1 -0
  6. package/docs/CAMUNDA_DMN_GUIDE.md +1380 -0
  7. package/docs/KAFKA_PRODUCTION_CONFIG.md +441 -0
  8. package/docs/RABBITMQ_PRODUCTION_CONFIG.md +227 -0
  9. package/docs/commands/ADD_RABBITMQ_CLIENT.md +192 -0
  10. package/docs/commands/EVALUATE_SYSTEM.md +272 -8
  11. package/docs/commands/GENERATE_RABBITMQ_EVENT.md +341 -0
  12. package/docs/commands/GENERATE_RABBITMQ_LISTENER.md +595 -0
  13. package/docs/commands/GENERATE_TEMPORAL_FLOW.md +52 -12
  14. package/docs/commands/INDEX.md +27 -3
  15. package/docs/prototype/TEMPORAL_COMMUNICATION_PATTERNS.md +731 -0
  16. package/docs/prototype/TEMPORAL_DESIGN_METHODOLOGY.md +740 -0
  17. package/docs/prototype/system/RISKS.md +277 -0
  18. package/docs/prototype/system/customers.yaml +133 -0
  19. package/docs/prototype/system/inventory.yaml +109 -0
  20. package/docs/prototype/system/notifications.yaml +131 -0
  21. package/docs/prototype/system/orders.yaml +241 -0
  22. package/docs/prototype/system/payments.yaml +256 -0
  23. package/docs/prototype/system/products.yaml +168 -0
  24. package/docs/prototype/system/system.yaml +269 -0
  25. package/examples/domain-endpoints-multi-aggregate.yaml +140 -0
  26. package/examples/domain-read-models.yaml +2 -2
  27. package/examples/system/customer.yaml +89 -0
  28. package/examples/system/orders.yaml +119 -0
  29. package/examples/system/product.yaml +27 -0
  30. package/examples/system/system.yaml +80 -0
  31. package/package.json +1 -1
  32. package/src/agents/design-gap-analyst-temporal.agent.md +452 -0
  33. package/src/agents/design-gap-analyst.agent.md +383 -0
  34. package/src/agents/design-reviewer-temporal.agent.md +412 -0
  35. package/src/agents/design-reviewer.agent.md +31 -5
  36. package/src/agents/implement-use-cases.prompt.md +179 -0
  37. package/src/agents/ux-gap-analyst.agent.md +412 -0
  38. package/src/commands/add-rabbitmq-client.js +261 -0
  39. package/src/commands/add-temporal-client.js +22 -2
  40. package/src/commands/build.js +267 -11
  41. package/src/commands/evaluate-system.js +700 -13
  42. package/src/commands/generate-entities.js +308 -16
  43. package/src/commands/generate-rabbitmq-event.js +665 -0
  44. package/src/commands/generate-rabbitmq-listener.js +205 -0
  45. package/src/commands/generate-temporal-activity.js +968 -34
  46. package/src/commands/generate-temporal-flow.js +95 -38
  47. package/src/commands/generate-temporal-system.js +708 -0
  48. package/src/skills/build-system-yaml/SKILL.md +222 -2
  49. package/src/skills/build-system-yaml/references/domain-yaml-spec.md +50 -4
  50. package/src/skills/build-system-yaml/references/module-spec.md +57 -8
  51. package/src/skills/build-temporal-system/SKILL.md +752 -0
  52. package/src/skills/build-temporal-system/references/temporal-communication-patterns.md +167 -0
  53. package/src/skills/build-temporal-system/references/temporal-domain-yaml-spec.md +449 -0
  54. package/src/skills/build-temporal-system/references/temporal-module-spec.md +353 -0
  55. package/src/skills/build-temporal-system/references/temporal-system-yaml-spec.md +326 -0
  56. package/src/skills/implement-use-case/SKILL.md +350 -0
  57. package/src/skills/implement-use-case/references/use-case-patterns.md +980 -0
  58. package/src/skills/requirements-elicitation/SKILL.md +228 -0
  59. package/src/skills/requirements-elicitation/references/interview-framework.md +260 -0
  60. package/src/skills/requirements-elicitation/references/output-templates.md +368 -0
  61. package/src/utils/bounded-context-diagram.js +844 -0
  62. package/src/utils/domain-validator.js +266 -4
  63. package/src/utils/naming.js +10 -0
  64. package/src/utils/system-validator.js +169 -11
  65. package/src/utils/system-yaml-parser.js +318 -0
  66. package/src/utils/temporal-validator.js +497 -0
  67. package/src/utils/yaml-to-entity.js +10 -7
  68. package/templates/aggregate/DomainEventHandler.java.ejs +116 -22
  69. package/templates/aggregate/JpaAggregateRoot.java.ejs +2 -2
  70. package/templates/aggregate/JpaEntity.java.ejs +2 -2
  71. package/templates/base/docker/rabbitmq-services.yaml.ejs +12 -0
  72. package/templates/base/resources/parameters/develop/kafka.yaml.ejs +5 -0
  73. package/templates/base/resources/parameters/develop/rabbitmq.yaml.ejs +15 -0
  74. package/templates/base/resources/parameters/develop/temporal.yaml.ejs +0 -3
  75. package/templates/base/resources/parameters/local/kafka.yaml.ejs +5 -0
  76. package/templates/base/resources/parameters/local/rabbitmq.yaml.ejs +15 -0
  77. package/templates/base/resources/parameters/local/temporal.yaml.ejs +0 -3
  78. package/templates/base/resources/parameters/production/kafka.yaml.ejs +39 -8
  79. package/templates/base/resources/parameters/production/rabbitmq.yaml.ejs +32 -0
  80. package/templates/base/resources/parameters/production/temporal.yaml.ejs +0 -3
  81. package/templates/base/resources/parameters/test/kafka.yaml.ejs +12 -6
  82. package/templates/base/resources/parameters/test/rabbitmq.yaml.ejs +15 -0
  83. package/templates/base/resources/parameters/test/temporal.yaml.ejs +0 -3
  84. package/templates/base/root/AGENTS.md.ejs +1 -1
  85. package/templates/crud/EndpointsController.java.ejs +1 -1
  86. package/templates/crud/ScaffoldCommand.java.ejs +5 -2
  87. package/templates/crud/ScaffoldCommandHandler.java.ejs +3 -1
  88. package/templates/crud/ScaffoldQuery.java.ejs +5 -2
  89. package/templates/crud/ScaffoldQueryHandler.java.ejs +3 -1
  90. package/templates/crud/SubEntityRemoveCommand.java.ejs +1 -1
  91. package/templates/evaluate/report.html.ejs +1447 -90
  92. package/templates/kafka-event/KafkaConfigBean.java.ejs +1 -1
  93. package/templates/kafka-event/KafkaMessageBroker.java.ejs +3 -3
  94. package/templates/ports/PortAclMapper.java.ejs +35 -0
  95. package/templates/ports/PortFeignAdapter.java.ejs +7 -22
  96. package/templates/ports/PortFeignClient.java.ejs +4 -0
  97. package/templates/ports/PortResponseDto.java.ejs +1 -1
  98. package/templates/rabbitmq-event/RabbitConfigBean.java.ejs +33 -0
  99. package/templates/rabbitmq-event/RabbitConfigExchange.java.ejs +12 -0
  100. package/templates/rabbitmq-event/RabbitMessageBroker.java.ejs +35 -0
  101. package/templates/rabbitmq-event/RabbitMessageBrokerMethod.java.ejs +9 -0
  102. package/templates/rabbitmq-listener/RabbitConfigConsumerBean.java.ejs +33 -0
  103. package/templates/rabbitmq-listener/RabbitConfigConsumerExchange.java.ejs +12 -0
  104. package/templates/rabbitmq-listener/RabbitListenerClass.java.ejs +82 -0
  105. package/templates/rabbitmq-listener/RabbitListenerSimple.java.ejs +56 -0
  106. package/templates/read-model/ReadModelJpa.java.ejs +1 -1
  107. package/templates/read-model/ReadModelJpaRepository.java.ejs +2 -0
  108. package/templates/read-model/ReadModelRabbitListener.java.ejs +71 -0
  109. package/templates/read-model/ReadModelRepositoryImpl.java.ejs +9 -5
  110. package/templates/read-model/ReadModelSyncHandler.java.ejs +2 -0
  111. package/templates/shared/configurations/kafkaConfig/KafkaConfig.java.ejs +18 -4
  112. package/templates/shared/configurations/rabbitmqConfig/RabbitMQConfig.java.ejs +100 -0
  113. package/templates/shared/configurations/temporalConfig/TemporalConfig.java.ejs +2 -64
  114. package/templates/shared/configurations/temporalConfig/TemporalWorkerFactoryLifecycle.java.ejs +41 -0
  115. package/templates/temporal-activity/ActivityImpl.java.ejs +68 -2
  116. package/templates/temporal-activity/ActivityInput.java.ejs +14 -0
  117. package/templates/temporal-activity/ActivityInterface.java.ejs +7 -1
  118. package/templates/temporal-activity/ActivityOutput.java.ejs +14 -0
  119. package/templates/temporal-activity/NestedType.java.ejs +12 -0
  120. package/templates/temporal-activity/SharedActivityInput.java.ejs +14 -0
  121. package/templates/temporal-activity/SharedActivityInterface.java.ejs +15 -0
  122. package/templates/temporal-activity/SharedActivityOutput.java.ejs +14 -0
  123. package/templates/temporal-activity/SharedNestedType.java.ejs +12 -0
  124. package/templates/temporal-flow/ModuleHeavyActivity.java.ejs +6 -0
  125. package/templates/temporal-flow/ModuleLightActivity.java.ejs +6 -0
  126. package/templates/temporal-flow/ModuleTemporalWorkerConfig.java.ejs +58 -0
  127. package/templates/temporal-flow/WorkFlowImpl.java.ejs +172 -12
  128. package/templates/temporal-flow/WorkFlowInput.java.ejs +11 -0
  129. package/templates/temporal-flow/WorkFlowInterface.java.ejs +5 -4
  130. package/templates/temporal-flow/WorkFlowService.java.ejs +42 -12
  131. package/COMMAND_EVALUATION.md +0 -911
  132. package/test-c2010.js +0 -49
  133. package/test-update-compat.js +0 -109
  134. package/test-update-lifecycle.js +0 -121
@@ -47,6 +47,9 @@ Antes de generar nada, lee estos archivos del proyecto para obtener contexto:
47
47
  | 6.5 | `system/c4-context.mmd` + `system/c4-container.mmd` | Este archivo (sección C4) |
48
48
  | 7 | `system/{module}.yaml` (uno por módulo) | `references/domain-yaml-spec.md` |
49
49
  | 8 | `system/{module}.md` (uno por módulo) | `references/module-spec.md` |
50
+ | 9a | `AGENTS.md` (project root — rewrite) | Este archivo (Paso 9) |
51
+ | 9b | `system/VALIDATION_FLOWS.md` | Este archivo (Paso 9) |
52
+ | 9c | `system/USER_FLOWS.md` | Este archivo (Paso 9) |
50
53
 
51
54
  Ejecuta **todos** los pasos en orden antes de devolver el control al usuario.
52
55
 
@@ -54,7 +57,14 @@ Ejecuta **todos** los pasos en orden antes de devolver el control al usuario.
54
57
 
55
58
  ## Paso 1 — Recopilar información
56
59
 
57
- Si el usuario no proveyó todos los datos, **pregunta** antes de generar:
60
+ **Antes de preguntar nada**, verifica si ya existen artefactos del skill `requirements-elicitation`:
61
+ - `system/FUNCTIONAL_REQUIREMENTS.md` — casos de uso, actores, ciclos de vida, integraciones externas
62
+ - `system/PRODUCT_FLOWS.md` — flujos de negocio por actor (happy paths + alternativos)
63
+ - `system/BUSINESS_RULES.md` — reglas de negocio, invariantes, restricciones
64
+
65
+ Si existen, **léelos primero** y extrae de ellos el contexto de negocio. Reduce o elimina las preguntas que ya están respondidas por estos archivos. Estos documentos son la fuente de verdad funcional — los módulos, casos de uso, estados y reglas que diseñes deben ser consistentes con lo que describen.
66
+
67
+ Si el usuario no proveyó todos los datos y los archivos anteriores no existen, **pregunta** antes de generar:
58
68
 
59
69
  0. **Contexto del negocio** — ¿Cuál es el dominio? Actores, procesos clave, reglas importantes.
60
70
  1. **¿Usa mensajería asíncrona?** `kafka` | `rabbitmq` | `sns-sqs`
@@ -337,13 +347,36 @@ Lee `references/domain-yaml-spec.md` para la especificación completa de estruct
337
347
 
338
348
  Para cada módulo en `modules:`, genera `system/{nombre-del-modulo}.yaml` con: aggregates, entities, valueObjects, enums (con transitions si aplica), events, endpoints, listeners, ports y **readModels** — todo inferido del `system.yaml`.
339
349
 
350
+ ### Endpoints en módulos con múltiples agregados
351
+
352
+ Si el módulo tiene **2 o más agregados** (ej: `Product` + `Category`), la sección `endpoints:` debe usar `basePath: ""` (string vacío) y paths **absolutos** en cada operación:
353
+
354
+ ```yaml
355
+ # Módulo con 2+ agregados → basePath vacío
356
+ endpoints:
357
+ basePath: ""
358
+ versions:
359
+ - version: v1
360
+ operations:
361
+ - useCase: CreateProduct
362
+ method: POST
363
+ path: /products
364
+ - useCase: CreateCategory
365
+ method: POST
366
+ path: /categories
367
+ ```
368
+
369
+ Si el módulo tiene **un solo agregado**, usar `basePath: /recurso` con paths relativos (ej: `/`, `/{id}`).
370
+
371
+ **NUNCA usar `basePath: /`** (con slash) — genera trailing slash en `@RequestMapping`. Usar `basePath: ""` (vacío).
372
+
340
373
  ### Inferencia de readModels desde system.yaml
341
374
 
342
375
  Cuando `integrations.async[].consumers[]` tiene `readModel:` y el `module` es el módulo actual:
343
376
  1. Agrupar todos los eventos del mismo `readModel:` → una entrada `readModels:` con múltiples `syncedBy`
344
377
  2. `source.module` = el `producer` de esas integraciones async
345
378
  3. `source.aggregate` = derivar del nombre del readModel (ej: `ProductReadModel` → `Product`)
346
- 4. `tableName` = `rm_` + snake_case del source module (ej: `rm_products`)
379
+ 4. `tableName` = `rm_` + consumer module + `_` + source module en snake_case (ej: `rm_orders_products`)
347
380
  5. `fields` = inferir del payload del evento fuente (incluir siempre `id`)
348
381
  6. `syncedBy[].action` = `UPSERT` para Created/Updated, `SOFT_DELETE` para Deactivated, `DELETE` para Deleted
349
382
  7. Si había una entrada `integrations.sync[]` al mismo módulo fuente → **no generar `ports:`** para esa llamada (el readModel la reemplaza)
@@ -435,10 +468,197 @@ Para cada módulo, genera `system/{nombre-del-modulo}.md` con: rol del módulo,
435
468
 
436
469
  ---
437
470
 
471
+ ## Paso 9 — Artefactos post-diseño
472
+
473
+ Inmediatamente después de completar el Paso 8, genera tres artefactos finales que contextualizan el sistema recién diseñado.
474
+
475
+ ### Paso 9a — Reescribir AGENTS.md (project-specific)
476
+
477
+ Reescribe el archivo `AGENTS.md` en la **raíz del proyecto** con contenido específico para el sistema diseñado.
478
+
479
+ **Proceso:**
480
+
481
+ 1. Lee el `AGENTS.md` actual como template base
482
+ 2. Analiza `system/system.yaml` y todos los `system/{module}.yaml` para detectar qué features se usan:
483
+ - Tipo de broker (Kafka / RabbitMQ / ninguno)
484
+ - `readModels:` en algún módulo
485
+ - `ports:` (llamadas HTTP síncronas)
486
+ - `listeners:` (consumidores de eventos)
487
+ - `events:` con `triggers:` vs `lifecycle:`
488
+ - `hasSoftDelete` en alguna entidad
489
+ - `audit.trackUser` en alguna entidad
490
+ - Value Objects con `methods:`
491
+ - Enums con `transitions:` e `initialValue`
492
+ - Flags de campo: `readOnly`, `hidden`, `defaultValue`, `validations`, `reference`
493
+ 3. **Poda** secciones de features no usados según estas reglas:
494
+
495
+ | Condición | Sección a eliminar |
496
+ |---|---|
497
+ | Sin Temporal | "Temporal Workflows" completa |
498
+ | Sin `readModels:` | Subsecciones readModels de "Características Avanzadas" y checklist |
499
+ | Sin `ports:` | Subsecciones ports |
500
+ | Sin `listeners:` | Subsecciones listeners |
501
+ | Sin `hasSoftDelete` | Sección soft delete y checklist items |
502
+ | Sin `audit.trackUser` | Infraestructura UserContextFilter/UserContextHolder/AuditorAwareImpl (mantener audit básico si `audit.enabled`) |
503
+ | Sin VO `methods:` | "Value Objects con Métodos" |
504
+ | Sin enum `transitions:` | "Enums con Ciclo de Vida" |
505
+
506
+ 4. **Especializa** el contenido restante:
507
+ - Reemplaza ejemplos genéricos (`User`, `Order`) con entidades/módulos reales del proyecto
508
+ - Actualiza la sección de comandos `eva` con los nombres de módulos reales
509
+ - Actualiza el ejemplo de `domain.yaml` con la estructura real del proyecto
510
+ - Reduce el checklist a solo items relevantes para este proyecto
511
+ 5. Agrega un **header de contexto** al inicio:
512
+
513
+ ```markdown
514
+ # AI Agent Guide — {System Name}
515
+
516
+ ## Project Overview
517
+ - **System:** {name} — {brief description from system.yaml}
518
+ - **Modules:** {list of modules with 1-line descriptions}
519
+ - **Messaging:** {broker type or "none"}
520
+ - **Database:** {database type}
521
+ - **Java:** {javaVersion} / **Spring Boot:** {springBootVersion}
522
+ ```
523
+
524
+ 6. **Siempre conserva** (son universales): principios DDD, arquitectura hexagonal, reglas de mappers, reglas de DTOs, diagramas de flujo de datos (Command write / Query read), patrones de testing
525
+ 7. Escribe **todo en inglés**
526
+ 8. **Límite: ≤ 1000 líneas** — poda agresivamente, comprime ejemplos, evita redundancia
527
+
528
+ ---
529
+
530
+ ### Paso 9b — Crear system/VALIDATION_FLOWS.md
531
+
532
+ Genera `system/VALIDATION_FLOWS.md` con los flujos de validación técnica del sistema. Toda la información se deriva de `system.yaml` y los `{module}.yaml`.
533
+
534
+ **Estructura obligatoria:**
535
+
536
+ ```markdown
537
+ # Validation Flows — {System Name}
538
+
539
+ ## Prerequisites
540
+ - Services: {infrastructure requerida — DB, broker, etc.}
541
+ - Startup order: {si relevante}
542
+ - Base URLs: {por módulo si difieren}
543
+
544
+ ## 1. Module Validation
545
+
546
+ ### 1.1 {Module Name}
547
+
548
+ #### CRUD Operations
549
+ | # | Operation | Endpoint | Payload/Params | Expected Result | Validates |
550
+ |---|-----------|----------|----------------|-----------------|------ ----|
551
+ | 1 | Create | POST /x | {key fields} | 201 + entity | {invariant} |
552
+ | 2 | Get by ID | GET /x/{id} | — | 200 + entity | — |
553
+ | 3 | List | GET /x | — | 200 + page | — |
554
+ | 4 | Update | PUT /x/{id} | {fields} | 200 + updated | — |
555
+ | 5 | Delete | DELETE /x/{id} | — | 204 | — |
556
+
557
+ #### State Transitions (if module has enum transitions)
558
+ | # | Transition | Endpoint | Precondition | Expected | Event Emitted |
559
+ |---|-----------|----------|--------------|----------|---------------|
560
+ | 1 | DRAFT→PUBLISHED | PUT /x/{id}/publish | exists in DRAFT | 200, status=PUBLISHED | XPublishedEvent |
561
+
562
+ #### Business Rules
563
+ | # | Rule | How to Trigger | Expected Error |
564
+ |---|------|----------------|----------------|
565
+
566
+ (repeat per module)
567
+
568
+ ## 2. Integration Flows
569
+
570
+ ### 2.1 {Flow Name}: {Event} → {Consumer Module}
571
+ **Trigger:** {action that emits the event}
572
+ **Steps:**
573
+ 1. {Create/modify entity in producer module}
574
+ 2. {Event emitted}: {EventName} on topic {TOPIC_NAME}
575
+ 3. {Consumer module} processes via {useCase}
576
+ 4. **Verify:** {expected state change in consumer}
577
+
578
+ (repeat per async integration)
579
+
580
+ ## 3. Read Model Synchronization (if applicable)
581
+ ### 3.1 {ReadModelName}
582
+ | Source Event | Action | Verification |
583
+ |---|---|---|
584
+ | XCreatedEvent | UPSERT | Query rm_table, record exists |
585
+ | XUpdatedEvent | UPSERT | Fields updated |
586
+ | XDeactivatedEvent | SOFT_DELETE | Record marked deleted |
587
+
588
+ ## 4. Sync Port Calls (if applicable)
589
+ ### 4.1 {PortName}: {caller} → {target}
590
+ | Method | Expected | Fallback |
591
+ |---|---|---|
592
+
593
+ ## 5. Error & Edge Cases
594
+ | # | Scenario | Steps | Expected Error |
595
+ |---|----------|-------|----------------|
596
+ | 1 | Create with missing required field | POST /x without {field} | 400 + validation message |
597
+ | 2 | Invalid state transition | PUT /x/{id}/action when invalid state | 400/409 + business error |
598
+ | 3 | Get non-existent entity | GET /x/{invalid-id} | 404 |
599
+ ```
600
+
601
+ **Reglas:**
602
+ - Cada flujo debe ser concreto: paths reales, nombres de eventos reales, campos reales del proyecto
603
+ - Incluir payloads JSON sugeridos donde sea útil
604
+ - Omitir secciones enteras si no aplican (ej: sin readModels → omitir sección 3)
605
+ - Todo en inglés
606
+
607
+ ---
608
+
609
+ ### Paso 9c — Crear system/USER_FLOWS.md
610
+
611
+ Genera `system/USER_FLOWS.md` con los flujos end-to-end desde la perspectiva del usuario.
612
+
613
+ **Estructura obligatoria:**
614
+
615
+ ```markdown
616
+ # User Flows — {System Name}
617
+
618
+ ## Actors
619
+ | Actor | Description | Modules Interacted |
620
+ |-------|-------------|--------------------|
621
+ | {Actor 1} | {role description} | {module list} |
622
+
623
+ ## Flow 1: {Business Process Name}
624
+ **Actor:** {who}
625
+ **Goal:** {what they want to achieve}
626
+ **Preconditions:** {initial state}
627
+
628
+ ### Happy Path
629
+ | Step | User Action | System Response | Behind the Scenes |
630
+ |------|-------------|-----------------|-------------------|
631
+ | 1 | {does X} | {sees Y} | {endpoint called, event emitted, etc.} |
632
+ | 2 | {does Z} | {sees W} | {consumer processes, state changes} |
633
+
634
+ ### Alternative Paths
635
+ | Condition | At Step | What Happens |
636
+ |-----------|---------|---------- ---|
637
+ | {condition} | {N} | {alternative outcome} |
638
+
639
+ ### Error Paths
640
+ | Error | At Step | User Sees |
641
+ |-------|---------|----------|
642
+ | {error} | {N} | {error message/behavior} |
643
+
644
+ (repeat per major business flow)
645
+ ```
646
+
647
+ **Reglas:**
648
+ - Derivar actores de quienes consumen los `exposes[]` (misma fuente que `Person()` del C4 Context)
649
+ - Cada flujo es un **escenario de negocio completo** que cruza módulos cuando aplica
650
+ - La columna "Behind the Scenes" conecta la experiencia de usuario con la realidad técnica (eventos, procesamiento async, state changes)
651
+ - Incluir al menos un flujo por cada camino principal de caso de uso del sistema
652
+ - Foco en comportamiento observable por el usuario, no implementación interna
653
+ - Todo en inglés
654
+
655
+ ---
656
+
438
657
  ## Ciclo de refinamiento
439
658
 
440
659
  Después de entregar v1, si el usuario pide ajustes:
441
660
  - Aplica el **cambio mínimo** necesario
442
661
  - Revalida el checklist del Paso 4
443
662
  - Actualiza `system.md`, `c4-context.mmd`, `c4-container.mmd`, `{module}.yaml` y `{module}.md` afectados
663
+ - Actualiza `AGENTS.md`, `VALIDATION_FLOWS.md` y `USER_FLOWS.md` si fueron afectados por el cambio
444
664
  - Entrega solo el diff explicado
@@ -25,7 +25,7 @@ Propón campos necesarios no mencionados, Value Objects expresivos, invariantes
25
25
  4. ❌ **No `transitions` sin `initialValue`** en el enum
26
26
  5. ❌ **No inventar módulos en `reference.module`** — solo los de `system/system.yaml`
27
27
  6. ❌ **No duplicar en `endpoints:`** lo de `system.yaml → exposes:`
28
- 7. ❌ **`endpoints:` NUNCA es lista plana** — siempre `{ basePath, versions: [{ version, operations }] }`
28
+ 7. ❌ **`endpoints:` NUNCA es lista plana** — siempre `{ basePath, versions: [{ version, operations }] }`. Si el módulo tiene **2+ agregados**, usar `basePath: ""` y paths absolutos por operación
29
29
  8. ❌ **No inventar eventos** — deben coincidir con `integrations.async[]` donde `producer` es este módulo
30
30
  9. ❌ **No inventar listeners** — deben coincidir con `integrations.async[].consumers[]` donde `module` es este módulo
31
31
  10. ❌ **No inventar ports** — deben coincidir con `integrations.sync[]` donde `caller` es este módulo
@@ -76,6 +76,50 @@ endpoints:
76
76
  path: /{id}
77
77
  ```
78
78
 
79
+ ### Módulos con múltiples agregados
80
+
81
+ Cuando un módulo contiene **2 o más agregados** (ej: Product + Category), NO es posible usar un solo `basePath` porque cada agregado tiene su propio recurso REST. En este caso:
82
+
83
+ - Usar `basePath: ""` (string vacío — **NO** `basePath: /` que genera slash trailing)
84
+ - Declarar paths **absolutos** en cada operación (ej: `/products`, `/categories/{id}`)
85
+ - El controlador generado tendrá `@RequestMapping("/api/v1")` (limpio, sin slash extra)
86
+
87
+ ```yaml
88
+ # ✅ Módulo con múltiples agregados — basePath vacío + paths absolutos
89
+ endpoints:
90
+ basePath: ""
91
+ versions:
92
+ - version: v1
93
+ operations:
94
+ # ── Product operations ──
95
+ - useCase: CreateProduct
96
+ method: POST
97
+ path: /products
98
+ - useCase: GetProduct
99
+ method: GET
100
+ path: /products/{id}
101
+ - useCase: FindAllProducts
102
+ method: GET
103
+ path: /products
104
+ # ── Category operations ──
105
+ - useCase: CreateCategory
106
+ method: POST
107
+ path: /categories
108
+ - useCase: GetCategory
109
+ method: GET
110
+ path: /categories/{id}
111
+ - useCase: FindProductsByCategory
112
+ method: GET
113
+ path: /categories/{id}/products
114
+ ```
115
+
116
+ **Regla de decisión:**
117
+
118
+ | Agregados en el módulo | basePath | Paths en operations |
119
+ |---|---|---|
120
+ | 1 agregado | `/recurso` (ej: `/orders`) | Relativos: `/`, `/{id}`, `/{id}/confirm` |
121
+ | 2+ agregados | `""` (vacío) | Absolutos: `/products`, `/categories/{id}` |
122
+
79
123
  ---
80
124
 
81
125
  ## Estructura completa del module.yaml
@@ -350,7 +394,7 @@ readModels:
350
394
  source: # Trazabilidad al módulo fuente (OBLIGATORIO)
351
395
  module: products # Módulo fuente (kebab-case)
352
396
  aggregate: Product # Agregado fuente (PascalCase)
353
- tableName: rm_products # Tabla en BD (OBLIGATORIO, prefijo rm_)
397
+ tableName: rm_orders_products # Tabla en BD (OBLIGATORIO, prefijo rm_{consumer}_{source})
354
398
  fields: # Campos proyectados — subconjunto del fuente
355
399
  - name: id
356
400
  type: String
@@ -372,7 +416,7 @@ readModels:
372
416
  ### Reglas
373
417
 
374
418
  - **`name:`** — PascalCase, **DEBE** terminar con `ReadModel`
375
- - **`tableName:`** — **DEBE** empezar con `rm_` (identificación visual en BD)
419
+ - **`tableName:`** — **DEBE** seguir el patrón `rm_{consumerModule}_{sourceModule}` (ej: `rm_orders_products`) para evitar colisiones en monolitos
376
420
  - **`fields:`** — **DEBE** incluir un campo `id`
377
421
  - **`syncedBy:`** — **DEBE** tener al menos una entrada
378
422
  - **`source.module:`** — **NO PUEDE** ser el mismo módulo actual (cross-module exclusivamente)
@@ -565,7 +609,9 @@ Si un valor no es trazable → falta un endpoint o listener en el diseño.
565
609
  - [ ] `events[].triggers[]` referencia métodos existentes en `transitions[].method`
566
610
  - [ ] `{entityName}Id` en `events[].fields` cuando cruza módulos via Kafka
567
611
  - [ ] `endpoints:` con estructura `{ basePath, versions }` — no lista plana
568
- - [ ] `endpoints[].path` relativos al basePath
612
+ - [ ] Módulo con 1 agregado → `basePath: /recurso` y paths relativos
613
+ - [ ] Módulo con 2+ agregados → `basePath: ""` y paths absolutos por operación
614
+ - [ ] `endpoints[].path` coherentes con el basePath elegido
569
615
  - [ ] `listeners[]` para todos los eventos donde este módulo es consumidor
570
616
  - [ ] `listeners[].useCase` coincide con `consumers[].useCase`
571
617
  - [ ] `listeners[].topic` bare SCREAMING_SNAKE_CASE (sin topicPrefix)
@@ -34,16 +34,23 @@ Especificación técnica narrativa del sistema completo. Una sección `##` por c
34
34
  **Postconditions:** [system state after successful execution]
35
35
  **Validations and errors:** [exception conditions and error types]
36
36
  **Events emitted:** [DomainEvent name and trigger condition, or "none"]
37
+ **Operations:**
38
+ 1. [Load entity / validate precondition — throw NotFoundException or 400 if invalid]
39
+ 2. [External port call: {PortName}.{method}() — if applicable]
40
+ 3. [Invoke domain method: entity.{method}()]
41
+ 4. [Persist via repository]
42
+ 5. [Emit event — if applicable]
37
43
 
38
44
  ### Exposed Endpoints
39
45
  [One `####` per endpoint in exposes:]
40
46
 
41
47
  #### {METHOD} {/path}
42
48
  **Purpose:** [endpoint description and usage context]
43
- **Path params / Query params:** [each parameter described]
44
- **Request body:** [expected fields, types, validation constraints]
45
- **Response:** [returned fields and their business meaning]
46
- **Errors:** [HTTP status codes and when they occur]
49
+ **Path params:** [param Type Description; omit if none]
50
+ **Query params:** [GET/DELETE only — param: Type, required/optional, default, description; omit if none]
51
+ **Request body:** [POST/PUT/PATCH only field: Type — constraint; omit for GET/DELETE]
52
+ **Response:** [GET only field: Type business meaning; list endpoints include {content:[...], totalElements, page, size}]
53
+ **Errors:** [HTTP status — condition]
47
54
 
48
55
  ### Emitted Events
49
56
  [Only if module is producer in integrations.async]
@@ -81,6 +88,8 @@ Especificación técnica narrativa del sistema completo. Una sección `##` por c
81
88
  - **Incluir useCases de consumers** como casos de uso del módulo consumidor.
82
89
  - **Referenciar módulos por nombre**.
83
90
  - **Máquinas de estado** cuando hay ciclos de vida.
91
+ - **Endpoints detallados**: separar path params de query params. Para GETs indicar los campos clave de la respuesta con sus tipos. Para POST/PUT/PATCH listar los campos del body con tipo y constraint. Nunca "ver request" como descripción de response.
92
+ - **Operations en casos de uso**: el campo `**Operations:**` es obligatorio en cada `#### {UseCaseName}`. Cada ítem describe un paso concreto del handler referenciando nombres reales de repositorios, ports, métodos de dominio y eventos. No usar items genéricos como "execute business logic".
84
93
  - Omitir secciones no aplicables.
85
94
 
86
95
  ---
@@ -215,6 +224,12 @@ sequenceDiagram
215
224
  **Invariants verified:** [ID list — e.g., INV-01, INV-03]
216
225
  **Validations and errors:** [exception conditions, error type, HTTP status]
217
226
  **Events emitted:** [DomainEvent name and condition, or "none"]
227
+ **Operations:**
228
+ 1. [Load entity by id via {Repository}.findById() — throw NotFoundException if absent]
229
+ 2. [Call {PortName}.{method}() to obtain cross-module data — if applicable]
230
+ 3. [Invoke entity.{domainMethod}() — domain enforces invariants]
231
+ 4. [Persist via {Repository}.save(entity)]
232
+ 5. [DomainEventHandler publishes event after transaction commit — if applicable]
218
233
 
219
234
  **Flow diagram:**
220
235
  ```mermaid
@@ -235,10 +250,42 @@ flowchart TD
235
250
  ### {METHOD} {/path}
236
251
  **Use case:** `{UseCase}`
237
252
  **Purpose:** [description]
238
- **Path params / Query params:** [each parameter]
239
- **Request body:** [fields, types, validations]
240
- **Response:** [fields and business meaning]
241
- **Errors:** [HTTP status codes and conditions]
253
+ **Path params:** _(omit table if none)_
254
+
255
+ | Param | Type | Description |
256
+ |-------|------|-------------|
257
+ | {param} | `String` | [description] |
258
+
259
+ **Query params:** _(GET / DELETE only — omit table if none)_
260
+
261
+ | Param | Type | Required | Default | Description |
262
+ |-------|------|----------|---------|-------------|
263
+ | {param} | `String` | No | — | [description] |
264
+
265
+ **Request body:** _(POST / PUT / PATCH only — omit for GET / DELETE)_
266
+ ```json
267
+ {
268
+ "field": "String", // required — [constraint]
269
+ "otherField": "Integer" // optional — [constraint]
270
+ }
271
+ ```
272
+
273
+ **Response schema:** _(GET single only — omit for mutations)_
274
+ ```json
275
+ {
276
+ "id": "String",
277
+ "field": "Type" // [business meaning]
278
+ }
279
+ ```
280
+ _(For GET list: `{ "content": [...], "totalElements": "Long", "page": "Integer", "size": "Integer" }`)_
281
+
282
+ **Errors:**
283
+
284
+ | Status | Condition |
285
+ |--------|-----------|
286
+ | 404 | [entity] not found |
287
+ | 400 | [validation failure] |
288
+ | 409 | [invariant violated] |
242
289
 
243
290
  ## Emitted Events
244
291
  [Only if module is producer in integrations.async]
@@ -290,6 +337,8 @@ flowchart TD
290
337
  - **Diagrama de flujo por caso de uso**: `flowchart TD` dentro de cada `### {UseCase}` con trigger, invariantes, lógica y eventos.
291
338
  - **Máquina de estados condicional**: solo si hay entidades con ciclo de vida. Restricciones de transición son invariantes implícitas.
292
339
  - **Referenciar invariantes** en cada caso de uso (INV-01, INV-02...).
340
+ - **Endpoints con contratos ricos**: para cada endpoint separar path params, query params, body y response en bloques distintos con tipos y constraints reales del dominio. Para GETs incluir el JSON schema de respuesta; para POST/PUT/PATCH el JSON del body. Listas incluyen wrapper de paginación `{ content, totalElements, page, size }`. Nunca usar placeholders genéricos.
341
+ - **Operations en casos de uso**: el campo `**Operations:**` es **obligatorio** en cada `### {UseCase}`. Lista los pasos del handler con nombres concretos: repositorio, port, método de dominio, evento. Sirve como contrato de implementación evaluable por revisores humanos antes de generar código.
293
342
  - **No duplicar** system.md — el `.md` del módulo es la especificación completa.
294
343
  - Archivos en `system/{module-name}.md`.
295
344