@ronaldjdevfs/forge 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +130 -8
  2. package/package.json +3 -3
  3. package/skills/forge/SKILL.md +86 -15
  4. package/skills/forge/profiles/express-drizzle.md +107 -0
  5. package/skills/forge/profiles/fastify-mongodb.md +103 -0
  6. package/skills/forge/profiles/fastify-prisma.md +81 -0
  7. package/skills/forge/profiles/nestjs-mongodb.md +92 -0
  8. package/skills/forge/profiles/nestjs-postgres.md +98 -0
  9. package/skills/forge/reference/api-design.md +62 -0
  10. package/skills/forge/reference/assay.md +82 -0
  11. package/skills/forge/reference/cast.md +81 -7
  12. package/skills/forge/reference/data-patterns.md +86 -0
  13. package/skills/forge/reference/di-strategies.md +50 -0
  14. package/skills/forge/reference/errors.md +65 -0
  15. package/skills/forge/reference/events.md +95 -0
  16. package/skills/forge/reference/help.md +40 -0
  17. package/skills/forge/reference/hooks.md +62 -0
  18. package/skills/forge/reference/observability.md +66 -0
  19. package/skills/forge/reference/patterns.md +52 -0
  20. package/skills/forge/reference/principles.md +6 -0
  21. package/skills/forge/reference/reforge.md +69 -5
  22. package/skills/forge/reference/relocate.md +15 -2
  23. package/skills/forge/reference/security-patterns.md +87 -0
  24. package/skills/forge/reference/testing-patterns.md +69 -0
  25. package/skills/forge/scripts/assay.mjs +481 -0
  26. package/skills/forge/scripts/context.mjs +147 -43
  27. package/skills/forge/scripts/detect.mjs +371 -22
  28. package/skills/forge/scripts/forge-api.mjs +373 -0
  29. package/skills/forge/scripts/forge-config.mjs +268 -0
  30. package/skills/forge/scripts/forge-signals.mjs +131 -0
  31. package/skills/forge/scripts/forge-state.mjs +97 -0
  32. package/skills/forge/scripts/formatter.mjs +133 -0
  33. package/skills/forge/scripts/graph.mjs +5 -21
  34. package/skills/forge/scripts/hook.mjs +250 -0
  35. package/skills/forge/scripts/inspect.mjs +171 -22
  36. package/skills/forge/scripts/parse-imports.mjs +249 -0
  37. package/skills/forge/scripts/pin.mjs +151 -0
  38. package/skills/forge/scripts/posttool.mjs +224 -0
  39. package/skills/forge/scripts/profile.mjs +124 -20
  40. package/skills/forge/scripts/registry/rules.mjs +344 -0
  41. package/skills/forge/scripts/rename.mjs +669 -0
  42. package/skills/forge/scripts/rollback.mjs +213 -0
  43. package/skills/forge/scripts/update.mjs +114 -0
  44. package/skills/forge/templates/feature/domain-error.ts.md +9 -0
  45. package/skills/forge/templates/feature/domain-event.ts.md +9 -0
  46. package/skills/forge/templates/feature/event-handler.ts.md +10 -0
  47. package/skills/forge/templates/feature/use-case.ts.md +10 -2
  48. package/skills/forge/tests/core.test.mjs +403 -0
