| name | ddd-step1-authoring |
| description | Ejecuta el Paso 1 del framework de diseño de sistemas con DDD: Diseño Estratégico. Analiza el contexto de negocio ingresado, identifica Bounded Contexts, Agregados y relaciones, y genera los cinco artefactos canónicos: system.yaml, system-spec.md y system-diagram.mmd en arch/system/, más AGENTS.md y CLAUDE.md en la raíz del proyecto. Usar SIEMPRE que el usuario quiera diseñar un nuevo sistema, plataforma, aplicación o dominio de negocio desde cero. También aplica cuando el usuario diga frases como "quiero diseñar", "necesito modelar un sistema", "vamos a hacer el paso 1", "analiza este negocio", "define los bounded contexts", "crea la arquitectura de", o cuando proporcione una descripción de un negocio y pida estructurarla arquitectónicamente. No esperar que el usuario use terminología DDD — si describe un negocio o sistema, este skill debe activarse.
|
DDD Paso 1 — Diseño Estratégico
Este skill produce el diseño estratégico completo de un sistema basado en Domain-Driven
Design. Al finalizar, existen cinco artefactos:
arch/system/system.yaml — fuente de verdad estructurada (input para generadores en pasos siguientes)
arch/system/system-spec.md — narrativa detallada por Bounded Context
arch/system/system-diagram.mmd — diagrama C4 Contenedores en Mermaid
AGENTS.md — contexto consolidado del sistema para agentes de IA
CLAUDE.md — contexto e instrucciones para Claude Code en la raíz del proyecto
Tu Rol Durante Esta Sesión
Asumes dos voces expertas simultáneas durante todo el proceso de diseño. Ambas deben
estar presentes al identificar BCs, definir fronteras, clasificar dominios y justificar
decisiones. No son roles alternativos — son una tensión productiva que produce mejores
diseños.
Voz 1: Experto de Negocio del Dominio
Conoces el negocio desde adentro. Piensas en términos de valor, flujos reales, cómo
operan las personas en el día a día, qué dolores existen, qué datos se manejan.
- Identificas los eventos que el negocio reconocería como significativos ("el pedido fue confirmado", "el stock se agotó")
- Cuestionas si los nombres de BCs y agregados reflejan el lenguaje que usa el negocio, no jerga técnica
- Detectas qué es realmente diferenciador para el negocio vs qué es plomería genérica
- Piensas en el cliente final y en los operadores internos, no solo en el sistema
- Señalas flujos de excepción relevantes: ¿qué pasa cuando falla el pago? ¿cuando el stock se agota en checkout?
Voz 2: Ingeniero Senior de Diseño de Sistemas DDD
Conoces los principios DDD y sus trade-offs. Sabes cuándo un BC es demasiado grande,
cuándo una integración sincrónica creará acoplamiento problemático, cuándo un agregado
esconde dos agregados distintos.
- Evalúas la dirección de dependencias entre BCs (Core no depende de Supporting)
- Decides si una integración es sincrónica o asíncrona basándote en la necesidad real del flujo
- Dimensionas correctamente los BCs: ni demasiado grandes ni demasiado pequeños
- Aplicas ACL en toda integración con sistemas externos
- Seleccionas los defaults de infraestructura que mejor se alinean con el contexto del negocio
Cuando las dos voces produzcan tensión (ej: el negocio quiere todo junto, la ingeniería
quiere separarlo), explicitarlo al usuario como parte del análisis. Esa tensión es
información de diseño, no un problema a ocultar.
Fase 1: Recolección de Contexto
Antes de diseñar, asegúrate de tener suficiente información. El usuario puede entregar
contexto libre o responder preguntas. Evalúa qué tienes y qué falta.
Información mínima requerida para comenzar
| Categoría | Por qué importa |
|---|
| Modelo de negocio | Define si hay marketplace, tienda propia, B2B, B2C — cambia los BCs radicalmente |
| Actores principales | Quién usa el sistema determina los flujos centrales |
| Flujo principal de valor | La secuencia de eventos que genera el valor del negocio |
| Medios de pago | Determina si Pagos es simple o complejo |
| Entrega/Fulfillment | ¿Físico, digital, servicio? Define si existe un BC de Despacho/Logística |
| Funcionalidades esenciales | Diferencia el core del supporting |
| Sistemas externos ya existentes | Define qué se integra vs qué se construye |
Cuándo hacer preguntas vs cuándo inferir
REGLA OBLIGATORIA: Antes de generar cualquier artefacto, usa vscode_askQuestions (o en texto directo) (o pregunta en texto si no está disponible) para
cubrir todas las dimensiones críticas que el usuario NO haya respondido explícitamente
en su prompt. No inferir dimensiones que cambiarían la estructura de BCs si el usuario
las respondiera de forma distinta.
Dimensiones que SIEMPRE requieren respuesta explícita del usuario (no inferir):
- Modelo de negocio: tienda propia vs marketplace — cambia radicalmente los BCs Core
- Segmento: B2C vs B2B vs ambos
- Fulfillment: entrega física propia, tercerizada, digital, o presencial
- Funcionalidades core del lanzamiento: evita modelar BCs para features que no van en V1
Dimensiones que SÍ puedes inferir y documentar como supuesto en notes:
- Tipo de infraestructura (tipo de broker y tipo de BD) — aplicar defaults (
messageBroker: true si hay async, database.type: relational)
- Sistemas externos genéricos (ej: pasarela de pago) cuando el dominio los implica claramente
- Actores secundarios obvios del dominio (ej: administrador interno)
Cuando infiras, registra el supuesto en el campo notes del artefacto correspondiente.
Agrupa todas las preguntas en una sola llamada vscode_askQuestions (o en texto directo) — nunca en múltiples rondas.
Preguntas clave a hacer (adapta según lo que ya sabes)
Para sistemas de venta/ecommerce/tickets/seguros/etc., las dimensiones críticas son:
- Modelo de negocio: ¿Tienda propia, marketplace, híbrido?
- Segmento de clientes: ¿B2C, B2B, ambos?
- Fulfillment: ¿Entrega física propia, tercerizada, digital, presencial?
- Medios de pago: ¿Cuáles? (define la complejidad del BC Pagos)
- Inventario: ¿Propio centralizado, distribuido, sin inventario?
- Funcionalidades core del lanzamiento: (multiselect — evita sobre-ingeniería)
- Sistemas externos ya definidos: ¿ERP, pasarela de pago, operador logístico?
- Tipo de base de datos: ¿relacional, documental, clave-valor, grafos? (o asumir
relational por default)
— La tecnología concreta (PostgreSQL, MySQL, etc.) se decide en el generador de código, no aquí.
Usa opciones cerradas con allowFreeformInput: true para agilizar. Agrupa en una sola
llamada vscode_askQuestions (o en texto directo) con todas las preguntas pendientes.
Análisis de dominio e integraciones (skills separados)
El análisis estratégico previo a la generación vive en dos skills enfocados que el
orquestador design-system ejecuta antes de esta fase (vía workers en Claude Code, o
inline en Copilot):
ddd-domain-analysis — event storming, clasificación de BCs (Core/Supporting/Generic),
agregados de nivel estratégico, checklist de entidades candidatas a agregado y dependencias
implícitas por ciclo de vida. Worker: domain-analyst.
ddd-integration-audit — identificación de sagas por coreografía y Auditoría de
Completitud de Integraciones (Matriz A–H, snapshot-at-write-time, decisión LRM vs HTTP del
Paso H). Worker: integration-auditor.
Esta fase asume que ese análisis ya está hecho y sus decisiones (BCs, agregados, integraciones,
sagas, LRM/HTTP) ya fueron confirmadas por el diseñador. Aquí solo se generan los artefactos.
Fase 3: Generación de Artefactos
Genera los tres artefactos en orden. Lee las referencias antes de escribir:
→ Lee references/system-yaml-schema.md para el schema completo de system.yaml
→ Lee references/system-yaml-guide.md para ejemplos anotados, señales de diseño (sobre/sub-diseño), patrones de integración con árbol de decisión y checklist de validación
Pre-vuelo: Verificación de Estructura — Object Storage
Gate no omitible — ejecutar antes del check de agnosticismo.
Recorre la lista de externalSystems candidatos. Si alguno tiene nombre o propósito que
coincida con almacenamiento de binarios (storage, images, files, documents,
uploads, attachments, media, assets) o sus operaciones son upload/download/
delete/put/get sobre objetos binarios:
→ No lo declares como externalSystem. Usa infrastructure.objectStorage en su lugar.
→ Elimina cualquier entrada externalSystems + integrations[] que hayas generado para ese recurso.
→ Declara el store en infrastructure.objectStorage con los campos correctos (name, visibility, urlAccess, ownedBy, notes).
→ Los use cases que interactúen con ese store usarán storageCalls[] en el diseño táctico (Paso 2).
Ver guía completa en references/system-yaml-guide.md → sección externalSystems → "Qué NO es un sistema externo".
Pre-vuelo: Verificación de Agnosticismo Tecnológico
Gate no omitible — ejecutar antes de escribir cualquier archivo. Si detectas referencias
tecnológicas en el diseño en memoria, corrígelas aquí antes de proceder.
Buscar en todos los campos de texto del diseño (purpose, description, notes, nombres
de BCs, agregados, entidades, contratos, actores):
| Categoría | Ejemplos a detectar |
|---|
| Frameworks / librerías | Spring, JPA, Hibernate, Django, FastAPI, NestJS, TypeORM, Rails, Laravel, Express |
| Bases de datos concretas | PostgreSQL, MySQL, MongoDB, DynamoDB, Redis, Cassandra, ElasticSearch |
| Message brokers concretos | Kafka, RabbitMQ, SQS, PubSub, ServiceBus, NATS |
| Proveedores cloud / storage | AWS, GCP, Azure, S3, S3-compatible, GCS, MinIO, Azure Blob, ECR, Lambda, Cloud Run |
| Patrones de implementación en notes | proxif, CDN, presign, signed URL algorithm, IAM, bucket policy, multipart upload |
| Anotaciones / tipos de lenguaje | @Entity, @Column, BigDecimal, LocalDateTime, UUID (Java), List<T>, Dict, async def |
| SQL físico | Nombres de tablas, columnas, SELECT, JOIN, INDEX ON, secuencias, triggers |
Caso frecuente — objectStorage[].notes: el campo notes de un store describe propósito de negocio.
Si contiene referencias al proveedor (S3, GCS, MinIO), al patrón de acceso (proxify, CDN,
presigned URL) o a la infraestructura (bucket policy, IAM role), reemplazar por lenguaje de dominio:
qué almacena, quién lo usa y qué produce para el agregado. Ver ejemplos en references/system-yaml-guide.md.
Primitivas DSL válidas que sí pueden aparecer (no son referencias tecnológicas):
message-broker, http, grpc, websocket, oauth2-cc, mTLS, internal-jwt,
relational, document, key-value, graph, modular-monolith, microservices,
serverless, hexagonal, layered, clean, schema-per-bc, db-per-bc, prefix-per-bc.
Si se detecta cualquier referencia fuera de las primitivas válidas:
- Reemplazarla por la primitiva DSL equivalente (ej:
Kafka → message-broker)
- O moverla al campo
notes con el prefijo [Decisión de Fase 2 — no parte del diseño:]
- Solo entonces continuar con la generación de artefactos
3.1 system.yaml
PRE-REQUISITO OBLIGATORIO: La Auditoría de Completitud de Integraciones
(ddd-integration-audit §2.6, Pasos A–F) debe estar completada antes de escribir este archivo. Si se detectaron
integraciones faltantes durante la auditoría, deben estar incorporadas al diseño.
No escribir system.yaml con integrations[] incompleto.
Idioma: INGLÉS obligatorio. Todo el contenido del archivo — nombres de BCs,
agregados, entidades, contratos, descripciones (purpose, description, notes) —
debe escribirse en inglés. Este archivo es el input estructurado para los pasos
siguientes de diseño táctico y generación de código; el inglés es la lengua franca
del código y garantiza consistencia con los identificadores que se generarán.
Los únicos valores en español permitidos son los comentarios de cabecera del archivo
(líneas con #) si el equipo lo prefiere, pero ningún campo YAML.
Estructura obligatoria con estas secciones en orden:
system: → system identity
actors: → (opcional) tipos de actor que interactúan con el sistema
boundedContexts: → BCs with aggregates (strategic level)
externalSystems: → external systems referenced in integrations
integrations: → communication map between BCs and externals
sagas: → (opcional) sagas por coreografía que cruzan 3+ BCs
infrastructure: → technology decisions from Step 1
actors[] — Cuándo incluirlo: Declarar actors[] cuando el sistema tiene 2 o más
tipos de actor distintos (customer, admin, system, etc.). Su presencia activa la
validación G14 del generador: cada useCases[].actor en los YAML tácticos de
cada BC debe referenciar exactamente un nombre declarado aquí.
Cuando actors[] está ausente, el generador no valida los campos actor de los
casos de uso (comportamiento legacy — cualquier valor es aceptado sin verificación).
Declarar actors[] desde el Paso 1 hace el diseño táctico más preciso: obliga al
diseñador a identificar quién ejecuta cada caso de uso y previene inconsistencias
entre el diseño estratégico y el táctico.
actors:
- name: customer
description: Registered user making purchases and managing their orders.
- name: admin
description: Back-office operator managing catalog and inventory.
- name: system
description: Internal system-to-system calls (e.g. scheduled jobs, saga triggers).
Defaults de infraestructura (aplicar si el usuario no especifica):
| Campo | Default | Opciones válidas |
|---|
deployment.strategy | modular-monolith | modular-monolith | microservices | serverless |
deployment.architectureStyle | hexagonal | hexagonal | layered | clean |
database.type | relational | relational | document | key-value | graph |
database.isolationStrategy | schema-per-bc | schema-per-bc | db-per-bc | prefix-per-bc |
messageBroker | true (si hay canales async) | true | omitir si no hay message-broker |
authServer | decisión explícita requerida | true | omitir si no hay autenticación JWT |
deployment.strategy: modular-monolith es doctrinal, no un default negociable:
la metodología es monolith-first — el desarrollo completo ocurre sobre monolito modular
y los BCs se desprenden como microservicios con el comando detach en la fase final
del ciclo (ver references/architecture-decision-guide.md §1, incluidos los
criterios de detachability que el diseño debe garantizar). Si el usuario declara
microservices/serverless, registrar su motivo en notes — el schema lo permite
y no hay validación coercitiva.
El resto de decisiones sí se contrasta con señales — no apliques defaults
mecánicamente: antes de fijar deployment.architectureStyle y
database.isolationStrategy, lee la guía (§2–§3) y contrasta las señales del contexto
(riqueza de invariantes, restricciones de datos, sensibilidad regulatoria). Documenta
en notes la elección y las señales que la justifican — un notes que solo dice
"default" no permite auditar la decisión (checklists F5–F7 de ddd-design-validation).
El §4 de la guía da además el criterio estratégico eventos-vs-síncrono para cada
integración interna.
Cuando apliques un default, docuéntalo en el campo notes de esa sección.
Si el diseño no tiene integraciones por eventos, omite messageBroker.
La tecnología concreta del broker y la base de datos (RabbitMQ, Kafka, PostgreSQL…) es decisión del generador de código (Fase 2) — no se declara en el Paso 1.
authServer: true — Regla de decisión obligatoria:
Declara authServer: true en infrastructure si cualquiera de estas condiciones se cumple:
- Al menos un UC del sistema usará
authorization (roles, permisos, scopes, ownership)
- Al menos un endpoint no es completamente público (accesible sin JWT)
- El sistema tiene diferentes actores con distintos niveles de acceso (admin vs customer vs system)
Qué genera: SecurityConfig.java, SecurityContextUtil.java, configuración JWT resource server,
y archivos auth-server.yaml por entorno (dev/test/staging/prod).
Omitir solo si el sistema no tiene ninguna autenticación JWT (e.g., servicio puramente interno
accedido solo desde red privada sin tokens). En ese caso, el generador no produce ningún artefacto
de seguridad y todos los endpoints son accesibles sin autenticación.
El proveedor concreto (Keycloak, Cognito, Auth0) es decisión de la Fase 2 — no se declara aquí.
Patrones de integración válidos:
| Patrón | Cuándo usarlo |
|---|
customer-supplier | Un BC depende del modelo de otro, sincrónico |
event | Comunicación asíncrona vía eventos de dominio |
acl | Integración con sistema externo — siempre usar ACL |
shared-kernel | Dos BCs comparten código (usar con precaución) |
open-host | BC publica API estable para consumo externo |
Criterios de selección: leer references/integration-patterns-guide.md antes de
asignar pattern — obligatorio si el candidato es shared-kernel (tres condiciones
restrictivas; sin justificación en notes es 🔴) u open-host (señal: ≥ 2 consumidores
del mismo contrato o consumidores externos). La guía incluye el árbol de decisión
completo y los errores de clasificación frecuentes.
Canales válidos: http | grpc | message-broker | websocket
Formato de contracts[] según canal:
El schema soporta solo coreografía. Si la saga tiene > 4 pasos, branching condicional
o necesidad de estado centralizado del proceso, aplicar ddd-integration-audit §2.5.1
(descomponer con evento pivote, promover a BC coordinador, o registrar la deuda) antes
de escribirla aquí.
sagas:
- name: CheckoutSaga
description: >
trigger:
event: OrderConfirmed
bc: orders
steps:
- order: 1
bc: payments
triggeredBy: OrderConfirmed
onSuccess: PaymentApproved
onFailure: PaymentFailed
compensation: PaymentCancelled
- order: 2
bc: inventory
triggeredBy: PaymentApproved
onSuccess: StockReserved
onFailure: StockReservationFailed
compensation: StockReleased
Reglas del schema:
-
Todos los nombres de eventos siguen la misma regla PascalCase inglés que los contratos de integración.
-
Cada evento en onSuccess, onFailure y compensation debe existir como contrato en la integración from: {bc}, to: ..., pattern: event del BC emisor (agregar si falta).
-
onFailure y compensation son opcionales por paso: omitir si el paso no puede fallar o si no tiene compensación.
-
compensation debe ser siempre un string PascalCase — el nombre del evento que confirma que la
compensación fue ejecutada. Nunca declarar como objeto con sub-propiedades: si se hace, la constante
en {SagaName}Steps.java se renderiza como [object Object] y el índice de anotaciones no funciona
(fallo silencioso sin error de build).
compensation: StockReleased
compensation:
bc: inventory
action: release-stock
-
El disparador de una compensación no es el evento compensation de system.yaml, sino el onFailure
del paso posterior que falla. Ejemplo: inventory tiene compensation: StockReleased en el paso 1, pero
el evento que activa esa compensación es PaymentFailed (onFailure del paso 2 de payments). Ese evento
debe declararse en consumed[] de inventory con un UC sagaStep.role: compensation. El generador no
crea ese listener automáticamente a partir del campo compensation de system.yaml.
3.1.1 Capacidades extendidas de system.yaml soportadas por el generador
El generador procesa los siguientes bloques opcionales. Declararlos solo
cuando aporten valor concreto al diseño — no añadirlos por completar.
actors[] — validación cruzada con el diseño táctico
actors:
- name: customer
description: Registered user making purchases and managing their orders.
- name: admin
description: Back-office operator managing catalog and inventory.
- name: system
description: Internal system-to-system calls (scheduled jobs, saga triggers).
Cuándo declarar:
- Siempre que el sistema tenga 2 o más tipos de actor (customer/admin/system).
- Antes de comenzar el diseño táctico (Paso 2): obliga a que cada UC declare su actor.
Efecto en el generador:
- Activa la validación G14: si
actors[] está declarado y un useCases[].actor en
algún {bc}.yaml no coincide con ningún nombre de esta lista → error bloqueante.
- Si
actors[] está ausente, la validación G14 se omite (comportamiento legacy).
externalSystems[].operations[] — OBLIGATORIO si el sistema externo es referenciado
Cuando un externalSystem aparece como to en integrations[], debe declarar
qué operaciones expone para que el generador produzca los ACL adapters. Sin operations[]
el generador emite INT-008 (warn) y salta la generación del adaptador.
externalSystems:
- name: payment-gateway
type: external
description: Third-party payment processor
baseUrlProperty: integration.payment-gateway.base-url
operations:
- name: chargePayment
method: POST
path: /v1/charges
request:
fields:
- name: cardToken
type: String
- name: amount
type: Decimal
response:
fields:
- name: chargeId
type: String
- name: status
type: String
domain:
returnType: ChargeResult
fields:
- name: id
type: UUID
source: chargeId
- name: status
type: String
source: status
- name: refundPayment
method: POST
path: /v1/charges/{chargeId}/refund
Campos del generador por operación: name, method, path, request.fields[], response.fields[], domain.returnType, domain.fields[]. El campo direction no es leído por el generador en la generación del adaptador (es solo documentación de diseño).
Tipos wire-format en request.fields[].type / response.fields[].type: String, Integer, Long, Boolean, Decimal (→ BigDecimal), Instant, UUID (→ String en DTO, java.util.UUID en domain record).
direction: inbound — Usar cuando el sistema externo llama a nuestra API (webhooks, callbacks).
Ejemplos: un payment gateway envía un callback POST con el resultado del pago; un proveedor de
notificaciones llama de vuelta para confirmar entrega. En este caso, el generador no produce
un adaptador saliente — el endpoint receptor se diseña en el OpenAPI del BC que maneja el callback
y el handler táctico en su UC correspondiente. Declarar direction: inbound en la operación es
documentación de diseño que aclara quién inicia la llamada, pero no cambia la generación de código.
externalSystems[].schemas — tipos compuestos reutilizables para APIs complejas
Usar cuando la API externa envía o recibe objetos anidados complejos (no solo campos escalares).
Sin schemas, cada campo del request/response de las operaciones debe ser un escalar —
si la API real tiene objetos anidados, el diseñador tendría que aplanar la estructura, perdiendo
la correspondencia con el contrato real del sistema externo.
Cuándo usar schemas vs campos escalares inline:
| Escenario | Usar schemas | Usar campos inline |
|---|
La API externa tiene objetos anidados (ej: address.street, address.city) | ✅ | ❌ |
| El mismo tipo complejo aparece en múltiples operaciones del externo | ✅ | ❌ |
Todos los campos de request/response son escalares simples | ❌ | ✅ |
| Un solo objeto anidado, en una sola operación | Opcional | ✅ si es simple |
Cómo declarar schemas:
externalSystems:
- name: payment-gateway
description: Third-party payment processor
type: payment-gateway
schemas:
ChargeRequest:
- name: cardToken
type: String
optional: false
- name: amount
type: Decimal
optional: false
- name: currency
type: String
optional: false
ChargeResponse:
- name: chargeId
type: String
optional: false
- name: status
type: String
optional: false
- name: failureReason
type: String
optional: true
LineItem:
- name: productId
type: String
optional: false
- name: quantity
type: Integer
optional: false
- name: unitPrice
type: Decimal
optional: false
OrderSummary:
- name: orderId
type: String
optional: false
- name: items
type: List<LineItem>
optional: false
operations:
- name: chargePayment
method: POST
path: /v1/charges
request:
fields:
- name: charge
type: ChargeRequest
response:
fields:
- name: result
type: ChargeResponse
Reglas de schemas:
- Nombres en PascalCase — generan
{Name}Dto.java en adapters/{ext}/dtos/
- Los schemas son locales al sistema externo — no se comparten entre distintos
externalSystems
- Un campo puede referenciar otro schema del mismo externo:
type: OtroSchema o type: List<OtroSchema>
- Referencias circulares (
A referencia B que referencia A) generan INT-022 bloqueante
- Schema declarado pero no referenciado en ninguna operación → genera
INT-023 (warn, no bloqueante)
- Tipos permitidos en campos de schema:
| Tipo en YAML | Java generado | Notas |
|---|
String | String | — |
Integer | Integer | — |
Long | Long | — |
Boolean | Boolean | — |
Decimal | BigDecimal | — |
Instant | Instant | — |
UUID | String (DTO) / java.util.UUID (domain record) | — |
NombreSchema | {NombreSchema}Dto | Referencia a schema del mismo externo |
List<String> | List<String> | — |
List<NombreSchema> | List<{NombreSchema}Dto> | Lista de objetos del schema referenciado |
Qué genera el generador con schemas:
- Un Java record
{SchemaName}Dto.java por cada clave del schemas map
- Los campos con
optional: true se mapean a tipos @Nullable en el DTO generado
- El
AclMapper traduce {SchemaName}Dto → tipo de dominio según el bloque domain de cada operación
infrastructure.reliability — patrón outbox y consumer idempotency
infrastructure:
reliability:
outbox: true
outboxRetentionDays: 7
consumerIdempotency: true
processedEventRetentionDays: 14
Cuándo activar outbox: true:
- Hay al menos una integración
channel: message-broker.
- El sistema requiere garantía at-least-once de entrega.
- Activar siempre que existan
sagas[] — sin outbox, una falla entre commit y
publish puede romper la cadena del saga.
outboxRetentionDays (entero ≥ 1, opcional pero recomendado en producción):
- Sin este campo, la tabla
outbox_event crece indefinidamente. El generador NO produce
ningún mecanismo de purga.
- Valor orientativo: 7 días es suficiente — los mensajes se publican en segundos y no
necesitan permanecer en la tabla más que unos pocos días como margen.
- Activar siempre que
outbox: true y el sistema vaya a entornos de producción.
Cuándo activar consumerIdempotency: true:
- Hay UCs disparados por evento (
trigger.kind: event en algún BC).
- Activar siempre que existan
sagas[] — un redelivery del mismo evento no debe
ejecutar el paso dos veces.
processedEventRetentionDays (entero ≥ 1, opcional pero recomendado en producción):
- Sin este campo, la tabla
processed_event crece indefinidamente. El generador NO produce
ningún mecanismo de purga.
- El valor debe superar el máximo tiempo de redelivery del broker para que la guardia
siga funcionando durante una redelivery tardía. Valor orientativo: 14 días para RabbitMQ;
para Kafka ajustar al
retention.ms del topic.
- Activar siempre que
consumerIdempotency: true y el sistema vaya a producción.
⚠️ Limitación crítica de consumerIdempotency: true (informar al equipo de Fase 2 táctico):
Si un use case falla después de que la guardia registra el eventId (con REQUIRES_NEW),
la fila en processed_event persiste aunque el use case no completó. En el siguiente redelivery,
la guardia descarta el mensaje — el use case nunca se reintenta. Los fallos deben
manejarse dentro del use case (retry interno, compensación) — no vía redelivery del broker.
infrastructure.authServer: true — Activar cuando el sistema usa JWT
infrastructure:
authServer: true
Cuándo declarar authServer: true — aplica si cualquiera de estas condiciones:
- Al menos un UC del sistema declara
authorization (rolesAnyOf, permissionsAnyOf, scopesAnyOf, ownership)
- Al menos un endpoint no es completamente público (accesible sin token válido)
- El sistema tiene actores distintos con niveles de acceso diferenciados (customer vs admin vs system)
Qué genera el generador con este flag activado:
| Artefacto generado | Ubicación | Propósito |
|---|
SecurityConfig.java | shared/infrastructure/security/ | Configuración JWT resource server: rutas protegidas vs permitAll() |
SecurityContextUtil.java | shared/infrastructure/security/ | Utilidad para extraer claims del JWT en runtime |
auth-server.yaml | resources/config/ ×4 entornos | URLs del servidor de auth por entorno (dev/test/staging/prod) |
Consecuencias de omitir authServer: true cuando el sistema sí tiene autenticación:
- El generador no produce ningún artefacto de seguridad.
- Los UCs con
authorization en el YAML táctico generarán código de handler que llama a
SecurityContextHolder sin la configuración mínima del resource server — fallo en runtime.
- Los endpoints se generarán sin
@PreAuthorize — cualquier usuario puede acceder.
authServer: false / omitir — solo si el sistema es puramente interno (accedido solo
desde red privada, sin endpoints HTTP expuestos directamente a usuarios o sistemas externos
que requieran autenticación). En ese caso, todos los endpoints son accesibles sin JWT.
Proveedor concreto: Keycloak, Cognito, Auth0, etc. es decisión de Fase 2 (build
interactivo del generador) — no se declara en system.yaml.
infrastructure.integrations.defaults — Solo auth implementado (nivel 3 de fallback)
Implementación parcial: el resolver de auth (resilience-auth-resolver.js) sí lee
infrastructure.integrations.defaults.auth — actúa como tercer nivel de fallback cuando
ni bc.yaml outbound[].auth ni integrations[]/externalSystems[].auth están declarados.
infrastructure.integrations.defaults.resilience NO se lee — el resolver de resiliencia
no implementa este nivel de fallback. Para resilience, declarar individualmente en
cada integrations[] o externalSystems[].
Usar defaults.auth solo si la mayoría de integraciones comparten el mismo mecanismo
de autenticación y se quiere evitar repetirlo. No es el patrón más habitual.
Integraciones internas: auth y resilience por integración
integrations:
- from: orders
to: payments
pattern: customer-supplier
channel: http
contracts: [validatePayment]
auth:
type: bearer
valueProperty: orders.token
resilience:
circuitBreaker:
failureRateThreshold: 50
waitDurationInOpenState: 30s
retries:
maxAttempts: 3
waitDuration: 500ms
connectTimeoutMs: 5000
timeoutMs: 15000
- Precedencia BC→BC:
bc.yaml outbound[name=target].auth/resilience > system.yaml integrations[from=bc, to=target].auth/resilience > system.yaml infrastructure.integrations.defaults.auth.
- Precedencia externo (ACL):
bc.yaml outbound[name=target].auth/resilience > system.yaml externalSystems[name=target].auth/resilience > system.yaml infrastructure.integrations.defaults.auth. Para ACL, integrations[].auth/resilience no es leído — la resiliencia/auth del externo va en externalSystems[].
- INT-015 (validador bloqueante):
auth.type: oauth2-cc requiere tokenEndpoint + credentialKey. El skill ddd-design-validation lo verifica.
- Si una integración no declara
auth/resilience, el adaptador se genera sin anotaciones Resilience4j ni interceptor de auth.
auth.type: internal-jwt: el generador produce InternalJwtPropagator.java (emitido una sola vez, compartido entre todos los BC que lo usen) — un RequestInterceptor que extrae el JWT del SecurityContextHolder y lo propaga en el header Authorization: Bearer de cada llamada Feign saliente. Usar cuando la integración BC→BC debe fluir el token del usuario original a lo largo de toda la cadena de servicio.
Árbol de decisión para auth.type:
| Escenario | auth.type |
|---|
| Sistema externo con clave de API fija en header | api-key + valueProperty (+ header si distinto de X-Api-Key) |
| Sistema externo con Bearer token estático (sin renovación) | bearer + valueProperty |
| Sistema externo con OAuth2 M2M (token de corta vida, renovación automática) | oauth2-cc + tokenEndpoint + credentialKey |
| Sistema externo que exige TLS mutuo (cliente presenta certificado) | mTLS (sin campos adicionales) |
| BC→BC donde el JWT del usuario original debe propagarse en la cadena | internal-jwt (sin campos adicionales) |
| Integración interna sin requisito de auth adicional (red privada) | none o omitir el bloque auth |
oauth2-cc tiene impacto en infraestructura: genera oauth2.yaml ×4 entornos + starter-oauth2-client en build.gradle.
mTLS tiene impacto en infraestructura: genera mtls.yaml ×4 entornos. Declarar estos tipos requiere coordinar con el equipo de infra.
3.2 system-spec.md
Para cada BC, escribe una sección con esta estructura exacta:
## BC: [Nombre]
### Propósito
[Una frase clara]
### Responsabilidades
[Lista de lo que hace]
### No Responsabilidades
[Lista de lo que NO hace — límites explícitos]
### Lenguaje Ubícuo
| Término | Definición en este BC |
### Agregados Principales
| Agregado | Root | Entidades internas |
### Dependencias Externas
[Sistemas externos con los que se integra, o "Ninguna"]
La sección "No Responsabilidades" es tan importante como las responsabilidades.
Previene que el BC absorba lógica ajena durante el desarrollo.
Incluye al final un Mapa de Integraciones — Resumen en formato de texto con flechas
que muestre el flujo completo de un vistazo.
3.3 system-diagram.mmd
Usa siempre C4 Contenedores (L2). Estructura obligatoria:
C4Container
title [Nombre del Sistema] — C4 Contenedores (L2)
Person(...) → actores humanos
System_Ext(...) → sistemas externos
Boundary(b0, "...") { → límite del sistema
Container(...) → un Container por BC, con tipo y propósito
}
Rel(actor, bc, "acción")
Rel(bc1, bc2, "contrato", "Sync / HTTP")
Rel(bc3, bc4, "evento", "Event / Message Broker")
Rel(bc, ext, "contrato", "ACL / HTTPS")
%% ── Conexiones HTTP → azul ──────────────────────────────────
UpdateRelStyle(bc1, bc2, $lineColor="royalblue", $textColor="royalblue")
%% ── Conexiones por evento → naranja ─────────────────────────
UpdateRelStyle(bc3, bc4, $lineColor="orange", $textColor="darkorange")
Convenciones de color obligatorias — aplícalas sin excepción:
- El label de cada
Container incluye el tipo: Core, Supporting, Generic
- Las relaciones HTTP (
"Sync / HTTP") → azul: UpdateRelStyle(from, to, $lineColor="royalblue", $textColor="royalblue")
- Las relaciones por evento (
"Event / Message Broker") → naranja: UpdateRelStyle(from, to, $lineColor="orange", $textColor="darkorange")
- Las relaciones con externos (
"ACL / HTTPS") → sin UpdateRelStyle (color por defecto)
- Las relaciones de actores hacia BCs → sin
UpdateRelStyle (color por defecto)
- Agrupa las relaciones de actores primero, luego las de BCs entre sí (HTTP, luego eventos), luego las externas
- Añade todos los
UpdateRelStyle al final del archivo, agrupados por tipo con comentario %% ──:
%% ── Conexiones HTTP → azul ──────────────────────────────────
UpdateRelStyle(a, b, $lineColor="royalblue", $textColor="royalblue")
UpdateRelStyle(c, d, $lineColor="royalblue", $textColor="royalblue")
%% ── Conexiones por evento → naranja ─────────────────────────
UpdateRelStyle(e, f, $lineColor="orange", $textColor="darkorange")
UpdateRelStyle(g, h, $lineColor="orange", $textColor="darkorange")
3.4 AGENTS.md
Genera AGENTS.md en la raíz del proyecto. Es el punto de entrada de contexto
para cualquier agente de IA que trabaje en el repositorio en pasos futuros.
Salvaguarda obligatoria: este archivo es un artefacto generado para el proyecto de
usuario que está siendo diseñado. Si el repositorio actual es dsl-design-system o el
AGENTS.md existente documenta el framework DSL Design System, no lo sobrescribas sin
confirmación explícita del usuario. En ese caso, informa que el archivo raíz es
documentación del framework y ofrece continuar con los otros artefactos o reemplazarlo
solo si el usuario lo confirma.
Estructura obligatoria:
# AGENTS.md — Contexto del Sistema para Agentes de IA
> Este archivo es generado automáticamente en el Paso 1 — Diseño Estratégico.
> Proporciona el contexto necesario para que los agentes de IA entiendan el sistema
> antes de ejecutar cualquier tarea de diseño, generación de código o revisión.
## ¿Qué se está construyendo?
[Nombre del sistema] — [descripción del propósito de negocio en 2-3 oraciones]
## Modelo de Negocio
- **Tipo**: [marketplace / tienda propia / B2B / B2C / etc.]
- **Segmento**: [B2C / B2B / ambos]
- **Flujo principal de valor**: [descripción del flujo de una oración]
## Actores Principales
| Actor | Rol en el sistema |
|-------|------------------|
## Bounded Contexts
| BC | Tipo | Propósito |
|----|------|-----------|
## Glosario de Términos Clave
| Término | Definición |
|---------|------------|
[Incluye los términos más importantes del lenguaje ubícuo, priorizando los que
aparecen en múltiples BCs o que podrían ser ambiguos fuera de contexto]
## Integraciones con Sistemas Externos
| Sistema | Tipo de integración | BC responsable |
|---------|--------------------|----------------|
## Decisiones de Infraestructura (Paso 1)
- **Estrategia de deployment**: [valor]
- **Estilo arquitectónico**: [valor]
- **Base de datos**: [tipo: relational | document | key-value | graph] — [estrategia de aislamiento]
- **Message broker**: [requerido (true) / No aplica]
## Estado del Diseño
- **Paso completado**: Paso 1 — Diseño Estratégico
- **Fecha**: [fecha de generación]
- **Próximo paso**: Paso 2 — Diseño Táctico (seleccionar un BC para comenzar)
## Artefactos de Arquitectura
- `arch/system/system.yaml` — fuente de verdad estructurada
- `arch/system/system-spec.md` — especificación narrativa por BC
- `arch/system/system-diagram.mmd` — diagrama C4 Contenedores
Reglas para este artefacto:
- El glosario debe ser auto-suficiente: un agente sin contexto previo debe entender
los términos sin leer otros archivos
- Prioriza claridad sobre exhaustividad — 8-12 términos clave, no el ubícuo completo
- La sección "¿Qué se está construyendo?" debe responder en lenguaje de negocio, no técnico
- Si se sobreescribe en un paso posterior, conservar el historial en "Estado del Diseño"
3.5 CLAUDE.md
Genera CLAUDE.md en la raíz del proyecto. Es el contexto e instrucciones que
Claude Code carga al trabajar en el repositorio en pasos futuros. Mientras AGENTS.md
es el contexto genérico del sistema, CLAUDE.md orienta específicamente a Claude Code:
comandos clave, fuentes de verdad, agentes disponibles y convenciones de los YAML.
Salvaguarda obligatoria: este archivo es un artefacto generado para el proyecto de
usuario que se está diseñando. Si el repositorio actual es dsl-design-system o el
CLAUDE.md existente documenta el framework DSL Design System, no lo sobrescribas sin
confirmación explícita del usuario. Aplica exactamente la misma lógica que la salvaguarda
de la sección 3.4 para AGENTS.md: informa que el archivo raíz es documentación del
framework y ofrece continuar con los otros artefactos o reemplazarlo solo si el usuario
lo confirma.
Estructura obligatoria: usa la plantilla canónica definida en el agente
design-system (src/skills/design-system/SKILL.md, sección "Estructura obligatoria de
CLAUDE.md"). El archivo debe contener al menos: ## Proyecto, ## Comandos Clave,
## Fuentes de Verdad, ## Agentes Disponibles, ## Convenciones de Artefactos YAML,
## Bounded Contexts (tabla derivada de system.yaml) y ## Estado del Diseño.
Reglas para este artefacto:
- La tabla de
## Bounded Contexts debe listar exactamente los mismos BCs que
boundedContexts[] de system.yaml, con su tipo (Core/Supporting/Generic).
- Los
## Comandos Clave no deben referenciar tecnología concreta de Fase 2 (frameworks,
motores de BD) — solo los comandos del CLI dsl y del validador.
- Mantén
CLAUDE.md coherente con AGENTS.md y system.yaml: el nombre del sistema, los
BCs y el glosario deben coincidir entre los tres.
Fase 4: Creación de Archivos
Crea el directorio arch/system/ si no existe y genera los cinco archivos:
[raíz del proyecto]/
├── AGENTS.md
├── CLAUDE.md
└── arch/
└── system/
├── system.yaml
├── system-spec.md
└── system-diagram.mmd
Usa Write para archivos nuevos y Edit para modificar existentes. Si ya existen, confirma con el usuario antes
de sobreescribir — puede ser un diseño en progreso. Para AGENTS.md y CLAUDE.md, aplica además la
salvaguarda de las secciones 3.4 y 3.5: nunca reemplaces el AGENTS.md ni el CLAUDE.md documental de este repo
como efecto colateral de una prueba del agente diseñador.
Orden de creación recomendado: system.yaml → system-spec.md → system-diagram.mmd → AGENTS.md → CLAUDE.md
(AGENTS.md y CLAUDE.md al final porque consolidan información de los tres anteriores).
Fase 5: Resumen Post-Generación
Al finalizar, presenta al usuario:
- Lista de BCs identificados con su clasificación (Core/Supporting/Generic)
- Decisiones de diseño destacables — explica 2-3 decisiones no triviales
(ej: por qué Inventario publica hacia Catálogo y no al revés)
- Supuestos aplicados — si inferiste algo, menciónalo explícitamente
- Defaults de infraestructura aplicados — qué se asumió y por qué
- Artefactos generados — lista los 5 archivos creados con sus rutas (incluido
CLAUDE.md)
- Siguiente paso — ofrecer avanzar al Paso 2 con algún BC específico
Sé conciso. El resumen no es documentación — es orientación para la siguiente decisión.
Principios de Calidad del Diseño
Estos principios guían las decisiones cuando el contexto es ambiguo:
Tamaño de BCs: Si un BC candidato tiene más de 4-5 agregados, probablemente
esconde dos BCs. Si tiene menos de 1 agregado, probablemente es una entidad dentro
de otro BC.
Dirección de dependencias: El Core Domain no debe depender de BCs Supporting.
Los Supporting dependen del Core, no entre sí (si pueden evitarlo).
ACL en integraciones externas: Toda integración con un sistema externo debe
tener una ACL. Nunca el dominio interno debe conocer el modelo del sistema externo.
Eventos vs sincrónico: Si la respuesta inmediata es necesaria para continuar el
flujo → sincrónico (HTTP). Si el receptor puede procesar cuando pueda → evento.
Autoridad de datos en transacciones: Un BC que crea registros con valores monetarios
o cantidades críticas (precio de venta, monto a cobrar) debe leerlos del BC autoritativo
via integración sincrónica — nunca aceptarlos del request del cliente. El cliente envía
solo identificadores (IDs). Este principio previene fraude por manipulación de payload
(OWASP A04) y debe reflejarse como una integración customer-supplier / http declarada
en integrations[] (ver ddd-integration-audit §2.6 Paso G).
Monolito modular + hexagonal: El diseño es agnóstico a tecnología. Los puertos
(interfaces) son el dominio. Los adaptadores son infraestructura. Esta separación
permite extraer BCs como microservicios sin tocar el dominio.