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.
- package/AGENTS.md +2 -0
- package/DOMAIN_YAML_GUIDE.md +3 -1
- package/QUICK_REFERENCE.md +8 -4
- package/bin/eva4j.js +70 -2
- package/config/defaults.json +1 -0
- package/docs/CAMUNDA_DMN_GUIDE.md +1380 -0
- package/docs/KAFKA_PRODUCTION_CONFIG.md +441 -0
- package/docs/RABBITMQ_PRODUCTION_CONFIG.md +227 -0
- package/docs/commands/ADD_RABBITMQ_CLIENT.md +192 -0
- package/docs/commands/EVALUATE_SYSTEM.md +272 -8
- package/docs/commands/GENERATE_RABBITMQ_EVENT.md +341 -0
- package/docs/commands/GENERATE_RABBITMQ_LISTENER.md +595 -0
- package/docs/commands/GENERATE_TEMPORAL_FLOW.md +52 -12
- package/docs/commands/INDEX.md +27 -3
- package/docs/prototype/TEMPORAL_COMMUNICATION_PATTERNS.md +731 -0
- package/docs/prototype/TEMPORAL_DESIGN_METHODOLOGY.md +740 -0
- package/docs/prototype/system/RISKS.md +277 -0
- package/docs/prototype/system/customers.yaml +133 -0
- package/docs/prototype/system/inventory.yaml +109 -0
- package/docs/prototype/system/notifications.yaml +131 -0
- package/docs/prototype/system/orders.yaml +241 -0
- package/docs/prototype/system/payments.yaml +256 -0
- package/docs/prototype/system/products.yaml +168 -0
- package/docs/prototype/system/system.yaml +269 -0
- package/examples/domain-endpoints-multi-aggregate.yaml +140 -0
- package/examples/domain-read-models.yaml +2 -2
- package/examples/system/customer.yaml +89 -0
- package/examples/system/orders.yaml +119 -0
- package/examples/system/product.yaml +27 -0
- package/examples/system/system.yaml +80 -0
- package/package.json +1 -1
- package/src/agents/design-gap-analyst-temporal.agent.md +452 -0
- package/src/agents/design-gap-analyst.agent.md +383 -0
- package/src/agents/design-reviewer-temporal.agent.md +412 -0
- package/src/agents/design-reviewer.agent.md +31 -5
- package/src/agents/implement-use-cases.prompt.md +179 -0
- package/src/agents/ux-gap-analyst.agent.md +412 -0
- package/src/commands/add-rabbitmq-client.js +261 -0
- package/src/commands/add-temporal-client.js +22 -2
- package/src/commands/build.js +267 -11
- package/src/commands/evaluate-system.js +700 -13
- package/src/commands/generate-entities.js +308 -16
- package/src/commands/generate-rabbitmq-event.js +665 -0
- package/src/commands/generate-rabbitmq-listener.js +205 -0
- package/src/commands/generate-temporal-activity.js +968 -34
- package/src/commands/generate-temporal-flow.js +95 -38
- package/src/commands/generate-temporal-system.js +708 -0
- package/src/skills/build-system-yaml/SKILL.md +222 -2
- package/src/skills/build-system-yaml/references/domain-yaml-spec.md +50 -4
- package/src/skills/build-system-yaml/references/module-spec.md +57 -8
- package/src/skills/build-temporal-system/SKILL.md +752 -0
- package/src/skills/build-temporal-system/references/temporal-communication-patterns.md +167 -0
- package/src/skills/build-temporal-system/references/temporal-domain-yaml-spec.md +449 -0
- package/src/skills/build-temporal-system/references/temporal-module-spec.md +353 -0
- package/src/skills/build-temporal-system/references/temporal-system-yaml-spec.md +326 -0
- package/src/skills/implement-use-case/SKILL.md +350 -0
- package/src/skills/implement-use-case/references/use-case-patterns.md +980 -0
- package/src/skills/requirements-elicitation/SKILL.md +228 -0
- package/src/skills/requirements-elicitation/references/interview-framework.md +260 -0
- package/src/skills/requirements-elicitation/references/output-templates.md +368 -0
- package/src/utils/bounded-context-diagram.js +844 -0
- package/src/utils/domain-validator.js +266 -4
- package/src/utils/naming.js +10 -0
- package/src/utils/system-validator.js +169 -11
- package/src/utils/system-yaml-parser.js +318 -0
- package/src/utils/temporal-validator.js +497 -0
- package/src/utils/yaml-to-entity.js +10 -7
- package/templates/aggregate/DomainEventHandler.java.ejs +116 -22
- package/templates/aggregate/JpaAggregateRoot.java.ejs +2 -2
- package/templates/aggregate/JpaEntity.java.ejs +2 -2
- package/templates/base/docker/rabbitmq-services.yaml.ejs +12 -0
- package/templates/base/resources/parameters/develop/kafka.yaml.ejs +5 -0
- package/templates/base/resources/parameters/develop/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/develop/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/local/kafka.yaml.ejs +5 -0
- package/templates/base/resources/parameters/local/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/local/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/production/kafka.yaml.ejs +39 -8
- package/templates/base/resources/parameters/production/rabbitmq.yaml.ejs +32 -0
- package/templates/base/resources/parameters/production/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/test/kafka.yaml.ejs +12 -6
- package/templates/base/resources/parameters/test/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/test/temporal.yaml.ejs +0 -3
- package/templates/base/root/AGENTS.md.ejs +1 -1
- package/templates/crud/EndpointsController.java.ejs +1 -1
- package/templates/crud/ScaffoldCommand.java.ejs +5 -2
- package/templates/crud/ScaffoldCommandHandler.java.ejs +3 -1
- package/templates/crud/ScaffoldQuery.java.ejs +5 -2
- package/templates/crud/ScaffoldQueryHandler.java.ejs +3 -1
- package/templates/crud/SubEntityRemoveCommand.java.ejs +1 -1
- package/templates/evaluate/report.html.ejs +1447 -90
- package/templates/kafka-event/KafkaConfigBean.java.ejs +1 -1
- package/templates/kafka-event/KafkaMessageBroker.java.ejs +3 -3
- package/templates/ports/PortAclMapper.java.ejs +35 -0
- package/templates/ports/PortFeignAdapter.java.ejs +7 -22
- package/templates/ports/PortFeignClient.java.ejs +4 -0
- package/templates/ports/PortResponseDto.java.ejs +1 -1
- package/templates/rabbitmq-event/RabbitConfigBean.java.ejs +33 -0
- package/templates/rabbitmq-event/RabbitConfigExchange.java.ejs +12 -0
- package/templates/rabbitmq-event/RabbitMessageBroker.java.ejs +35 -0
- package/templates/rabbitmq-event/RabbitMessageBrokerMethod.java.ejs +9 -0
- package/templates/rabbitmq-listener/RabbitConfigConsumerBean.java.ejs +33 -0
- package/templates/rabbitmq-listener/RabbitConfigConsumerExchange.java.ejs +12 -0
- package/templates/rabbitmq-listener/RabbitListenerClass.java.ejs +82 -0
- package/templates/rabbitmq-listener/RabbitListenerSimple.java.ejs +56 -0
- package/templates/read-model/ReadModelJpa.java.ejs +1 -1
- package/templates/read-model/ReadModelJpaRepository.java.ejs +2 -0
- package/templates/read-model/ReadModelRabbitListener.java.ejs +71 -0
- package/templates/read-model/ReadModelRepositoryImpl.java.ejs +9 -5
- package/templates/read-model/ReadModelSyncHandler.java.ejs +2 -0
- package/templates/shared/configurations/kafkaConfig/KafkaConfig.java.ejs +18 -4
- package/templates/shared/configurations/rabbitmqConfig/RabbitMQConfig.java.ejs +100 -0
- package/templates/shared/configurations/temporalConfig/TemporalConfig.java.ejs +2 -64
- package/templates/shared/configurations/temporalConfig/TemporalWorkerFactoryLifecycle.java.ejs +41 -0
- package/templates/temporal-activity/ActivityImpl.java.ejs +68 -2
- package/templates/temporal-activity/ActivityInput.java.ejs +14 -0
- package/templates/temporal-activity/ActivityInterface.java.ejs +7 -1
- package/templates/temporal-activity/ActivityOutput.java.ejs +14 -0
- package/templates/temporal-activity/NestedType.java.ejs +12 -0
- package/templates/temporal-activity/SharedActivityInput.java.ejs +14 -0
- package/templates/temporal-activity/SharedActivityInterface.java.ejs +15 -0
- package/templates/temporal-activity/SharedActivityOutput.java.ejs +14 -0
- package/templates/temporal-activity/SharedNestedType.java.ejs +12 -0
- package/templates/temporal-flow/ModuleHeavyActivity.java.ejs +6 -0
- package/templates/temporal-flow/ModuleLightActivity.java.ejs +6 -0
- package/templates/temporal-flow/ModuleTemporalWorkerConfig.java.ejs +58 -0
- package/templates/temporal-flow/WorkFlowImpl.java.ejs +172 -12
- package/templates/temporal-flow/WorkFlowInput.java.ejs +11 -0
- package/templates/temporal-flow/WorkFlowInterface.java.ejs +5 -4
- package/templates/temporal-flow/WorkFlowService.java.ejs +42 -12
- package/COMMAND_EVALUATION.md +0 -911
- package/test-c2010.js +0 -49
- package/test-update-compat.js +0 -109
- 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
|
-
|
|
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_` +
|
|
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:
|
|
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**
|
|
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
|
-
- [ ] `
|
|
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
|
|
44
|
-
**
|
|
45
|
-
**
|
|
46
|
-
**
|
|
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
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|