@@ -0,0 +1,95 @@
1
+ # Events — Eventos de dominio, outbox, sagas
2
+
3
+ ## Principios
4
+
5
+ - Los eventos representan **hechos consumados** en el dominio (pasado simple).
6
+ - Se emiten desde el use case después de persistir, nunca antes.
7
+ - El event bus es infraestructura (platform/events/); el dominio solo define la interfaz.
8
+ - Los handlers están en `adapters/` (out) del feature que reacciona al evento.
9
+
10
+ ## Estructura
11
+
12
+ ```
13
+ features/<name>/
14
+ domain/
15
+ events/
16
+ UserCreated.event.ts
17
+ UserEmailChanged.event.ts
18
+ ```
19
+
20
+ ## Evento de dominio
21
+
22
+ ```ts
23
+ // features/users/domain/events/UserCreated.event.ts
24
+ export class UserCreatedEvent {
25
+ constructor(
26
+ public readonly userId: string,
27
+ public readonly email: string,
28
+ public readonly occurredAt: Date = new Date(),
29
+ ) {}
30
+ }
31
+ ```
32
+
33
+ ## Emisión desde use case
34
+
35
+ ```ts
36
+ // features/users/application/use-cases/CreateUser.uc.ts
37
+ export class CreateUserUseCase {
38
+ constructor(
39
+ private readonly userRepo: IUserRepository,
40
+ private readonly eventBus: IEventBus,
41
+ ) {}
42
+
43
+ async execute(dto: CreateUserDTO): Promise<UserEntity> {
44
+ const user = UserEntity.create(dto);
45
+ const saved = await this.userRepo.save(user);
46
+ this.eventBus.publish(new UserCreatedEvent(saved.id, saved.email));
47
+ return saved;
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## Event Bus
53
+
54
+ ```ts
55
+ // platform/events/EventBus.ts
56
+ export interface IEventBus {
57
+ publish(event: object): void;
58
+ subscribe<T>(eventType: new (...args: any[]) => T, handler: (event: T) => Promise<void>): void;
59
+ }
60
+ ```
61
+
62
+ ## Outbox Pattern
63
+
64
+ Para eventos que **deben** entregarse de forma confiable (ej: notificar a otro servicio).
65
+
66
+ 1. El use case persiste el evento en una tabla `outbox` dentro de la misma transacción de BD.
67
+ 2. Un worker independiente lee la outbox y publica los eventos al message broker.
68
+ 3. Elimina o marca como enviado tras confirmación del broker.
69
+
70
+ ```
71
+ features/<name>/adapters/out/persistence/
72
+ ├── User.repository.ts
73
+ └── Outbox.repository.ts
74
+ ```
75
+
76
+ ## Sagas / Process Managers
77
+
78
+ Para flujos multi-paso que abarcan múltiples features.
79
+
80
+ ```ts
81
+ // features/orders/application/sagas/CreateOrder.saga.ts
82
+ // 1. OrderCreated → PaymentRequired
83
+ // 2. PaymentConfirmed → InventoryReserved
84
+ // 3. InventoryReserved → OrderConfirmed
85
+ // 4. Si falla: compensar (rollback) cada paso
86
+ ```
87
+
88
+ ## Buenas prácticas
89
+
90
+ - Eventos en pasado (`UserCreated`, `EmailChanged`), nunca (`CreateUser`, `ChangeEmail`)
91
+ - Un evento por handler. Si un handler falla, no bloquea otros.
92
+ - Idempotencia en handlers: processar el mismo evento dos veces produce el mismo resultado.
93
+ - Eventos sin lógica: son datos, no comportamiento.
94
+ - Para integración entre features: el feature A emite evento, el feature B lo escucha. Nunca import directo.
95
+ - Outbox para garantía de entrega; in-memory event bus solo para tests o monolitos pequeños.
@@ -0,0 +1,40 @@
1
+ # forge — Ayuda
2
+
3
+ ## Uso
4
+ forge <comando> [flags]
5
+
6
+ ## Comandos
7
+
8
+ forge Inicializar proyecto (boot sequence completa)
9
+ cast Crear nuevo feature con estructura hexagonal
10
+ inspect Auditoría arquitectónica (110pts → 0-100)
11
+ relocate Migrar código legacy a features/platform/shared/infra
12
+ reforge Refactorizar arquitectura multi-capa
13
+ quench Validar reglas R1-R9 (--fix auto-corrige)
14
+ temper Endurecer inyección de dependencias
15
+ chain Grafo de dependencias multi-capa
16
+ graph Grafo arquitectónico con risk score
17
+ inscribe Generar/actualizar ARCHITECTURE.md
18
+ smelt Extraer código puro a shared/
19
+ assay Ensayo multi-persona (--persona=, --save)
20
+ nail Crear shortcut de navegación
21
+ unnail Eliminar shortcut de navegación
22
+ forge state Estado persistente post-auditoría
23
+ forge hook Git pre-commit hook
24
+ forge api Validación de contratos API
25
+ forge rollback Restauración de puntos de guardado
26
+ forge update Verificar actualizaciones
27
+
28
+ ## Flags
29
+
30
+ --fix Auto-corregir violaciones (quench)
31
+ --show-ignores Mostrar inline ignores (quench)
32
+ --persona=<id> Filtrar ensayo por persona (assay)
33
+ --save Persistir ensayo en .forge/assay/ (assay)
34
+ --json Salida JSON (assay, forge state)
35
+
36
+ ## Inline Ignores
37
+
38
+ // forge-ignore-next-line
39
+ // forge-ignore: R1
40
+ // forge-ignore: R1, R8
@@ -0,0 +1,62 @@
1
+ # Hook — Git pre-commit hook arquitectónico
2
+
3
+ ## Propósito
4
+
5
+ Validar automáticamente la arquitectura del proyecto antes de cada commit,
6
+ bloqueando commits que introduzcan violaciones CRITICAL o ERROR en los
7
+ archivos staged.
8
+
9
+ ## Uso
10
+
11
+ ```bash
12
+ # Instalar el hook pre-commit
13
+ forge hook install
14
+
15
+ # Ver estado
16
+ forge hook status
17
+
18
+ # Ignorar una regla específica
19
+ forge hook ignore R1
20
+
21
+ # Dejar de ignorar
22
+ forge hook unignore R1
23
+
24
+ # Listar reglas ignoradas
25
+ forge hook list-ignored
26
+
27
+ # Ejecutar validación manual sobre staged files
28
+ forge hook check
29
+
30
+ # Desinstalar
31
+ forge hook uninstall
32
+ ```
33
+
34
+ ## Comportamiento
35
+
36
+ El hook ejecuta `detect.mjs` sobre los archivos staged con extensión
37
+ `.ts`, `.js`, `.mjs`, `.tsx`, `.jsx` dentro de `src/`. Si encuentra
38
+ violaciones de severidad CRITICAL o ERROR que afecten a archivos staged:
39
+
40
+ 1. Muestra las violaciones con su severidad y fix sugerido
41
+ 2. Bloquea el commit (exit code 1)
42
+ 3. Sugiere cómo ignorar la regla si es necesario
43
+
44
+ El commit puede saltarse con `git commit --no-verify`.
45
+
46
+ ## Archivos de configuración
47
+
48
+ | Archivo | Propósito |
49
+ |---------|-----------|
50
+ | `.forge/hooks-ignore.json` | Lista de reglas ignoradas por el hook |
51
+ | `.git/hooks/pre-commit` | Script instalado por `forge hook install` |
52
+
53
+ ## Reglas ignoradas
54
+
55
+ Las reglas ignoradas se almacenan en `.forge/hooks-ignore.json`:
56
+
57
+ ```json
58
+ { "ignored": ["R1", "R7", "R9"] }
59
+ ```
60
+
61
+ Cuando una regla está ignorada, el hook no bloquea el commit por
62
+ violaciones de esa regla, aunque el detector sigue reportándolas.
@@ -0,0 +1,66 @@
1
+ # Observability — Logging, tracing, métricas, health checks
2
+
3
+ ## Principios
4
+
5
+ - Observabilidad es infraestructura, no dominio. Toda instrumentación está en `platform/` o `adapters/`.
6
+ - El dominio nunca escribe logs ni emite métricas directamente.
7
+ - Usar OpenTelemetry como estándar unificado.
8
+
9
+ ## Estructura recomendada
10
+
11
+ ```
12
+ src/platform/observability/
13
+ ├── Metrics.ts → Contadores, histogramas (Prometheus / OTel)
14
+ ├── Tracing.ts → Trazas distribuidas (OpenTelemetry)
15
+ ├── Health.ts → Health checks agregados
16
+ ├── Logger.service.ts → Logger estructurado (pino, winston)
17
+ └── Logger.config.ts → Niveles, formatos, transports
18
+ ```
19
+
20
+ ## Logging estructurado
21
+
22
+ ```ts
23
+ // platform/observability/Logger.service.ts
24
+ export class LoggerService {
25
+ info(msg: string, ctx?: Record<string, unknown>): void {
26
+ pino.info({ msg, ...ctx });
27
+ }
28
+ error(msg: string, err?: Error, ctx?: Record<string, unknown>): void {
29
+ pino.error({ msg, err: { message: err?.message, stack: err?.stack }, ...ctx });
30
+ }
31
+ }
32
+ ```
33
+
34
+ Inyectar en use cases solo si es estrictamente necesario (auditoría). Preferir middlewares de logging.
35
+
36
+ ## Health checks
37
+
38
+ ```ts
39
+ // platform/observability/Health.ts
40
+ export interface IHealthCheck {
41
+ name: string;
42
+ check(): Promise<{ status: "ok" | "degraded" | "down"; detail?: string }>;
43
+ }
44
+
45
+ // GET /health → { status: "ok", checks: [{ name: "db", status: "ok" }, ...] }
46
+ // GET /health/ready → readiness (dependencias listas)
47
+ // GET /health/live → liveness (proceso vivo)
48
+ ```
49
+
50
+ ## Métricas clave
51
+
52
+ | Métrica | Tipo | Descripción |
53
+ |---------|------|-------------|
54
+ | `http_requests_total` | Counter | Total requests por método, ruta, status |
55
+ | `http_request_duration_seconds` | Histogram | Latencia por ruta |
56
+ | `db_query_duration_seconds` | Histogram | Latencia de queries por repositorio |
57
+ | `feature_uc_execution_seconds` | Histogram | Duración de use cases por feature |
58
+
59
+ ## Buenas prácticas
60
+
61
+ - Correlation ID en cada request (inyectado en platform/http/)
62
+ - Logs en JSON siempre. Nivel info para flujo normal, debug para detalle, warn/error para anomalías.
63
+ - No loggear datos sensibles (PII, passwords, tokens)
64
+ - Tracing distribuido con baggage contextual
65
+ - Health checks sin autenticación (solo para orquestadores)
66
+ - Alertas basadas en métricas, no en logs
@@ -86,6 +86,58 @@ src/features/<feature-name>/
86
86
 
87
87
  ---
88
88
 
89
+ ## Events
90
+
91
+ | Archivo | Formato | Ejemplo |
92
+ |---------|---------|---------|
93
+ | Eventos de dominio | `<Domain><Accion>.event.ts` | `UserCreated.event.ts`, `OrderPaid.event.ts` |
94
+ | Handlers | `<Domain><Accion>.handler.ts` | `SendWelcomeEmail.handler.ts` |
95
+ | Outbox record | `<Entidad>.outbox.ts` | `User.outbox.ts` |
96
+
97
+ Los eventos siempre en pasado (`Created`, `Updated`, `Deleted`, `Paid`, `Shipped`), nunca en imperativo.
98
+
99
+ ---
100
+
101
+ ## Observability
102
+
103
+ | Archivo | Formato | Ejemplo |
104
+ |---------|---------|---------|
105
+ | Loggers | `Logger.service.ts`, `Logger.config.ts` | — |
106
+ | Métricas | `Metrics.ts`, `Metrics.middleware.ts` | — |
107
+ | Tracing | `Tracing.ts` | — |
108
+ | Health | `Health.ts`, `Health.controller.ts` | — |
109
+
110
+ Toda instrumentación vive en `platform/observability/`.
111
+ Para referencia completa ver `reference/observability.md`.
112
+
113
+ ---
114
+
115
+ ## Errors
116
+
117
+ | Archivo | Formato | Ejemplo |
118
+ |---------|---------|---------|
119
+ | Error base | `<Name>Error.ts` | `AppError.ts` |
120
+ | Error específico | `<Name>Error.ts` | `NotFoundError.ts`, `ValidationError.ts`, `ConflictError.ts` |
121
+
122
+ Los errores transversales viven en `shared/errors/`. Errores específicos de feature en `features/<name>/domain/errors/`.
123
+ Para guía completa ver `reference/errors.md`.
124
+
125
+ ---
126
+
127
+ ## API
128
+
129
+ | Archivo | Formato | Ejemplo |
130
+ |---------|---------|---------|
131
+ | Esquemas de validación | `<name>.schema.ts` | `createUser.schema.ts` |
132
+ | Routes | `<Name>.routes.ts` | `User.routes.ts` |
133
+ | Controller | `<Name>.controller.ts` | `User.controller.ts` |
134
+ | DTOs request | `<Name>.req.ts` | `CreateUser.req.ts` |
135
+ | DTOs response | `<Name>.res.ts` | `User.res.ts` |
136
+
137
+ REST prefiere `/api/v1/resources`. GraphQL schema en `adapters/in/graphql/` dentro del feature.
138
+
139
+ ---
140
+
89
141
  ## Infra Layer
90
142
 
91
143
  | Directorio | Archivos | Ejemplo |
@@ -27,3 +27,9 @@
27
27
  11. **El sistema es un grafo arquitectónico vivo** — Todo componente es un nodo tipado (platform, feature, shared, infra, domain, adapter, application). Toda relación es un edge validado. Las violaciones son edges prohibidos. El grafo es la fuente de verdad del sistema y se regenera en cada auditoría. Riesgo, salud y ownership se derivan del grafo, no de opiniones.
28
28
 
29
29
  12. **Cuatro dominios arquitectónicos con ownership estricto** — Todo backend se modela en cuatro capas: Platform (backbone técnico), Features (negocio), Shared (código puro reutilizable) e Infrastructure (implementaciones concretas). Cada componente tiene un único propietario arquitectónico. Los huérfanos, duplicados y componentes mal ubicados se detectan automáticamente. Las reglas de dependencia entre capas son obligatorias: `feature → platform → infra`, `feature → shared`, `adapter → infra`. Cualquier violación es una degradación arquitectónica.
30
+
31
+ 13. **Errores tipados en el dominio** — Los errores de dominio son clases explícitas, no `throw Error()` genéricos. Viven en `shared/errors/` si son transversales o en `domain/` del feature si son específicos. Los adapters HTTP traducen errores de dominio a códigos HTTP. La capa de aplicación nunca sabe qué códigos HTTP existen. Ver `reference/errors.md`.
32
+
33
+ 14. **Tests como ciudadanos de primera clase** — El dominio y los casos de uso se testean con unit tests sin infraestructura (mocks en las interfaces). Los adapters se testean con integration tests contra infraestructura real. La pirámide de tests es 70% unit / 20% integration / 10% e2e. Sin coverage de use cases no hay aprobación arquitectónica. Ver `reference/testing-patterns.md`.
34
+
35
+ 15. **Seguridad como infraestructura transversal** — AuthN, AuthZ, rate limiting y validación son infraestructura, no dominio. Se implementan en `platform/security/` y `platform/http/` como middlewares. El dominio recibe `userId` o `role` si un caso de uso lo necesita, pero nunca implementa lógica de autenticación. Ver `reference/security-patterns.md` y `reference/api-design.md`.
@@ -2,6 +2,8 @@
2
2
 
3
3
  Refactoriza la arquitectura de un feature o de un componente de platform/shared/infra.
4
4
 
5
+ También renombra archivos para cumplir con las convenciones de naming (`reference/patterns.md`).
6
+
5
7
  ## Cuándo usarlo
6
8
 
7
9
  - Un feature tiene violaciones arquitectónicas
@@ -9,20 +11,82 @@ Refactoriza la arquitectura de un feature o de un componente de platform/shared/
9
11
  - Un componente de platform necesita refinarse
10
12
  - Un componente de shared necesita rediseñarse
11
13
  - El grafo arquitectónico muestra violaciones que requieren intervención
14
+ - Un archivo no cumple con las convenciones de naming (`patterns.md`)
15
+ - Quieres renombrar un archivo y actualizar todos sus imports automáticamente
16
+
17
+ ## Caso A — `reforge <filename>` (solo renombrar)
18
+
19
+ Renombra un único archivo según las convenciones de `reference/patterns.md` y actualiza todos los imports que lo referencian.
20
+
21
+ **No ejecuta backup** (el rename no modifica lógica de negocio).
22
+
23
+ ### Flujo
24
+
25
+ 1. Identificar la ruta del archivo (relativa a la raíz del proyecto)
26
+ 2. Ejecutar `node .opencode/skills/forge/scripts/rename.mjs --detect --file <path>` para detectar violación
27
+ 3. Si el archivo ya cumple naming, informar y terminar
28
+ 4. Mostrar preview del cambio al usuario
29
+ 5. Ejecutar `node .opencode/skills/forge/scripts/rename.mjs --file <path>` que:
30
+ - Renombra físicamente el archivo
31
+ - Escanea todos los `.ts`/`.js` del proyecto
32
+ - Actualiza imports que referencian el path antiguo (relativos y absolutos)
33
+ 6. Verificar con `forge quench`
34
+ 7. Reportar resultado: archivo renombrado + cantidad de imports actualizados
35
+
36
+ ### Ejemplo
37
+
38
+ ```
39
+ $ forge reforge src/features/users/domain/userEntity.ts
40
+ Renombrar:
41
+ src/features/users/domain/userEntity.ts
42
+ → src/features/users/domain/User.entity.ts
43
+ Regla: feature/users/domain: <Name>.entity.ts
12
44
 
