@ronaldjdevfs/forge 1.3.0-beta → 1.3.1
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/README.md +1 -1
- package/package.json +1 -1
- package/skills/forge/SKILL.md +57 -128
- package/skills/forge/command/forge.md +59 -14
- package/skills/forge/reference/adr.md +242 -0
- package/skills/forge/reference/anti-corruption-layer.md +340 -0
- package/skills/forge/reference/api-design.md +7 -0
- package/skills/forge/reference/api-versioning.md +354 -0
- package/skills/forge/reference/architectural-depth-checklist.md +311 -0
- package/skills/forge/reference/architecture-template.md +41 -0
- package/skills/forge/reference/assay.md +6 -0
- package/skills/forge/reference/bounded-contexts.md +311 -0
- package/skills/forge/reference/chain.md +6 -0
- package/skills/forge/reference/cohesion-checklist.md +256 -0
- package/skills/forge/reference/cqrs.md +286 -0
- package/skills/forge/reference/data-patterns.md +6 -0
- package/skills/forge/reference/di-strategies.md +6 -0
- package/skills/forge/reference/errors.md +5 -0
- package/skills/forge/reference/events.md +8 -0
- package/skills/forge/reference/evolutionary-architecture.md +300 -0
- package/skills/forge/reference/forge.md +7 -0
- package/skills/forge/reference/hooks.md +6 -0
- package/skills/forge/reference/idempotency.md +283 -0
- package/skills/forge/reference/inscribe.md +5 -0
- package/skills/forge/reference/inspect.md +6 -0
- package/skills/forge/reference/modular-monolith.md +252 -0
- package/skills/forge/reference/observability.md +5 -0
- package/skills/forge/reference/quench.md +5 -0
- package/skills/forge/reference/relocate.md +6 -0
- package/skills/forge/reference/sagas.md +359 -0
- package/skills/forge/reference/security-patterns.md +6 -0
- package/skills/forge/reference/smelt.md +6 -0
- package/skills/forge/reference/temper.md +6 -0
- package/skills/forge/reference/testing-patterns.md +6 -0
- package/skills/forge/reference/transactional-outbox.md +311 -0
- package/skills/forge/scripts/architecture.mjs +10 -5
- package/skills/forge/scripts/assay.mjs +2 -2
- package/skills/forge/scripts/chain.mjs +31 -5
- package/skills/forge/scripts/context.mjs +24 -4
- package/skills/forge/scripts/detect.mjs +39 -30
- package/skills/forge/scripts/forge-boot.mjs +108 -0
- package/skills/forge/scripts/forge-config.mjs +182 -3
- package/skills/forge/scripts/forge-state.mjs +1 -1
- package/skills/forge/scripts/forgeSentinel-lib.mjs +2 -2
- package/skills/forge/scripts/forgeSentinel.mjs +2 -2
- package/skills/forge/scripts/forgeSmith.mjs +2 -2
- package/skills/forge/scripts/graph.mjs +65 -9
- package/skills/forge/scripts/hook.mjs +2 -2
- package/skills/forge/scripts/inspect.mjs +56 -48
- package/skills/forge/scripts/parse-imports.mjs +0 -2
- package/skills/forge/scripts/posttool.mjs +211 -17
- package/skills/forge/scripts/recommendation-engine.mjs +125 -0
- package/skills/forge/scripts/rollback.mjs +5 -3
- package/skills/forge/templates/feature/acl-gateway.ts.md +52 -0
- package/skills/forge/templates/feature/acl-repository.ts.md +36 -0
- package/skills/forge/templates/feature/acl-translator.ts.md +24 -0
- package/skills/forge/templates/feature/cqrs-query.ts.md +40 -0
- package/skills/forge/templates/feature/outbox-repository.ts.md +36 -0
- package/skills/forge/templates/feature/saga-orchestrator.ts.md +72 -0
- package/skills/forge/templates/platform/outbox-relayer.ts.md +80 -0
- package/skills/forge/tests/core.test.mjs +288 -4
- package/src/cli.js +26 -13
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Architectural Depth — Checklist de Referencias
|
|
2
|
+
|
|
3
|
+
Checklist de las 10 nuevas referencias estratégicas para Forge. Cada entrada define el alcance exacto, secciones obligatorias, relaciones con referencias existentes y criterio de completitud.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Estado actual
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
[x] 01 — bounded-contexts.md — DDD Estratégico
|
|
11
|
+
[x] 02 — modular-monolith.md — Estrategia de despliegue
|
|
12
|
+
[x] 03 — adr.md — Registro de decisiones
|
|
13
|
+
[x] 04 — anti-corruption-layer.md — Integración legacy
|
|
14
|
+
[x] 05 — evolutionary-architecture.md — Evolución arquitectónica
|
|
15
|
+
[x] 06 — cqrs.md — CQRS
|
|
16
|
+
[x] 07 — sagas.md — Transacciones distribuidas
|
|
17
|
+
[x] 08 — transactional-outbox.md — Fiabilidad de eventos
|
|
18
|
+
[x] 09 — idempotency.md — Idempotencia
|
|
19
|
+
[x] 10 — api-versioning.md — Evolución de contratos
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 01 — `bounded-contexts.md`
|
|
25
|
+
|
|
26
|
+
**Propósito:** Fundamentar la capa `features/` en DDD Estratégico. Sin bounded contexts, las features son sólo directorios.
|
|
27
|
+
|
|
28
|
+
**Depende de:** nada (fundacional)
|
|
29
|
+
**Es usado por:** `modular-monolith.md`, `anti-corruption-layer.md`, `cqrs.md`, `sagas.md`
|
|
30
|
+
|
|
31
|
+
### Secciones obligatorias
|
|
32
|
+
|
|
33
|
+
- [ ] **Fundamentos de DDD Estratégico**: dominio, subdominio (core/supporting/generic), bounded context
|
|
34
|
+
- [ ] **Ubiquitous Language**: por contexto, glosario compartido, conflictos de lenguaje
|
|
35
|
+
- [ ] **Context Mapping**: Partnership, Shared Kernel, Customer-Supplier, Conformist, Anti-Corruption Layer, Open-Host Service, Published Language, Separate Ways
|
|
36
|
+
- [ ] **Identificación de bounded contexts**: heurísticas (equipo, lenguaje, modelo, base de datos)
|
|
37
|
+
- [ ] **Mapeo visual**: diagrama de contexts con relaciones y flujos
|
|
38
|
+
- [ ] **Relación con el modelo de Forge**: cómo cada feature se corresponde con (parte de) un bounded context
|
|
39
|
+
- [ ] **Anti-patrones**: contextos gigantes (orphan core), contextos fantasma, contextos sin lenguaje
|
|
40
|
+
- [ ] **Ejemplo completo**: sistema de e-commerce con 4-5 bounded contexts mapeados
|
|
41
|
+
- [ ] **Conexión con reglas R8 y R9**: cómo los contextos prohíben acoplamiento directo y ciclos
|
|
42
|
+
|
|
43
|
+
### Criterio de completitud
|
|
44
|
+
|
|
45
|
+
Un lector puede tomar cualquier feature existente y determinar su bounded context, su relación con otros contexts, y si el mapeo actual viola algún patrón de integridad.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 02 — `modular-monolith.md`
|
|
50
|
+
|
|
51
|
+
**Propósito:** Proveer un marco de decisión para elegir entre monolith modular y microservicios, alineado con el modelo de 4 capas.
|
|
52
|
+
|
|
53
|
+
**Depende de:** `bounded-contexts.md`
|
|
54
|
+
**Es usado por:** `relocate.md`, `reforge.md`, `cast.md`
|
|
55
|
+
|
|
56
|
+
### Secciones obligatorias
|
|
57
|
+
|
|
58
|
+
- [ ] **Definición de modular monolith**: módulos con boundaries fuertes, mismo proceso, despliegue único
|
|
59
|
+
- [ ] **Espectro Monolith → Modular → Microservices**: continuo, no binario
|
|
60
|
+
- [ ] **Marco de decisión**: cohesión, acoplamiento, topología de equipo (Conway's Law), escalabilidad, deployment autonomy
|
|
61
|
+
- [ ] **Cuándo mantener monolith**: equipo pequeño, dominio cohesionado, latencia crítica, inicio incierto
|
|
62
|
+
- [ ] **Señales para partir**: equipo scaling, deployment bottleneck, boundaries maduros, different failure characteristics
|
|
63
|
+
- [ ] **Criterio de corte por capa**: qué puede vivir como servicio vs qué debe compartirse (shared, platform)
|
|
64
|
+
- [ ] **Integración con Forge**: cómo modelar módulos usando features existentes, qué reglas (R8) se relajan dentro del monolith
|
|
65
|
+
- [ ] **Transición controlada**: split de features sin reescritura (strangler fig aplicado a features)
|
|
66
|
+
- [ ] **Anti-patrones**: distributed monolith, premature splitting, shared database entre servicios, nano-services
|
|
67
|
+
- [ ] **Ejemplo**: monolith modular de SaaS facturación que eventualmente parte billing en servicio separado
|
|
68
|
+
|
|
69
|
+
### Criterio de completitud
|
|
70
|
+
|
|
71
|
+
Un equipo puede evaluar su arquitectura actual contra el marco de decisión y obtener una recomendación accionable sobre si partir o consolidar y por dónde empezar.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 03 — `adr.md`
|
|
76
|
+
|
|
77
|
+
**Propósito:** Capturar y preservar decisiones arquitectónicas como parte del workflow de Forge.
|
|
78
|
+
|
|
79
|
+
**Depende de:** nada
|
|
80
|
+
**Es usado por:** `reforge.md`, `cast.md`, `inscribe.md`, todos
|
|
81
|
+
|
|
82
|
+
### Secciones obligatorias
|
|
83
|
+
|
|
84
|
+
- [ ] **Formato ADR estándar**: Title, Status, Context, Decision, Consequences (plantilla)
|
|
85
|
+
- [ ] **Variantes**: ADR simple (5 secciones), ADR extendido (con alternatives, compliance), ADR ligero (1 párrafo)
|
|
86
|
+
- [ ] **Estados**: Proposed → Accepted / Deprecated / Superseded / Amended
|
|
87
|
+
- [ ] **Integración con `inscribe`**: anexar ADRs activos en ARCHITECTURE.md
|
|
88
|
+
- [ ] **Integración con `assay`**: las decisiones como insumo para el ensayo multi-persona
|
|
89
|
+
- [ ] **Cuándo escribir un ADR**: scoping, tecnología, patrón, estándar, cambio de regla, excepción
|
|
90
|
+
- [ ] **ADRs como fuente de verdad**: enlazar ADRs desde reglas de detect.mjs, desde inline ignores
|
|
91
|
+
- [ ] **Ejemplos**: ADRs reales del modelo Forge (ej. "usar capa Shared en vez de cross-feather imports", "adoptar Prisma como ORM")
|
|
92
|
+
- [ ] **Tooling**: script para crear, listar, cambiar estado de ADRs
|
|
93
|
+
- [ ] **Anti-patrones**: ADRs que nunca se leen, ADRs sin contexto, ADRs sin consecuencia, ADRs de frameworks
|
|
94
|
+
|
|
95
|
+
### Criterio de completitud
|
|
96
|
+
|
|
97
|
+
Un `forge inscribe` genera ARCHITECTURE.md con enlaces a ADRs activos. Un nuevo miembro del equipo puede entender las decisiones clave en 10 minutos.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 04 — `anti-corruption-layer.md`
|
|
102
|
+
|
|
103
|
+
**Propósito:** Aislar sistemas legacy o externos sin contaminar el modelo de dominio de Forge.
|
|
104
|
+
|
|
105
|
+
**Depende de:** `bounded-contexts.md`
|
|
106
|
+
**Es usado por:** `relocate.md`, `reforge.md`, `cast.md`
|
|
107
|
+
|
|
108
|
+
### Secciones obligatorias
|
|
109
|
+
|
|
110
|
+
- [ ] **Definición y propósito ACL**: traducir entre modelos, evitar corrupción del modelo de dominio
|
|
111
|
+
- [ ] **Estructura de una ACL**: adapters de entrada (traducen del externo al dominio), adapters de salida (traducen del dominio al externo)
|
|
112
|
+
- [ ] **Strangler Fig pattern**: migración incremental con ACL como fachada
|
|
113
|
+
- [ ] **Implementación en el modelo de Forge**: la ACL vive en `adapter/out/` de una feature y traduce entre `infra/` y el modelo de dominio
|
|
114
|
+
- [ ] **Mapeo de integraciones legacy**: cómo modelar sistemas externos como bounded contexts con ACL
|
|
115
|
+
- [ ] **Estrategias de traducción**: event-based (publicar/suscribir), service-based (llamadas sincrónicas), repository-based (datos compartidos)
|
|
116
|
+
- [ ] **Conexión con reglas R1 y R7**: cómo ACL permite feature → infra sin violar la regla (porque el adapter traduce)
|
|
117
|
+
- [ ] **Detección automática**: qué patrones en detect.mjs indican necesidad de ACL
|
|
118
|
+
- [ ] **Ejemplo**: feature de "Orders" migrando de legacy SQL a nuevo schema con ACL + Strangler Fig
|
|
119
|
+
- [ ] **Anti-patrones**: ACL que filtra sin traducir (leaky abstraction), ACL que muta el origen, ACL como pasamanos
|
|
120
|
+
|
|
121
|
+
### Criterio de completitud
|
|
122
|
+
|
|
123
|
+
Un desarrollador puede identificar cuándo necesita una ACL, modelarla dentro del feature correspondiente, y ejecutar la migración con `relocate` sin romper el sistema existente.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 05 — `evolutionary-architecture.md`
|
|
128
|
+
|
|
129
|
+
**Propósito:** Guiar la evolución continua de la arquitectura sin reescrituras, usando fitness functions.
|
|
130
|
+
|
|
131
|
+
**Depende de:** nada (fundacional)
|
|
132
|
+
**Es usado por:** `inspect.md`, `reforge.md`, `graph.md`, `quench.md`
|
|
133
|
+
|
|
134
|
+
### Secciones obligatorias
|
|
135
|
+
|
|
136
|
+
- [ ] **Definición**: arquitectura que evoluciona incrementalmente guiada por fitness functions
|
|
137
|
+
- [ ] **Fitness functions**: tests automatizados que validan características arquitectónicas (acoplamiento, modularidad, performance, seguridad)
|
|
138
|
+
- [ ] **Tipos de fitness functions**: estáticas (lint-level), dinámicas (runtime), periódicas (benchmark), trigger-based (CI)
|
|
139
|
+
- [ ] **Implementación en Forge**: las reglas R1-R9 como fitness functions gobernadas por detect.mjs
|
|
140
|
+
- [ ] **Fitness functions custom**: cómo el usuario define sus propias funciones y se registran en registry/rules.mjs
|
|
141
|
+
- [ ] **Guía de cambio incremental**: smallest viable change, refactor patterns, scaffolding antes de feature completo
|
|
142
|
+
- [ ] **Evolución de boundaries**: cómo partir, fusionar o mover features sin reescribir
|
|
143
|
+
- [ ] **Integración con CI/CD**: fitness functions en pipeline, gate de deployment, alertas de regresión
|
|
144
|
+
- [ ] **Ejemplo**: fitness function "no feature importa infra" evolucionando a "ningún módulo importa otro módulo sin interfaz"
|
|
145
|
+
- [ ] **Anti-patrones**: big-bang rewrite, frozen architecture, analysis paralysis, chasing tech debt sin métrica
|
|
146
|
+
|
|
147
|
+
### Criterio de completitud
|
|
148
|
+
|
|
149
|
+
Un equipo puede añadir fitness functions personalizadas, integrarlas en su pipeline, y medir la salud arquitectónica en cada PR sin intervención manual.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 06 — `cqrs.md`
|
|
154
|
+
|
|
155
|
+
**Propósito:** Modelar separación de commands y queries dentro de features con demandas asimétricas.
|
|
156
|
+
|
|
157
|
+
**Depende de:** `bounded-contexts.md`
|
|
158
|
+
**Es usado por:** `data-patterns.md`, `events.md`, `sagas.md`, `cast.md`
|
|
159
|
+
|
|
160
|
+
### Secciones obligatorias
|
|
161
|
+
|
|
162
|
+
- [ ] **Fundamentos**: Command (escritura, efecto secundario, validación) vs Query (lectura, proyección, sin efectos)
|
|
163
|
+
- [ ] **Cuándo aplicar CQRS**: modelos de lectura/escritura divergentes, escalabilidad asimétrica, equipos separados, event sourcing
|
|
164
|
+
- [ ] **Implementación en el modelo de Forge**: command → use-case, query → repository o query service separado
|
|
165
|
+
- [ ] **Read models**: proyecciones desnormalizadas, tablas de lectura, caché de queries
|
|
166
|
+
- [ ] **CQRS parcial (sin event sourcing)**: commands y queries separados en la aplicación, misma BD
|
|
167
|
+
- [ ] **CQRS completo**: read model separado (tabla, BD, cache), eventual consistency
|
|
168
|
+
- [ ] **Materialized views / Projections**: cómo mantener read models actualizados
|
|
169
|
+
- [ ] **Separación de interfaces**: ICommandBus, IQueryBus como contratos en shared/
|
|
170
|
+
- [ ] **Conexión con reglas**: CQRS no viola ninguna regla de Forge porque commands y queries residen dentro del mismo feature
|
|
171
|
+
- [ ] **Anti-patrones**: CQRS everywhere (para CRUD simple), query leak (lógica de negocio en read model), eventual consistency ignorada
|
|
172
|
+
- [ ] **Ejemplo**: feature "Analytics" con CQRS parcial + read model en Redis via infra/redis
|
|
173
|
+
|
|
174
|
+
### Criterio de completitud
|
|
175
|
+
|
|
176
|
+
Un feature complejo con demands asimétricas puede modelarse con CQRS dentro de la estructura de Forge sin violar reglas y sin over-engineering.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 07 — `sagas.md`
|
|
181
|
+
|
|
182
|
+
**Propósito:** Coordinar transacciones multi-feature sin violar la regla R8 (no acoplamiento directo entre features).
|
|
183
|
+
|
|
184
|
+
**Depende de:** `bounded-contexts.md`, `events.md`
|
|
185
|
+
**Es usado por:** `cast.md`, `reforge.md`, `events.md`
|
|
186
|
+
|
|
187
|
+
### Secciones obligatorias
|
|
188
|
+
|
|
189
|
+
- [ ] **Problema**: transacciones que cruzan bounded contexts sin ACID distribuido
|
|
190
|
+
- [ ] **Definición de Saga**: secuencia de transacciones locales con compensación
|
|
191
|
+
- [ ] **Coreografía (Choreography)**: cada participante publica/escucha eventos, decisión descentralizada
|
|
192
|
+
- [ ] **Orquestación (Orchestration)**: coordinador central que instruye a los participantes
|
|
193
|
+
- [ ] **Compensación**: transacciones reversibles, acciones compensatorias, consistencia eventual
|
|
194
|
+
- [ ] **Manejo de fallos**: retry con backoff, dead letter queue, fallback humano, saga log
|
|
195
|
+
- [ ] **Implementación en el modelo de Forge**: saga orchestrator como feature independiente (ej. "checkout-saga"), saga participantes usan eventos de dominio + adapters
|
|
196
|
+
- [ ] **Conexión con reglas R8 y R5**: cómo las sagas coordinan features sin importarlas directamente, eventos como contrato en shared/
|
|
197
|
+
- [ ] **Testing de sagas**: unit (participante individual), integration (flujo completo con mock), resilience (fallos y compensaciones)
|
|
198
|
+
- [ ] **Anti-patrones**: saga sin compensación (irreversible), orchestrator con lógica de negocio, coreografía sin trazabilidad, timeout único
|
|
199
|
+
- [ ] **Ejemplo**: saga de checkout (Inventory → Payment → Shipping) con orquestación y compensación por fallo de pago
|
|
200
|
+
|
|
201
|
+
### Criterio de completitud
|
|
202
|
+
|
|
203
|
+
Un desarrollador puede modelar un flujo multi-feature usando sagas sin violar R8, con compensaciones claras, testing cubierto y trazabilidad.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 08 — `transactional-outbox.md`
|
|
208
|
+
|
|
209
|
+
**Propósito:** Garantizar entrega confiable de eventos sin exponer inconsistencias transaccionales.
|
|
210
|
+
|
|
211
|
+
**Depende de:** `events.md`
|
|
212
|
+
**Es usado por:** `sagas.md`, `cqrs.md`, `events.md`
|
|
213
|
+
|
|
214
|
+
### Secciones obligatorias
|
|
215
|
+
|
|
216
|
+
- [ ] **Problema**: dual-write (escribir en BD + publicar evento) atómico sin 2PC
|
|
217
|
+
- [ ] **Patrón Outbox**: escribir evento en tabla outbox dentro de la misma transacción que la operación de negocio
|
|
218
|
+
- [ ] **Outbox processor (relayer)**: proceso que lee la tabla outbox y publica eventos al message broker
|
|
219
|
+
- [ ] **Garantías**: at-least-once delivery, exactly-once processing con idempotencia
|
|
220
|
+
- [ ] **Implementaciones**: poll-based (relayer periódico), log-based (CDC con Debezium), hybrid
|
|
221
|
+
- [ ] **Integración con el modelo de Forge**: outbox en infra/prisma o infra/mongodb, processor como script/scheduler en platform/scheduler
|
|
222
|
+
- [ ] **Manejo de fallos**: retry con exponential backoff, poison messages, dead letter queue, alertas de outbox stuck
|
|
223
|
+
- [ ] **Idempotencia en consumidores**: deduplicación por event ID, idempotency key
|
|
224
|
+
- [ ] **Conexión con reglas**: outbox es infra que feature escribe mediante su adapter, sin violar R1
|
|
225
|
+
- [ ] **Anti-patrones**: outbox sin cleanup (tabla infinita), processor sin límite de reintentos, eventos sin idempotencia
|
|
226
|
+
- [ ] **Ejemplo**: feature "Orders" escribe pedido + outbox event en misma transacción Prisma → processor publica a RabbitMQ → "Payments" consume
|
|
227
|
+
|
|
228
|
+
### Criterio de completitud
|
|
229
|
+
|
|
230
|
+
Un feature que publica eventos puede implementar outbox pattern siguiendo el template de Forge, garantizando at-least-once delivery sin riesgo de inconsistencias.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 09 — `idempotency.md`
|
|
235
|
+
|
|
236
|
+
**Propósito:** Garantizar operaciones seguras para retry en APIs, eventos y procesos asíncronos.
|
|
237
|
+
|
|
238
|
+
**Depende de:** `api-design.md`
|
|
239
|
+
**Es usado por:** `api-design.md`, `events.md`, `sagas.md`, `cast.md`
|
|
240
|
+
|
|
241
|
+
### Secciones obligatorias
|
|
242
|
+
|
|
243
|
+
- [ ] **Definición**: propiedad de una operación que puede aplicarse múltiples veces sin efecto secundario adicional
|
|
244
|
+
- [ ] **Tipos de idempotencia**: natural (GET), por clave (idempotency key), por semántica (last-write-wins)
|
|
245
|
+
- [ ] **Idempotency keys en APIs**: cabecera Idempotency-Key, almacenamiento en BD/cache, deduplicación, respuesta en caché
|
|
246
|
+
- [ ] **Idempotencia en eventos**: event ID como clave, deduplicación en consumidor, exactly-once semantics
|
|
247
|
+
- [ ] **Implementación en el modelo de Forge**: middleware en platform/http, repository en infra/redis, contract en shared/contracts
|
|
248
|
+
- [ ] **Idempotencia en sagas**: cómo cada paso de saga debe ser idempotente para retry seguro
|
|
249
|
+
- [ ] **Manejo de expiración**: TTL de claves de idempotencia, cleanup, conflictos de clave
|
|
250
|
+
- [ ] **Testing de idempotencia**: enviar misma request N veces, verificar resultado único
|
|
251
|
+
- [ ] **Conexión con reglas**: idempotency middleware es platform, repositorio de claves es infra, contracts son shared
|
|
252
|
+
- [ ] **Anti-patrones**: idempotency sin expiración, claves generadas por el servidor, idempotencia en GET, mutex como idempotencia
|
|
253
|
+
- [ ] **Ejemplo**: POST /payments con Idempotency-Key, key almacenada en Redis, respuesta en caché, consumidor de eventos con deduplicación
|
|
254
|
+
|
|
255
|
+
### Criterio de completitud
|
|
256
|
+
|
|
257
|
+
Cada API de mutación en el feature expone idempotency keys. Cada consumidor de eventos maneja deduplicación. Retry es seguro en toda la cadena.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 10 — `api-versioning.md`
|
|
262
|
+
|
|
263
|
+
**Propósito:** Evolucionar contratos de API sin romper clientes existentes.
|
|
264
|
+
|
|
265
|
+
**Depende de:** `api-design.md`
|
|
266
|
+
**Es usado por:** `api-design.md`, `reforge.md`, `cast.md`
|
|
267
|
+
|
|
268
|
+
### Secciones obligatorias
|
|
269
|
+
|
|
270
|
+
- [ ] **Estrategias de versionado**: URL path (/v1/), header (Accept: application/vnd.api+json;version=1), content negotiation, query param
|
|
271
|
+
- [ ] **Compatibilidad**: backward compatible (additive changes), breaking changes (removal, rename, type change, required→optional)
|
|
272
|
+
- [ ] **Evolución de OpenAPI**: spec versionada, changelog automático, diff entre versiones
|
|
273
|
+
- [ ] **Versionado en el modelo de Forge**: controllers versionados por feature (features/users/adapters/in/http/v1/, v2/), routes con prefijo
|
|
274
|
+
- [ ] **Deprecación**: cabeceras Sunset, Deprecation, Retirement policy, migración de clientes
|
|
275
|
+
- [ ] **Internal vs Public API**: versionado estricto para pública, semver para interna
|
|
276
|
+
- [ ] **Integration testing multi-versión**: tests que corren contra v1 y v2 simultáneamente
|
|
277
|
+
- [ ] **Conexión con reglas**: ningún controller versionado debe violar R0 (cero lógica de negocio). La lógica vive en use cases
|
|
278
|
+
- [ ] **Anti-patrones**: versionado por "fecha" sin estabilidad, mantener N versiones sin política de muerte, versionado de toda la API en vez de por endpoint
|
|
279
|
+
- [ ] **Ejemplo**: feature "Users" migrando de v1 a v2 con cambio de modelo, controllers separados, deprecación gradual
|
|
280
|
+
|
|
281
|
+
### Criterio de completitud
|
|
282
|
+
|
|
283
|
+
Un feature puede evolucionar su API de forma segura, con versionado explícito, deprecación controlada, tests multi-versión, y sin tocar la lógica de negocio.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Integración en SKILL.md
|
|
288
|
+
|
|
289
|
+
- [x] Agregar las 10 referencias a la tabla **Module Index** en SKILL.md
|
|
290
|
+
- [x] Agregar entradas de **Command Routing** para los nuevos temas (lenguaje natural → referencia)
|
|
291
|
+
- [ ] Verificar que las referencias existentes que mencionan temas ahora cubiertos (events.md → sagas + outbox, data-patterns.md → CQRS) hagan `Ver: reference/<nueva>.md`
|
|
292
|
+
|
|
293
|
+
## Templates
|
|
294
|
+
|
|
295
|
+
- [x] Evaluar si `templates/feature/` necesita nuevos templates (saga orchestrator, outbox processor, ACL adapter, CQRS query service)
|
|
296
|
+
- [x] saga-orchestrator.ts.md — orchestrator con compensaciones
|
|
297
|
+
- [x] cqrs-query.ts.md — query service para lecturas separadas
|
|
298
|
+
- [x] acl-repository.ts.md — ACL que implementa repositorio de dominio
|
|
299
|
+
- [x] acl-translator.ts.md — traducción entre DTO externo y entidad de dominio
|
|
300
|
+
- [x] acl-gateway.ts.md — comunicación con sistema externo (HTTP)
|
|
301
|
+
- [x] outbox-repository.ts.md — repositorio de outbox integrado en UnitOfWork
|
|
302
|
+
- [x] outbox-relayer.ts.md — relayer en platform/scheduler
|
|
303
|
+
- [x] domain-event.ts.md — clase base DomainEvent con eventId para deduplicación
|
|
304
|
+
- [ ] Evaluar si `templates/shared/` necesita contratos de idempotencia o de eventos de integración
|
|
305
|
+
|
|
306
|
+
## Testing
|
|
307
|
+
|
|
308
|
+
- [x] transactional-outbox pattern — 5 tests (entry lifecycle, retry policy, DLQ, required fields, pending detection)
|
|
309
|
+
- [x] idempotency pattern — 5 tests (UUID validation, cached response, separate keys, TTL expiry, method filtering)
|
|
310
|
+
- [x] anti-corruption-layer pattern — 5 tests (external→domain mapping, domain→external mapping, null handling, 404 handling, delegation order)
|
|
311
|
+
- [ ] Prioridad futura: ADR workflow, evolutionary architecture fitness functions
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Architecture State
|
|
2
|
+
|
|
3
|
+
- Project Name: <name>
|
|
4
|
+
- Framework: <detectado>
|
|
5
|
+
- Runtime: <detectado>
|
|
6
|
+
- Database: <detectado>
|
|
7
|
+
- ORM: <detectado>
|
|
8
|
+
- DI Strategy: <detectado>
|
|
9
|
+
- Profile: <detectado>
|
|
10
|
+
- Architecture: hexagonal-feature (Platform + Features + Shared + Infra)
|
|
11
|
+
- Last Audit: <fecha> (score: <puntaje>)
|
|
12
|
+
|
|
13
|
+
## Platform
|
|
14
|
+
- platform/config/
|
|
15
|
+
- platform/server/
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
- features/users/
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
## Shared
|
|
23
|
+
- shared/errors/
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
## Infrastructure
|
|
27
|
+
- infra/prisma/
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
## Ownership
|
|
31
|
+
- Health: healthy | degraded | critical
|
|
32
|
+
- Score: 0-100
|
|
33
|
+
- Orphans: 0
|
|
34
|
+
- Duplicates: 0
|
|
35
|
+
- Misplaced: 0
|
|
36
|
+
|
|
37
|
+
## Architecture Graph
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
## Dependency Health
|
|
41
|
+
...
|
|
@@ -80,3 +80,9 @@ Se recomienda:
|
|
|
80
80
|
3. Priorizar acciones basado en las recomendaciones
|
|
81
81
|
4. Refactorizar con `reforge`, `temper`, o `smelt`
|
|
82
82
|
5. Repetir el ciclo
|
|
83
|
+
|
|
84
|
+
## Ver también
|
|
85
|
+
|
|
86
|
+
- `reference/inspect.md` — el reporte que alimenta el ensayo
|
|
87
|
+
- `reference/adr.md` — ADRs como insumo para las opiniones de cada persona
|
|
88
|
+
- `reference/principles.md` — principios contra los que assay contrasta las decisiones
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Bounded Contexts — DDD Estratégico
|
|
2
|
+
|
|
3
|
+
Las features de Forge se corresponden con bounded contexts. Sin esta correspondencia, `src/features/<name>/` son solo directoríos con código agrupado por nombre, no unidades con integridad de dominio.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Fundamentos de DDD Estratégico
|
|
8
|
+
|
|
9
|
+
### Dominio y Subdominios
|
|
10
|
+
|
|
11
|
+
El **dominio** es el área de actividad que el sistema modela. Se divide en tres tipos de **subdominio**:
|
|
12
|
+
|
|
13
|
+
| Tipo | Características | Ejemplo en e-commerce |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| **Core** | Ventaja competitiva, complejo, hecho en casa | Pricing engine, recomendaciones |
|
|
16
|
+
| **Supporting** | Necesario pero no diferenciador, puede externalizarse | Inventario, catálogo |
|
|
17
|
+
| **Generic** | Commodity, comprar o usar OSS | Auth, notificaciones, pagos |
|
|
18
|
+
|
|
19
|
+
Un **bounded context** es un límite explícito dentro del cual un modelo de dominio específico es consistente. Fuera del contexto, el mismo término puede tener significado distinto.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// En el contexto de "Catalog", Product tiene precio, descripción, imágenes
|
|
23
|
+
// En el contexto de "Inventory", Product tiene SKU, stock, warehouse location
|
|
24
|
+
// En el contexto de "Orders", Product tiene orderLine, quantity, status
|
|
25
|
+
// Son tres modelos distintos para el mismo concepto del mundo real
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Ubiquitous Language
|
|
29
|
+
|
|
30
|
+
Cada bounded context tiene su propio lenguaje ubicuo, compartido por el equipo de desarrollo y los expertos de negocio.
|
|
31
|
+
|
|
32
|
+
**Reglas del lenguaje ubicuo:**
|
|
33
|
+
- Los nombres de clases, métodos y módulos reflejan el lenguaje del negocio, no el lenguaje técnico
|
|
34
|
+
- No hay traducción entre "lo que el negocio dice" y "lo que el código llama"
|
|
35
|
+
- Si el negocio dice "Order" → la entidad se llama `OrderEntity`, no `OrderRecord` ni `OrderDoc`
|
|
36
|
+
- Si el negocio dice "cancelar pedido" → el caso de uso se llama `CancelOrderUseCase`, no `OrderDeleterService`
|
|
37
|
+
- Las discrepancias de lenguaje entre contexts son señales de límites válidos
|
|
38
|
+
|
|
39
|
+
**Conflicto de lenguaje como herramienta:** cuando dos personas del equipo usan la misma palabra con significado distinto (ej. "cliente" significa "usuario registrado" para marketing y "cuenta corporativa" para billing), hay dos bounded contexts esperando ser descubiertos.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Context Mapping
|
|
44
|
+
|
|
45
|
+
Cada bounded context se relaciona con otros mediante relaciones explícitas. Estos son los 8 patrones del Context Mapping:
|
|
46
|
+
|
|
47
|
+
### Partnership
|
|
48
|
+
|
|
49
|
+
Dos contexts cooperan para entregar un flujo. Si uno falla, el otro también.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
[Orders] ←→ [Inventory]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- Relación bidireccional
|
|
56
|
+
- Coordinación frecuente entre equipos
|
|
57
|
+
- Acoplamiento temporal tolerado
|
|
58
|
+
- Útil para flujos transaccionales críticos (checkout)
|
|
59
|
+
|
|
60
|
+
### Shared Kernel
|
|
61
|
+
|
|
62
|
+
Comparten un subconjunto pequeño y estable del modelo.
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
[Orders] ← kernel: Customer, Money → [Billing]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- El kernel compartido está en `src/shared/contracts/`
|
|
69
|
+
- Solo datos, no lógica de negocio
|
|
70
|
+
- El kernel se mantiene por acuerdo entre equipos
|
|
71
|
+
- Cambios requieren coordinación y tests
|
|
72
|
+
- Si crece demasiado, es señal de que los contexts deberían fusionarse
|
|
73
|
+
|
|
74
|
+
### Customer-Supplier
|
|
75
|
+
|
|
76
|
+
Un contexto upstream provee datos que el downstream consume. El upstream gana.
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
[CRM] → [Marketing] (CRM dicta el contrato)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- Upstream (supplier) define el contrato
|
|
83
|
+
- Downstream (customer) se adapta
|
|
84
|
+
- El downstream debe implementar una ACL si el upstream no cubre sus necesidades
|
|
85
|
+
- Relación unidireccional
|
|
86
|
+
|
|
87
|
+
### Conformist
|
|
88
|
+
|
|
89
|
+
El downstream acepta el modelo del upstream sin cuestionarlo.
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
[SAP] → [Reporting] (Reporting se adapta al modelo de SAP)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- Sin traducción: el downstream usa el modelo del upstream directamente
|
|
96
|
+
- Útil cuando el upstream es un sistema externo commodity
|
|
97
|
+
- Riesgo de corrupción del modelo de dominio downstream si el upstream cambia
|
|
98
|
+
|
|
99
|
+
### Anti-Corruption Layer (ACL)
|
|
100
|
+
|
|
101
|
+
El downstream protege su modelo con una capa de traducción.
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
[CRM Legacy] → [ACL] → [Orders]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- La ACL traduce del modelo legacy al modelo de dominio de Orders
|
|
108
|
+
- Ver `reference/anti-corruption-layer.md`
|
|
109
|
+
- Patrón obligatorio cuando se integra un sistema legacy o externo en un core domain
|
|
110
|
+
|
|
111
|
+
### Open-Host Service
|
|
112
|
+
|
|
113
|
+
El upstream expone un protocolo/shareable al que los downstreams se suscriben.
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
[Catalog] ── OHS (Published Language) ──→ [Search]
|
|
117
|
+
──→ [Recommendations]
|
|
118
|
+
──→ [Pricing]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- El upstream publica un Published Language (API, eventos, contratos compartidos)
|
|
122
|
+
- Múltiples downstreams consumen sin coordinar entre sí
|
|
123
|
+
- Es la relación ideal para la capa `adapter/out/` de una feature exponiendo eventos
|
|
124
|
+
|
|
125
|
+
### Published Language
|
|
126
|
+
|
|
127
|
+
El lenguaje compartido que el OHS usa. Puede ser:
|
|
128
|
+
- Contratos TypeScript en `src/shared/contracts/`
|
|
129
|
+
- Eventos de dominio con schema versionado
|
|
130
|
+
- OpenAPI spec como contrato HTTP
|
|
131
|
+
- Protobuf / Avro schemas
|
|
132
|
+
|
|
133
|
+
Los contratos publicados deben ser:
|
|
134
|
+
- Versionados (`src/shared/contracts/catalog/v1/`, `v2/`)
|
|
135
|
+
- Inmutables una vez publicados
|
|
136
|
+
- Documentados con ejemplos
|
|
137
|
+
- Validados con tests de compatibilidad
|
|
138
|
+
|
|
139
|
+
### Separate Ways
|
|
140
|
+
|
|
141
|
+
Dos contexts no tienen relación. Cada uno modela su solución independientemente.
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
[Notifications] [Analytics]
|
|
145
|
+
(no se hablan)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- Válido cuando no hay solapamiento funcional
|
|
149
|
+
- Forzado por R8 (no imports directos entre features): por defecto, toda feature que no comparte contratos está en Separate Ways con las demás
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Identificación de Bounded Contexts
|
|
154
|
+
|
|
155
|
+
### Heurísticas prácticas
|
|
156
|
+
|
|
157
|
+
| Señal | Pregunta guía |
|
|
158
|
+
|---|---|
|
|
159
|
+
| **Equipo** | ¿Otro equipo podría ser dueño de esto? |
|
|
160
|
+
| **Lenguaje** | ¿Usan las mismas palabras con el mismo significado? |
|
|
161
|
+
| **Modelo** | ¿La misma entidad tiene atributos o comportamientos distintos? |
|
|
162
|
+
| **Frecuencia de cambio** | ¿Una parte del sistema cambia a ritmo distinto que otra? |
|
|
163
|
+
| **Base de datos** | ¿Podría tener su propio schema o base de datos? |
|
|
164
|
+
| **Deploy** | ¿Podría deployarse independientemente? |
|
|
165
|
+
| **Fallo** | ¿Un fallo aquí no debería afectar a otras partes? |
|
|
166
|
+
|
|
167
|
+
### Regla práctica de Forge
|
|
168
|
+
|
|
169
|
+
Si puedes nombrar un directorio `src/features/<name>/` y describir qué hace sin usar términos de otra feature, tienes un bounded context candidato.
|
|
170
|
+
|
|
171
|
+
Si necesitas decir "esto es parte de X pero usa el modelo de Y" o "comparte la BD con Z", el context mapping está mal definido.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Mapeo Visual
|
|
176
|
+
|
|
177
|
+
Un diagrama de contextos muestra los bounded contexts como cajas y las relaciones como flechas etiquetadas.
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
┌──────────────────────────────────────────────────────┐
|
|
181
|
+
│ E-Commerce System │
|
|
182
|
+
│ │
|
|
183
|
+
│ ┌──────────┐ SK ┌──────────┐ OHS ┌──────────┐ │
|
|
184
|
+
│ │ Orders │◄────►│ Catalog ├────────►│ Search │ │
|
|
185
|
+
│ └────┬─────┘ └──────────┘ └──────────┘ │
|
|
186
|
+
│ │ │ │
|
|
187
|
+
│ │PS │PL │
|
|
188
|
+
│ ▼ ▼ │
|
|
189
|
+
│ ┌──────────┐ ┌──────────┐ │
|
|
190
|
+
│ │Inventory │ │ Pricing │ │
|
|
191
|
+
│ └──────────┘ └──────────┘ │
|
|
192
|
+
│ │ │
|
|
193
|
+
│ │CS │
|
|
194
|
+
│ ▼ │
|
|
195
|
+
│ ┌──────────┐ │
|
|
196
|
+
│ │Shipping │ │
|
|
197
|
+
│ └──────────┘ │
|
|
198
|
+
│ │
|
|
199
|
+
│ ┌──────────┐ SW ┌──────────┐ │
|
|
200
|
+
│ │ Auth │ │Analytics │ │
|
|
201
|
+
│ └──────────┘ └──────────┘ │
|
|
202
|
+
└────────────────────────────────────────────────────────┘
|
|
203
|
+
|
|
204
|
+
Leyenda:
|
|
205
|
+
SK = Shared Kernel
|
|
206
|
+
OHS = Open-Host Service (vía Published Language)
|
|
207
|
+
PS = Partnership
|
|
208
|
+
PL = Published Language (unidirectional OHS)
|
|
209
|
+
CS = Customer-Supplier
|
|
210
|
+
SW = Separate Ways
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Relación con el Modelo de Forge
|
|
216
|
+
|
|
217
|
+
Cada `src/features/<name>/` mapea a (parte de) un bounded context.
|
|
218
|
+
|
|
219
|
+
| Regla | Relación con bounded contexts |
|
|
220
|
+
|---|---|
|
|
221
|
+
| **R8** (no cross-feature imports) | Enforces Separate Ways entre contexts. Si dos features necesitan comunicarse, debe ser vía Published Language (contratos en shared/) o Partnership (interfaces inyectadas). |
|
|
222
|
+
| **R9** (no ciclos) | Los ciclos entre contexts indican que el context mapping está mal: dos contexts que se necesitan mutuamente deberían fusionarse o introducir un tercer contexto mediador. |
|
|
223
|
+
| **R2** (platform → feature) | Platform es un contexto genérico que sirve a todos. No debe invertirse. |
|
|
224
|
+
| **R4** (shared → infra) | Shared kernel debe ser puro. Si shared necesita infra, el kernel está contaminado. |
|
|
225
|
+
|
|
226
|
+
### La feature como bounded context implementado
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
src/features/orders/
|
|
230
|
+
domain/ ← Modelo del contexto Orders
|
|
231
|
+
entities/
|
|
232
|
+
events/
|
|
233
|
+
repositories/ ← Puertos
|
|
234
|
+
application/
|
|
235
|
+
use-cases/ ← Flujos del contexto Orders
|
|
236
|
+
mappers/ ← Traducción dentro del contexto
|
|
237
|
+
adapters/
|
|
238
|
+
in/http/ ← Entrada: Open-Host Service (API REST)
|
|
239
|
+
out/persistence/ ← Salida: repositorio concreto
|
|
240
|
+
out/events/ ← Salida: eventos publicados (Published Language)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Anti-patrones
|
|
246
|
+
|
|
247
|
+
| Anti-patrón | Problema | Solución |
|
|
248
|
+
|---|---|---|
|
|
249
|
+
| **Contexto gigante (Orphan Core)** | Un solo contexto contiene todo el core domain. No hay límites. | Dividir por subdominio. Si duele partir, empezar por los flujos que cambian a ritmo distinto. |
|
|
250
|
+
| **Contexto fantasma** | Un bounded context declarado que no tiene modelo propio. Solo llama APIs de otros contexts. | Fusionar con el contexto que realmente tiene el modelo o eliminarlo. |
|
|
251
|
+
| **Contexto sin lenguaje** | El código usa nombres técnicos (UserService, DataManager, TransactionHelper). No hay rastro del lenguaje del negocio. | Hacer event storming con el equipo de negocio. Renombrar todo para reflejar el lenguaje ubícuo. |
|
|
252
|
+
| **Shared Kernel gigante** | Los contratos compartidos crecen sin control porque es más fácil poner algo en shared que diseñar el límite. | Forzar revisión en cada PR de shared/contracts/. Shared kernel debe ser minimalista y estable. |
|
|
253
|
+
| **Contexto anémico** | Un contexto que solo tiene CRUD y getters/setters. Sin reglas de negocio ni invariantes. | Preguntar: ¿qué reglas de negocio existen aquí? Si la respuesta es "ninguna", probablemente el contexto debería ser un subdominio genérico resuelto con infraestructura (CRUD framework). |
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Ejemplo Completo
|
|
258
|
+
|
|
259
|
+
Sistema de e-commerce con 4 bounded contexts:
|
|
260
|
+
|
|
261
|
+
**Catalog** (Supporting)
|
|
262
|
+
- Modelo: `Product`, `Category`, `Price`
|
|
263
|
+
- Lenguaje: producto, categoría, precio de lista, variante
|
|
264
|
+
- Persistencia: PostgreSQL
|
|
265
|
+
- Relaciones: OHS → Search (Published Language), CS → Pricing (provee precios base)
|
|
266
|
+
|
|
267
|
+
**Orders** (Core)
|
|
268
|
+
- Modelo: `Order`, `OrderLine`, `Payment`, `Shipment`
|
|
269
|
+
- Lenguaje: pedido, línea, pago, envío, cancelación, reembolso
|
|
270
|
+
- Persistencia: PostgreSQL (propio schema)
|
|
271
|
+
- Relaciones: Partnership ↔ Inventory, CS → Shipping, consume eventos de Catalog (Published Language)
|
|
272
|
+
|
|
273
|
+
**Inventory** (Supporting)
|
|
274
|
+
- Modelo: `Stock`, `Warehouse`, `Movement`
|
|
275
|
+
- Lenguaje: stock, almacén, entrada, salida, reserva
|
|
276
|
+
- Persistencia: PostgreSQL
|
|
277
|
+
- Relaciones: Partnership ↔ Orders, CS → Shipping (provee peso/volumen)
|
|
278
|
+
|
|
279
|
+
**Search** (Generic, con Elasticsearch)
|
|
280
|
+
- Modelo: `SearchableProduct` (read model desnormalizado de Catalog)
|
|
281
|
+
- Lenguaje: búsqueda, filtro, índice, relevancia
|
|
282
|
+
- Persistencia: Elasticsearch
|
|
283
|
+
- Relaciones: consume OHS de Catalog
|
|
284
|
+
- No tiene relaciones de salida: es puramente un contexto de lectura
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
Decisiones arquitectónicas reflejadas:
|
|
288
|
+
- Catalog y Search están separados porque tienen distinta frecuencia de cambio y stack
|
|
289
|
+
- Orders e Inventory en Partnership porque el checkout necesita coordinación transaccional
|
|
290
|
+
- Catalog como OHS permite que Search, Pricing y Recommendations consuman sin acoplar
|
|
291
|
+
- No hay ACL porque ningún legacy está involucrado (todos los contexts son nuevos)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Conexión con Forge
|
|
297
|
+
|
|
298
|
+
| Comando | Acción |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `forge cast` | Crea una nueva feature que se corresponde con un nuevo bounded context o subdomino |
|
|
301
|
+
| `forge inspect` | Detecta violaciones de límites entre contexts (R8, R9) |
|
|
302
|
+
| `forge graph` | Visualiza los bounded contexts y sus relaciones como grafo arquitectónico |
|
|
303
|
+
| `forge relocate` | Migra código entre contexts o extrae un contexto de un monolito legacy |
|
|
304
|
+
| `forge assay` | Evalúa cualitativamente la integridad de los límites entre contexts |
|
|
305
|
+
|
|
306
|
+
## Ver también
|
|
307
|
+
|
|
308
|
+
- `reference/modular-monolith.md` — contexto como unidad del monolith
|
|
309
|
+
- `reference/anti-corruption-layer.md` — protección de límites entre contexts
|
|
310
|
+
- `reference/cqrs.md` — separación command/query dentro de un context
|
|
311
|
+
- `reference/sagas.md` — coordinación entre contexts
|