13
- ## Flujo básico
45
+ Archivo renombrado: userEntity.ts → User.entity.ts
46
+ ✓ Imports actualizados en 3 archivo(s):
47
+ src/features/users/application/use-cases/CreateUser.uc.ts
48
+ src/features/users/application/mappers/User.mapper.ts
49
+ src/features/users/adapters/in/http/User.controller.ts
50
+ ```
14
51
 
52
+ ## Caso B — `reforge` (completo con auto-fix naming)
53
+
54
+ ### Flujo
55
+
56
+ 0. **Backup**: Ejecutar `forge rollback backup <target>` antes de cualquier cambio
15
57
  1. Ejecutar `forge inspect` para obtener estado actual
16
58
  2. Identificar violaciones en el grafo arquitectónico
17
59
  3. Identificar ownership problemático (huérfanos, duplicados, mal ubicados)
18
- 4. Decidir las acciones correctivas en orden:
60
+ 4. **Detectar naming violations**: Ejecutar `node .opencode/skills/forge/scripts/rename.mjs --detect --json`
61
+ 5. Si hay naming violations, preguntar al usuario: "¿Corregir naming conventions automáticamente?"
62
+ - Si acepta, ejecutar `node .opencode/skills/forge/scripts/rename.mjs --all`
63
+ 6. Decidir las acciones correctivas en orden:
19
64
  - Violaciones CRITICAL primero (R1, R2, R5, R6)
20
65
  - Violaciones ERROR después (R3, R4, R8, R9)
21
66
  - Ownership problemático
67
+ - Naming violations (si no se corrigieron en paso 5)
22
68
  - Warnings
23
- 5. Ejecutar cambios en el feature o componente
24
- 6. Ejecutar `forge quench` para verificar
25
- 7. Actualizar `ARCHITECTURE.md`
69
+ 7. Ejecutar cambios en el feature o componente
70
+ 8. Verificar con `forge rollback verify` si el score empeora, restaurar
71
+ 9. Ejecutar `forge quench` para verificar
72
+ 10. Actualizar `ARCHITECTURE.md`
73
+
74
+ ### Flags
75
+
76
+ | Flag | Efecto |
77
+ |------|--------|
78
+ | `--dry-run` | Preview de naming violations sin hacer cambios |
79
+ | `--fix-naming` | Corregir naming violations sin preguntar |
80
+ | `--skip-naming` | Omitir detección y corrección de naming |
81
+
82
+ ## Rollback
83
+
84
+ Si la refactorización empeora el score arquitectónico, restaurar automáticamente:
85
+
86
+ ```bash
87
+ forge rollback list
88
+ forge rollback restore <id>
89
+ ```
26
90
 
27
91
  ## Refactorización multi-capa
28
92
 
@@ -15,6 +15,7 @@ También puede migrar componentes legacy a los layers Platform, Shared o Infrast
15
15
 
16
16
  ## Flujo
17
17
 
18
+ 0. **Backup automático**: Ejecutar `forge rollback backup <target>` antes de cualquier cambio
18
19
  1. Identificar el componente a migrar
19
20
  2. Clasificarlo en el layer correcto:
20
21
  - Configuración, servidor, logger, DI → **Platform**
@@ -25,8 +26,20 @@ También puede migrar componentes legacy a los layers Platform, Shared o Infrast
25
26
  4. Migrar archivos manteniendo la lógica intacta
26
27
  5. Actualizar imports
27
28
  6. Eliminar estructura legacy
28
- 7. Ejecutar `forge quench` para verificar
29
- 8. Actualizar `ARCHITECTURE.md`
29
+ 7. Verificar con `forge rollback verify` si el score empeora, restaurar con `forge rollback restore <backup-id>`
30
+ 8. Ejecutar `forge quench` para verificar
31
+ 9. Actualizar `ARCHITECTURE.md`
32
+
33
+ ## Rollback
34
+
35
+ Si la migración introduce violaciones (R1-R9), el agente DEBE restaurar automáticamente:
36
+
37
+ ```bash
38
+ forge rollback list # ver backups disponibles
39
+ forge rollback restore <id> # restaurar
40
+ ```
41
+
42
+ El backup se almacena en `.forge/backups/<target>--<timestamp>/` y preserva la estructura original completa.
30
43
 
31
44
  ## Estrategias por layer
32
45
 
@@ -0,0 +1,87 @@
1
+ # Security Patterns — Autenticación, autorización, rate limiting, validación
2
+
3
+ ## Principios arquitectónicos
4
+
5
+ - La seguridad es **infraestructura transversal**, no dominio de negocio.
6
+ - AuthN/AuthZ se implementan en `platform/security/` y se inyectan como middleware o decoradores.
7
+ - El dominio nunca contiene lógica de autenticación. Solo recibe `userId` si el caso de uso lo necesita.
8
+ - Validación de entrada en el controller o middleware de validación, nunca en la entidad de dominio.
9
+
10
+ ## Capas de seguridad
11
+
12
+ | Capa | Responsabilidad | Ubicación |
13
+ |------|----------------|-----------|
14
+ | Transport | TLS, HSTS, CORS, CSRF | platform/http/ |
15
+ | AuthN | Verificar quién es el usuario | platform/security/ |
16
+ | AuthZ | Verificar qué puede hacer | platform/security/ + features |
17
+ | Input validation | Sanitizar entrada | platform/http/ middleware |
18
+ | Rate limiting | Proteger contra abuso | platform/http/ middleware |
19
+ | Audit logging | Registrar acciones sensibles | platform/observability/ |
20
+
21
+ ## AuthN: Estrategias
22
+
23
+ | Estrategia | Cuándo usarla |
24
+ |------------|---------------|
25
+ | JWT (access + refresh) | SPAs, mobile, APIs stateless |
26
+ | Session + cookie | SSR tradicional, apps server-side |
27
+ | API Key | Service-to-service, CLIs |
28
+ | OAuth2 / OIDC | Delegación a terceros (Google, GitHub) |
29
+
30
+ ```ts
31
+ // platform/security/Auth.middleware.ts
32
+ export class AuthMiddleware {
33
+ async authenticate(req: Request, res: Response, next: NextFunction) {
34
+ const token = req.headers.authorization?.replace("Bearer ", "");
35
+ const payload = await this.jwtService.verify(token);
36
+ req.user = payload;
37
+ next();
38
+ }
39
+ }
40
+ ```
41
+
42
+ ## AuthZ: RBAC y Policy-based
43
+
44
+ ```ts
45
+ // features/users/application/use-cases/DeleteUser.uc.ts
46
+ export class DeleteUserUseCase {
47
+ constructor(
48
+ private readonly userRepo: IUserRepository,
49
+ private readonly authz: IAuthorizationService,
50
+ ) {}
51
+
52
+ async execute(actorId: string, targetId: string): Promise<void> {
53
+ await this.authz.require(actorId, "user:delete", { targetId });
54
+ // … lógica del caso de uso
55
+ }
56
+ }
57
+ ```
58
+
59
+ ## Rate limiting
60
+
61
+ ```ts
62
+ // platform/http/RateLimiter.middleware.ts
63
+ // Por IP, por ruta, por rol. Almacenamiento en Redis.
64
+ // Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
65
+ ```
66
+
67
+ ## Validación
68
+
69
+ ```ts
70
+ // shared/contracts/schemas.ts (zod)
71
+ export const createUserSchema = z.object({
72
+ email: z.string().email(),
73
+ name: z.string().min(2).max(100),
74
+ role: z.enum(["admin", "user"]).default("user"),
75
+ });
76
+ ```
77
+
78
+ ## Buenas prácticas
79
+
80
+ - Jamás almacenar passwords en texto plano. Usar bcrypt/argon2.
81
+ - JWT con corta expiración (15min access, 7d refresh)
82
+ - Refresh token rotation al usarse
83
+ - Rate limit por endpoint según criticidad: login (5/min), register (3/min), GET (100/min)
84
+ - CORS whitelist de origins conocidos, nunca `*`
85
+ - Helmet para headers de seguridad (CSP, X-Frame-Options, etc.)
86
+ - Secretos en variables de entorno, nunca en código
87
+ - Auditoría de acciones sensibles: login, delete, role change, export
@@ -0,0 +1,69 @@
1
+ # Testing Patterns — Tests en arquitectura hexagonal
2
+
3
+ ## Pirámide de tests
4
+
5
+ ```
6
+ ╱╲
7
+ ╱ E2E ╲ (2-5%) — happy paths críticos
8
+ ╱────────╲
9
+ ╱ Integration ╲ (15-25%) — adapters, rutas, repositorios
10
+ ╱────────────────╲
11
+ ╱ Unit Tests ╲ (70-80%) — use cases, entidades, mappers
12
+ ```
13
+
14
+ ## Qué testear en cada capa
15
+
16
+ | Capa | Tipo | Qué testear |
17
+ |------|------|-------------|
18
+ | `domain/entity` | Unit | Reglas de negocio, invariantes, validaciones |
19
+ | `application/use-cases` | Unit | Flujo completo con mocks de repositorios |
20
+ | `application/mappers` | Unit | Mapeo dominio ↔ DTO |
21
+ | `adapters/in/http` | Integration | HTTP requests, status codes, payloads |
22
+ | `adapters/out/persistence` | Integration | Queries reales (test DB) |
23
+ | `shared/errors` | Unit | Mensajes, códigos, instanceof |
24
+ | `platform/` | Integration | Middleware, server, logger, cache |
25
+
26
+ ## Unit: Use case con mocks
27
+
28
+ ```ts
29
+ // test/features/users/CreateUser.uc.test.ts
30
+ import { CreateUserUseCase } from "@/features/users/application/use-cases/CreateUser.uc.js";
31
+
32
+ const mockRepo = {
33
+ findByEmail: vi.fn(),
34
+ save: vi.fn(),
35
+ };
36
+
37
+ const uc = new CreateUserUseCase(mockRepo);
38
+
39
+ it("creates a user successfully", async () => {
40
+ mockRepo.findByEmail.mockResolvedValue(null);
41
+ mockRepo.save.mockResolvedValue({ id: "1", email: "test@test.com" });
42
+
43
+ const result = await uc.execute({ email: "test@test.com", name: "Test" });
44
+ expect(result).toHaveProperty("id");
45
+ });
46
+ ```
47
+
48
+ ## Integration: Controller
49
+
50
+ ```ts
51
+ // test/features/users/User.controller.test.ts
52
+ import supertest from "supertest";
53
+
54
+ it("POST /users returns 201", async () => {
55
+ const res = await request(app)
56
+ .post("/users")
57
+ .send({ email: "test@test.com", name: "Test" });
58
+ expect(res.status).toBe(201);
59
+ });
60
+ ```
61
+
62
+ ## Buenas prácticas
63
+
64
+ - No testear frameworks, solo tu código
65
+ - Mocks en el puerto (interfaz), no en la implementación
66
+ - Tests de integración contra BD real o testcontainers
67
+ - Nombrar tests como unidades de comportamiento, no métodos
68
+ - Coverage mínimo sugerido: 85% use cases, 75% adapters
69
+ - Los mappers se testean con fixtures: entrada conocida → salida esperada