@ronaldjdevfs/forge 1.3.3 → 1.3.6
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 +18 -10
- package/package.json +1 -1
- package/skills/forge/SKILL.md +13 -2
- package/skills/forge/command/forge.md +22 -22
- package/skills/forge/reference/assay.md +10 -10
- package/skills/forge/reference/cast.md +43 -0
- package/skills/forge/reference/chain.md +3 -3
- package/skills/forge/reference/evolutionary-architecture.md +2 -2
- package/skills/forge/reference/inspect.md +3 -3
- package/skills/forge/reference/patterns.md +60 -1
- package/skills/forge/reference/principles.md +2 -0
- package/skills/forge/reference/quench.md +3 -3
- package/skills/forge/reference/reforge.md +30 -8
- package/skills/forge/reference/relocate.md +25 -3
- package/skills/forge/scripts/armorer.mjs +21 -0
- package/skills/forge/scripts/detect.mjs +188 -0
- package/skills/forge/scripts/forgeSmith.mjs +85 -0
- package/skills/forge/scripts/inspect.mjs +4 -0
- package/skills/forge/scripts/registry/rules.mjs +25 -0
- package/skills/forge/scripts/rename.mjs +9 -0
- package/skills/forge/scripts/update.mjs +1 -1
- package/skills/forge/templates/feature/controller.ts.md +13 -5
- package/skills/forge/templates/feature/di.ts.md +33 -0
- package/skills/forge/templates/feature/mapper.ts.md +5 -0
- package/skills/forge/templates/feature/repository-impl.ts.md +6 -1
- package/skills/forge/templates/feature/routes.ts.md +5 -0
- package/skills/forge/templates/feature/schema.ts.md +4 -0
- package/skills/forge/templates/feature/test.ts.md +68 -0
- package/skills/forge/templates/feature/use-case.ts.md +5 -0
- package/skills/forge/tests/core.test.mjs +3 -2
- package/src/cli.js +21 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<img src="favicon.svg" alt="Forge Logo" width="100" height="100">
|
|
2
2
|
|
|
3
|
-
> **v1.3.
|
|
3
|
+
> **v1.3.6** — Multi-Agent Path Resolution Fix
|
|
4
4
|
|
|
5
5
|
## Forge — Backend Architecture Operating System
|
|
6
6
|
|
|
@@ -29,10 +29,10 @@ Los proyectos backend degeneran en código acoplado porque la infraestructura t
|
|
|
29
29
|
|-----------|---------|-------------|
|
|
30
30
|
| **Proyecto nuevo** | `forge` | Inicializa platform/features/shared/infra, detecta stack, crea `ARCHITECTURE.md` |
|
|
31
31
|
| **Crear un nuevo dominio** | `cast` | Genera un feature completo desde cero (verifica platform/shared/infra primero) |
|
|
32
|
-
| **Auditar arquitectura** | `inspect` | Evaluación completa
|
|
32
|
+
| **Auditar arquitectura** | `inspect` | Evaluación completa 180pts → 0-100 con ownership, platform, grafo e import conventions |
|
|
33
33
|
| **Migrar código legacy** | `relocate` | Traslada código a platform/, shared/, infra/ o features/ |
|
|
34
34
|
| **Refactorizar** | `reforge` | Reestructura features o componentes multi-capa |
|
|
35
|
-
| **Validar reglas** | `quench` | Verifica
|
|
35
|
+
| **Validar reglas** | `quench` | Verifica 12 reglas arquitectónicas (R1-R12) |
|
|
36
36
|
| **Endurecer DI** | `temper` | Aplica inyección por constructor, elimina service locators |
|
|
37
37
|
| **Analizar dependencias** | `chain` | Grafo multi-capa (platform, features, shared, infra), orden topológico, ciclos |
|
|
38
38
|
| **Documentar** | `inscribe` | Genera/actualiza `ARCHITECTURE.md` con métricas, ownership y violaciones |
|
|
@@ -72,16 +72,20 @@ src/features/<name>/
|
|
|
72
72
|
|
|
73
73
|
### `inspect` — Auditoría arquitectónica
|
|
74
74
|
|
|
75
|
-
Evalúa
|
|
75
|
+
Evalúa 10 categorías contra un máximo de 180 puntos (normalizado a 0-100):
|
|
76
76
|
|
|
77
77
|
| Categoría | Puntos | Qué mide |
|
|
78
78
|
|-----------|--------|----------|
|
|
79
|
-
| Structure |
|
|
80
|
-
| Layers |
|
|
79
|
+
| Structure | 30 | Organización de platform, features, shared, infra |
|
|
80
|
+
| Layers | 25 | Aislamiento entre capas, imports prohibidos |
|
|
81
|
+
| Decorators | 20 | Decoradores @injectable()/@inject() en use cases, controllers, repos |
|
|
81
82
|
| Ownership | 20 | Huérfanos, duplicados, mal ubicados |
|
|
82
83
|
| Platform | 15 | Completitud del backbone técnico (config, server, logger, di, etc.) |
|
|
83
84
|
| Dependencies | 15 | Dirección de dependencias, ciclos, edges inválidos |
|
|
84
85
|
| Graph | 20 | Salud del grafo arquitectónico, risk score |
|
|
86
|
+
| Custom Rules | 5 | Reglas personalizadas desde `.forge/rules.json` |
|
|
87
|
+
| Naming | 10 | Convenciones de nomenclatura PascalCase/kebab |
|
|
88
|
+
| Import Conventions | 20 | R10-R12: bare specifiers, extensión .ts, bootstrap.di.js |
|
|
85
89
|
|
|
86
90
|
**Resultado**: Score 0-100 con grado A-F y severidades por cada violación.
|
|
87
91
|
|
|
@@ -116,6 +120,10 @@ Ejecuta 9 reglas arquitectónicas (R1-R9) con severidad:
|
|
|
116
120
|
| R7 | `infra → feature` (prohibido) | WARNING |
|
|
117
121
|
| R8 | Cross-feature direct imports | ERROR |
|
|
118
122
|
| R9 | Ciclos de dependencia | ERROR |
|
|
123
|
+
| R10 | Bare specifiers en imports locales | ERROR |
|
|
124
|
+
| R11 | Extensión `.ts` en imports (debe ser `.js`) | ERROR |
|
|
125
|
+
| R12 | Import a `bootstrap.di.js` (no existe) | CRITICAL |
|
|
126
|
+
| R12b | `registerSingleton` con model() de Mongoose | CRITICAL |
|
|
119
127
|
|
|
120
128
|
### `temper` — Endurecimiento de DI
|
|
121
129
|
|
|
@@ -311,8 +319,8 @@ Ver `reference/patterns.md` para el detalle completo.
|
|
|
311
319
|
- **4 dominios arquitectónicos**: Platform (backbone), Features (negocio), Shared (código puro), Infra (implementaciones)
|
|
312
320
|
- **Architecture graph como fuente de verdad**: 6 tipos de nodo (platform, feature, shared, infra, domain, adapter), 9 reglas (R1-R9), risk score y dependency health
|
|
313
321
|
- **Ownership automático**: Detección de huérfanos, duplicados, componentes mal ubicados y sugerencias de reubicación
|
|
314
|
-
- **Scoring arquitectónico**:
|
|
315
|
-
- **
|
|
322
|
+
- **Scoring arquitectónico**: 180 puntos en 10 categorías, normalizado a 0-100 con grado A-F
|
|
323
|
+
- **10 perfiles tecnológicos predefinidos**: Express + MongoDB, Express + PostgreSQL, Express + Prisma, Express + Drizzle, Fastify + MongoDB, Fastify + PostgreSQL, Fastify + Prisma, NestJS + MongoDB, NestJS + PostgreSQL, NestJS + Prisma
|
|
316
324
|
- **Boot sequence obligatoria**: 9 pasos que garantizan contexto completo antes de cualquier acción
|
|
317
325
|
- **Documentación automática**: `ARCHITECTURE.md` vivo que se actualiza tras cada operación
|
|
318
326
|
- **Sin dependencias runtime**: Solo Node ≥ 18, todo corre con scripts ESM propios
|
|
@@ -358,7 +366,7 @@ Donde vive toda la inteligencia arquitectónica:
|
|
|
358
366
|
| `scripts/profile.mjs` | Matchea stack contra perfiles conocidos o sintetiza uno genérico |
|
|
359
367
|
| `scripts/graph.mjs` | Grafo completo: 6 tipos de nodo, 4 capas, 9 reglas (R1-R9), risk score, dependency health |
|
|
360
368
|
| `scripts/chain.mjs` | Grafo multi-capa (platform, features, shared, infra) con orden topológico |
|
|
361
|
-
| `scripts/detect.mjs` | Validación de reglas R1-
|
|
369
|
+
| `scripts/detect.mjs` | Validación de reglas R1-R12 con inline ignores, `--fix` e import conventions |
|
|
362
370
|
| `scripts/inspect.mjs` | Orquesta auditoría completa con reporte coloreado |
|
|
363
371
|
| `scripts/architecture.mjs` | Genera/actualiza `ARCHITECTURE.md` vivo |
|
|
364
372
|
| `scripts/bootstrap.mjs` | Inicializa platform/shared/infra según perfil (interno) |
|
|
@@ -385,7 +393,7 @@ Donde vive toda la inteligencia arquitectónica:
|
|
|
385
393
|
| `reference/assay.md` | Documentación del comando assay |
|
|
386
394
|
| `reference/hooks.md` | Documentación del sistema de hooks |
|
|
387
395
|
| `profiles/` | 10 perfiles tecnológicos detallados |
|
|
388
|
-
| `templates/feature/` |
|
|
396
|
+
| `templates/feature/` | 19 templates TypeScript para features |
|
|
389
397
|
| `templates/platform/` | 6 templates para componentes de platform |
|
|
390
398
|
| `templates/shared/` | 4 templates para shared (errors, contracts, types, utils) |
|
|
391
399
|
| `templates/infra/` | 4 templates para infra (prisma, mongodb, redis, mail) |
|
package/package.json
CHANGED
package/skills/forge/SKILL.md
CHANGED
|
@@ -75,7 +75,7 @@ En esencia:
|
|
|
75
75
|
ANTES de cualquier acción, Forge DEBE ejecutar `forge-boot.mjs` con la profundidad adecuada al comando:
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
|
-
boot=$(node
|
|
78
|
+
boot=$(node {{AGENT_PATH}}/scripts/forge-boot.mjs --depth <depth> --json 2>/dev/null)
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
La profundidad (`--depth`) depende del comando (ver Execution Flow):
|
|
@@ -150,6 +150,17 @@ El boot usa caché de `.forge/cache/`. Si los archivos `src/` no cambiaron, los
|
|
|
150
150
|
- Si `ARCHITECTURE.md` está desactualizado (fecha de auditoría > 7 días), sugerir `forge inscribe`.
|
|
151
151
|
- Todos los resultados se muestran con severidades: `[CRITICAL]`, `[ERROR]`, `[WARNING]`, `[INFO]`, `[SUGGESTION]`.
|
|
152
152
|
|
|
153
|
+
### ⚠️ Regla de Platform: Sin lógica de dominio
|
|
154
|
+
|
|
155
|
+
Cuando `reforge` o `relocate` operen sobre `src/platform/`, verificar que los archivos movidos/creados no contengan lógica de dominio:
|
|
156
|
+
|
|
157
|
+
- **No** mover entidades, value objects, casos de uso, mappers de dominio, schemas de entidades, repositorios de dominio a `platform/`
|
|
158
|
+
- **No** crear archivos con sufijos `.entity.ts`, `.uc.ts`, `.mapper.ts`, `.repository.ts` (domain), `.port.ts` dentro de `platform/`
|
|
159
|
+
- **No** importar desde `features/` dentro de `platform/` (viola R2)
|
|
160
|
+
- Si un componente tiene imports hacia `domain/` o `features/`, pertenece a un feature, no a platform
|
|
161
|
+
|
|
162
|
+
Platform solo acepta: config, database, http, server, logger, cache, security, events, scheduler, observability, di.
|
|
163
|
+
|
|
153
164
|
### Inline Ignores
|
|
154
165
|
|
|
155
166
|
Forge soporta comentarios inline para excepcionar violaciones línea por línea:
|
|
@@ -182,7 +193,7 @@ El agente DEBE leer este archivo al inicio de cada interacción y actualizarlo a
|
|
|
182
193
|
Forge incluye tests unitarios con `node:test` (sin dependencias externas).
|
|
183
194
|
|
|
184
195
|
```bash
|
|
185
|
-
node --test
|
|
196
|
+
node --test {{AGENT_PATH}}/tests/core.test.mjs
|
|
186
197
|
```
|
|
187
198
|
|
|
188
199
|
| Módulo | Tests | Descripción |
|
|
@@ -30,13 +30,13 @@ Si el subcomando NO tiene flags en $ARGUMENTS y tiene flags disponibles (ver tab
|
|
|
30
30
|
Inicializa el proyecto arquitectónicamente. Ejecuta context + bootstrap + profile + armorer + graph + chain + inscribe.
|
|
31
31
|
|
|
32
32
|
```
|
|
33
|
-
node
|
|
34
|
-
node
|
|
35
|
-
node
|
|
36
|
-
node
|
|
37
|
-
node
|
|
38
|
-
node
|
|
39
|
-
node
|
|
33
|
+
node {{AGENT_PATH}}/scripts/context.mjs
|
|
34
|
+
node {{AGENT_PATH}}/scripts/bootstrap.mjs
|
|
35
|
+
node {{AGENT_PATH}}/scripts/profile.mjs
|
|
36
|
+
node {{AGENT_PATH}}/scripts/armorer.mjs
|
|
37
|
+
node {{AGENT_PATH}}/scripts/graph.mjs
|
|
38
|
+
node {{AGENT_PATH}}/scripts/chain.mjs
|
|
39
|
+
node {{AGENT_PATH}}/scripts/architecture.mjs
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
### cast
|
|
@@ -52,7 +52,7 @@ Migra un feature existente. Puede targetizar platform/, shared/, infra/ o featur
|
|
|
52
52
|
Genera ARCHITECTURE.md con grafo arquitectónico, ownership y platform.
|
|
53
53
|
|
|
54
54
|
```
|
|
55
|
-
node
|
|
55
|
+
node {{AGENT_PATH}}/scripts/architecture.mjs
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
### graph
|
|
@@ -60,13 +60,13 @@ node .opencode/skills/forge/scripts/architecture.mjs
|
|
|
60
60
|
Construye el grafo arquitectónico del proyecto (4 capas: platform, feature, shared, infra) con reglas R1-R9.
|
|
61
61
|
|
|
62
62
|
```
|
|
63
|
-
node
|
|
63
|
+
node {{AGENT_PATH}}/scripts/graph.mjs
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
Para salida JSON:
|
|
67
67
|
|
|
68
68
|
```
|
|
69
|
-
node
|
|
69
|
+
node {{AGENT_PATH}}/scripts/graph.mjs --json
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
### smelt
|
|
@@ -78,7 +78,7 @@ Extrae código reutilizable a shared/ (solo código puro, sin dependencias infra
|
|
|
78
78
|
Inicializa platform, shared e infra layers (uso interno, se ejecuta automáticamente).
|
|
79
79
|
|
|
80
80
|
```
|
|
81
|
-
node
|
|
81
|
+
node {{AGENT_PATH}}/scripts/bootstrap.mjs
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
## Evaluate
|
|
@@ -88,13 +88,13 @@ node .opencode/skills/forge/scripts/bootstrap.mjs
|
|
|
88
88
|
Audita la conformidad arquitectónica completa. 6 categorías: structure(20), layers(20), ownership(20), platform(15), dependencies(15), graph(20).
|
|
89
89
|
|
|
90
90
|
```
|
|
91
|
-
node
|
|
91
|
+
node {{AGENT_PATH}}/scripts/inspect.mjs
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
Para salida JSON:
|
|
95
95
|
|
|
96
96
|
```
|
|
97
|
-
node
|
|
97
|
+
node {{AGENT_PATH}}/scripts/inspect.mjs --json
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
### assay
|
|
@@ -102,16 +102,16 @@ node .opencode/skills/forge/scripts/inspect.mjs --json
|
|
|
102
102
|
Ensayo arquitectónico multi-persona. Interpretación cualitativa del audit desde 5 perspectivas (Bezos, Fowler, Hacker, PM, Arquitecta Senior).
|
|
103
103
|
|
|
104
104
|
```
|
|
105
|
-
node
|
|
105
|
+
node {{AGENT_PATH}}/scripts/assay.mjs
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
Filtros:
|
|
109
109
|
|
|
110
110
|
```
|
|
111
|
-
node
|
|
112
|
-
node
|
|
113
|
-
node
|
|
114
|
-
node
|
|
111
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --persona=bezos
|
|
112
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --json
|
|
113
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --save
|
|
114
|
+
node {{AGENT_PATH}}/scripts/assay.mjs history
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
### quench
|
|
@@ -119,7 +119,7 @@ node .opencode/skills/forge/scripts/assay.mjs history
|
|
|
119
119
|
Valida reglas arquitectónicas R1-R9.
|
|
120
120
|
|
|
121
121
|
```
|
|
122
|
-
node
|
|
122
|
+
node {{AGENT_PATH}}/scripts/detect.mjs
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
### chain
|
|
@@ -127,13 +127,13 @@ node .opencode/skills/forge/scripts/detect.mjs
|
|
|
127
127
|
Orden topológico de dependencias multi-capa (platform, features, shared, infra).
|
|
128
128
|
|
|
129
129
|
```
|
|
130
|
-
node
|
|
130
|
+
node {{AGENT_PATH}}/scripts/chain.mjs
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
Para salida JSON:
|
|
134
134
|
|
|
135
135
|
```
|
|
136
|
-
node
|
|
136
|
+
node {{AGENT_PATH}}/scripts/chain.mjs --json
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
### armorer
|
|
@@ -141,7 +141,7 @@ node .opencode/skills/forge/scripts/chain.mjs --json
|
|
|
141
141
|
Reporte de ownership: huérfanos, duplicados, componentes mal ubicados.
|
|
142
142
|
|
|
143
143
|
```
|
|
144
|
-
node
|
|
144
|
+
node {{AGENT_PATH}}/scripts/armorer.mjs
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
## Refine
|
|
@@ -23,26 +23,26 @@ Genera un **ensayo arquitectónico multi-persona** que evalúa el estado actual
|
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
# Ensayo completo con todas las personas
|
|
26
|
-
node
|
|
26
|
+
node {{AGENT_PATH}}/scripts/assay.mjs
|
|
27
27
|
|
|
28
28
|
# Solo la opinión de una persona
|
|
29
|
-
node
|
|
30
|
-
node
|
|
31
|
-
node
|
|
32
|
-
node
|
|
33
|
-
node
|
|
29
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --persona=bezos
|
|
30
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --persona=fowler
|
|
31
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --persona=hacker
|
|
32
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --persona=pm
|
|
33
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --persona=senior
|
|
34
34
|
|
|
35
35
|
# Salida JSON (para consumo por herramientas)
|
|
36
|
-
node
|
|
36
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --json
|
|
37
37
|
|
|
38
38
|
# Persistir ensayo en .forge/assay/
|
|
39
|
-
node
|
|
39
|
+
node {{AGENT_PATH}}/scripts/assay.mjs --save
|
|
40
40
|
|
|
41
41
|
# Ver historial de ensayos
|
|
42
|
-
node
|
|
42
|
+
node {{AGENT_PATH}}/scripts/assay.mjs history
|
|
43
43
|
|
|
44
44
|
# Leer un ensayo previo
|
|
45
|
-
node
|
|
45
|
+
node {{AGENT_PATH}}/scripts/assay.mjs read assay-2026-06-25T00-00-00.md
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
## Formato de salida
|
|
@@ -143,6 +143,49 @@ Usar el perfil detectado para determinar:
|
|
|
143
143
|
- Convenciones de imports (rutas relativas vs alias)
|
|
144
144
|
- Componentes de platform a usar (config, logger, http, database)
|
|
145
145
|
|
|
146
|
+
## ⚠️ Post-Cast: Entity Discovery
|
|
147
|
+
|
|
148
|
+
Antes de crear `<Name>.entity.ts`, verificar si la entidad ya existe como entidad compartida:
|
|
149
|
+
|
|
150
|
+
1. **Buscar en `src/platform/domain/entities/<Name>.ts`** — si existe, NO crear entidad local
|
|
151
|
+
2. **Si es compartida**: usar `@/domain/entities/<Name>.js` en vez de path relativo en todos los templates
|
|
152
|
+
3. **Verificar también** `src/shared/contracts/` por interfaces/DTOs existentes
|
|
153
|
+
|
|
154
|
+
Regla: si la entidad vive fuera del feature, todos los imports deben usar path alias `@/domain/`, no `../../`.
|
|
155
|
+
|
|
156
|
+
## ⚠️ Post-Cast: DI Wiring
|
|
157
|
+
|
|
158
|
+
Después de crear los archivos del feature, generar `di.ts` siguiendo el template `templates/feature/di.ts.md`:
|
|
159
|
+
|
|
160
|
+
1. **Feature con DI propia**: crear `src/features/<name>/di.ts` usando el template
|
|
161
|
+
2. **Feature SIN DI propia**: si ya existe `src/platform/setting/dependencies/<name>.di.js`, los controllers deben importar desde allí en vez de `bootstrap.di.js`
|
|
162
|
+
3. **Controllers**: asegurar que el import en el controller apunte a `@/setting/dependencies/<name>.di.js` o `./di.js`, NUNCA a `bootstrap.di.js`
|
|
163
|
+
4. **Mongoose model()**: si el schema exporta `export default model()` (objeto, no clase), el DI debe usar `container.register(..., { useValue: ... })`, NO `registerSingleton`
|
|
164
|
+
|
|
165
|
+
## ⚠️ Post-Cast: Tests
|
|
166
|
+
|
|
167
|
+
Después del scaffold, generar tests unitarios para cada use case siguiendo `templates/feature/test.ts.md`:
|
|
168
|
+
|
|
169
|
+
1. Crear `src/features/<name>/__tests__/Create<Name>.test.ts`
|
|
170
|
+
2. Usar `node:test` (sin dependencias externas)
|
|
171
|
+
3. Convenciones de test:
|
|
172
|
+
- Extension `.js` en imports (no `.ts`)
|
|
173
|
+
- `as const` para literales de union types: `status: "activo" as const`
|
|
174
|
+
- `result!` (non-null assertion) cuando execute() retorna `T | null`
|
|
175
|
+
- `(result as any)._id` si `_id` no existe en el tipo de dominio
|
|
176
|
+
|
|
177
|
+
## ⚠️ Post-Cast: Import Validation Checklist
|
|
178
|
+
|
|
179
|
+
Antes de dar por terminado el feature, verificar CADA archivo generado:
|
|
180
|
+
|
|
181
|
+
- [ ] Todos los imports locales usan prefijo `./` o `../` — sin bare specifiers (`import X from "domain/..."` ❌)
|
|
182
|
+
- [ ] Todos los imports tienen extensión `.js` — sin extensión `.ts`
|
|
183
|
+
- [ ] Entidades compartidas usan `@/domain/` — sin paths relativos rotos
|
|
184
|
+
- [ ] Controllers importan desde `di.ts` o `@/setting/dependencies/` — no desde `bootstrap.di.js`
|
|
185
|
+
- [ ] Nombres de método del controller coinciden con los de la ruta (ej: `createHandler` en controller → `controller.createHandler` en routes)
|
|
186
|
+
- [ ] DI usa `register({ useValue })` para modelos Mongoose — no `registerSingleton`
|
|
187
|
+
- [ ] Tests: `.js` extension, `as const`, `!`, `as any` para _id
|
|
188
|
+
|
|
146
189
|
## Post-creación
|
|
147
190
|
|
|
148
191
|
- `forge quench` — verificar que no hay violaciones
|
|
@@ -54,13 +54,13 @@ container.registerSingleton<ICreditRepository>(
|
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
# Grafo de dependencias entre features (API legacy)
|
|
57
|
-
node
|
|
57
|
+
node {{AGENT_PATH}}/scripts/chain.mjs
|
|
58
58
|
|
|
59
59
|
# Grafo arquitectónico completo (nodos, edges, violaciones)
|
|
60
|
-
node
|
|
60
|
+
node {{AGENT_PATH}}/scripts/graph.mjs
|
|
61
61
|
|
|
62
62
|
# ARCHITECTURE.md con grafo incluido
|
|
63
|
-
node
|
|
63
|
+
node {{AGENT_PATH}}/scripts/architecture.mjs
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
`chain.mjs` ahora es un wrapper sobre `graph.mjs`. Produce el mismo formato de salida para compatibilidad (nodos, edges, features, orden topológico). El nuevo `graph.mjs` amplía el análisis a todos los tipos de nodo (core, feature, domain, infra, adapter) y detecta violaciones de reglas arquitectónicas (R1-R6).
|
|
@@ -85,10 +85,10 @@ jobs:
|
|
|
85
85
|
runs-on: ubuntu-latest
|
|
86
86
|
steps:
|
|
87
87
|
- uses: actions/checkout@v4
|
|
88
|
-
- run: node
|
|
88
|
+
- run: node {{AGENT_PATH}}/scripts/detect.mjs
|
|
89
89
|
env:
|
|
90
90
|
FORGE_STRICT: "true"
|
|
91
|
-
- run: node
|
|
91
|
+
- run: node {{AGENT_PATH}}/scripts/chain.mjs --json
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
---
|
|
@@ -52,9 +52,9 @@ Inspecciona la conformidad arquitectónica del proyecto.
|
|
|
52
52
|
## Ejecución
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
node
|
|
56
|
-
node
|
|
57
|
-
node
|
|
55
|
+
node {{AGENT_PATH}}/scripts/inspect.mjs
|
|
56
|
+
node {{AGENT_PATH}}/scripts/inspect.mjs --json
|
|
57
|
+
node {{AGENT_PATH}}/scripts/detect.mjs --severity ERROR
|
|
58
58
|
|
|
59
59
|
## Ver también
|
|
60
60
|
|
|
@@ -150,11 +150,70 @@ REST prefiere `/api/v1/resources`. GraphQL schema en `adapters/in/graphql/` dent
|
|
|
150
150
|
|
|
151
151
|
---
|
|
152
152
|
|
|
153
|
+
## Import Conventions (OBLIGATORIO)
|
|
154
|
+
|
|
155
|
+
Todo import generado por Forge debe cumplir estas reglas. Violaciones = ERROR en forge quench:
|
|
156
|
+
|
|
157
|
+
### 1. Prefijo relativo obligatorio
|
|
158
|
+
Los imports locales SIEMPRE deben usar prefijo `./` o `../`. Prohibido el bare specifier:
|
|
159
|
+
```ts
|
|
160
|
+
// ✅ Correcto
|
|
161
|
+
import { X } from "./foo.js";
|
|
162
|
+
import { Y } from "../../bar.js";
|
|
163
|
+
|
|
164
|
+
// ❌ Incorrecto (bare specifier — se resuelve contra node_modules)
|
|
165
|
+
import { X } from "domain/entities/Task.js";
|
|
166
|
+
import { Y } from "domain/repositories/IRepo.js";
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 2. Extensión .js obligatoria
|
|
170
|
+
Con `moduleResolution: "nodenext"`, todos los imports locales requieren extensión `.js`:
|
|
171
|
+
```ts
|
|
172
|
+
// ✅ Correcto
|
|
173
|
+
import { X } from "./foo.js";
|
|
174
|
+
|
|
175
|
+
// ❌ Incorrecto
|
|
176
|
+
import { X } from "./foo.ts";
|
|
177
|
+
import { X } from "./foo";
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 3. Path alias para cross-layer
|
|
181
|
+
Usar path alias `@/` para cruzar capas, no paths relativos largos:
|
|
182
|
+
| Capa | Alias | Ejemplo |
|
|
183
|
+
|------|-------|---------|
|
|
184
|
+
| Platform → cualquiera | `@/platform/` | `@/platform/config/App.config.js` |
|
|
185
|
+
| Shared → cualquiera | `@/shared/` | `@/shared/errors/NotFoundError.js` |
|
|
186
|
+
| Infra → cualquiera | `@/infra/` | `@/infra/mongodb/Mongo.config.js` |
|
|
187
|
+
| **Entities compartidas** | **`@/domain/`** | **`@/domain/entities/Task.js`** |
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
// ✅ Correcto — path alias para entidad compartida
|
|
191
|
+
import { Task } from "@/domain/entities/Task.js";
|
|
192
|
+
|
|
193
|
+
// ❌ Incorrecto — path relativo largo que no resuelve
|
|
194
|
+
import { Task } from "../../../../domain/entities/Task.js";
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 4. Entity Discovery — compartida vs local
|
|
198
|
+
- Si la entidad vive en `src/features/<feature>/domain/entities/` → import relativo (`../../domain/entities/`)
|
|
199
|
+
- Si la entidad vive en `src/platform/domain/entities/` → path alias (`@/domain/entities/`)
|
|
200
|
+
- Verificar existencia ANTES de generar el import
|
|
201
|
+
|
|
202
|
+
### 5. Controllers y DI
|
|
203
|
+
- Controllers importan desde `./di.js` (feature con DI propia) o `@/setting/dependencies/<name>.di.js` (feature sin DI propia)
|
|
204
|
+
- Prohibido importar desde `bootstrap.di.js` — ese archivo no existe en la arquitectura actual
|
|
205
|
+
|
|
206
|
+
### 6. Tests
|
|
207
|
+
- Todos los imports con extensión `.js` (nunca `.ts`)
|
|
208
|
+
- Usar `as const` para literales de union types
|
|
209
|
+
- Usar `result!` para valores posiblemente null
|
|
210
|
+
- Usar `(result as any)._id` si `_id` no está en el tipo
|
|
211
|
+
|
|
153
212
|
## Export Conventions
|
|
154
213
|
|
|
155
214
|
- Cada directorio expone un `index.ts` barrel con named exports
|
|
156
215
|
- Usar `export * from "./<Name>.<artifact>.js"` en barrels
|
|
157
216
|
- Preferir `export function` / `export class` sobre `export default`
|
|
158
217
|
- Imports relativos dentro del mismo feature (`../../domain/`)
|
|
159
|
-
- Path alias para cross-layer: `@/platform/`, `@/shared/`, `@/infra/`
|
|
218
|
+
- Path alias para cross-layer: `@/platform/`, `@/shared/`, `@/infra/`, `@/domain/`
|
|
160
219
|
- Extension `.js` en imports (ESM compat): `import { X } from "./foo.js"`
|
|
@@ -28,6 +28,8 @@
|
|
|
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
30
|
|
|
31
|
+
**⚠️ Platform es exclusivamente backbone técnico.** Nunca debe contener entidades de dominio, casos de uso, mappers, repositorios de dominio, schemas de entidades, DTOs de negocio ni ninguna lógica con reglas de negocio. Si un archivo en `platform/` tiene sufijos `.entity.ts`, `.uc.ts`, `.mapper.ts`, `.port.ts` o importa desde `features/`, está mal ubicado. Esa lógica pertenece a `src/features/<name>/`. Violar esto introduce acoplamiento `platform → feature` (R2) y contamina el backbone técnico con lógica de dominio (R13).
|
|
32
|
+
|
|
31
33
|
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
34
|
|
|
33
35
|
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`.
|
|
@@ -64,13 +64,13 @@ El grafo se construye automáticamente con `scripts/graph.mjs` y las violaciones
|
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
66
|
# Validación completa
|
|
67
|
-
node
|
|
67
|
+
node {{AGENT_PATH}}/scripts/detect.mjs
|
|
68
68
|
|
|
69
69
|
# Solo errores y críticos
|
|
70
|
-
node
|
|
70
|
+
node {{AGENT_PATH}}/scripts/detect.mjs --severity ERROR
|
|
71
71
|
|
|
72
72
|
# Solo un tipo específico
|
|
73
|
-
node
|
|
73
|
+
node {{AGENT_PATH}}/scripts/detect.mjs --type layers
|
|
74
74
|
|
|
75
75
|
## Ver también
|
|
76
76
|
|
|
@@ -23,10 +23,10 @@ Renombra un único archivo según las convenciones de `reference/patterns.md` y
|
|
|
23
23
|
### Flujo
|
|
24
24
|
|
|
25
25
|
1. Identificar la ruta del archivo (relativa a la raíz del proyecto)
|
|
26
|
-
2. Ejecutar `node
|
|
26
|
+
2. Ejecutar `node {{AGENT_PATH}}/scripts/rename.mjs --detect --file <path>` para detectar violación
|
|
27
27
|
3. Si el archivo ya cumple naming, informar y terminar
|
|
28
28
|
4. Mostrar preview del cambio al usuario
|
|
29
|
-
5. Ejecutar `node
|
|
29
|
+
5. Ejecutar `node {{AGENT_PATH}}/scripts/rename.mjs --file <path>` que:
|
|
30
30
|
- Renombra físicamente el archivo
|
|
31
31
|
- Escanea todos los `.ts`/`.js` del proyecto
|
|
32
32
|
- Actualiza imports que referencian el path antiguo (relativos y absolutos)
|
|
@@ -57,9 +57,9 @@ $ forge reforge src/features/users/domain/userEntity.ts
|
|
|
57
57
|
1. Ejecutar `forge inspect` para obtener estado actual
|
|
58
58
|
2. Identificar violaciones en el grafo arquitectónico
|
|
59
59
|
3. Identificar ownership problemático (huérfanos, duplicados, mal ubicados)
|
|
60
|
-
4. **Detectar naming violations**: Ejecutar `node
|
|
60
|
+
4. **Detectar naming violations**: Ejecutar `node {{AGENT_PATH}}/scripts/rename.mjs --detect --json`
|
|
61
61
|
5. Si hay naming violations, preguntar al usuario: "¿Corregir naming conventions automáticamente?"
|
|
62
|
-
- Si acepta, ejecutar `node
|
|
62
|
+
- Si acepta, ejecutar `node {{AGENT_PATH}}/scripts/rename.mjs --all`
|
|
63
63
|
6. Decidir las acciones correctivas en orden:
|
|
64
64
|
- Violaciones CRITICAL primero (R1, R2, R5, R6)
|
|
65
65
|
- Violaciones ERROR después (R3, R4, R8, R9)
|
|
@@ -67,9 +67,15 @@ $ forge reforge src/features/users/domain/userEntity.ts
|
|
|
67
67
|
- Naming violations (si no se corrigieron en paso 5)
|
|
68
68
|
- Warnings
|
|
69
69
|
7. Ejecutar cambios en el feature o componente
|
|
70
|
-
8.
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
8. **Eliminar estructura legacy** — después de migrar/refactorizar, limpiar todo el código fuente legacy que ya no tenga referencias activas:
|
|
71
|
+
- Archivos originales en ubicaciones legacy (`src/domain/`, `src/application/`, `src/adapters/`, etc.)
|
|
72
|
+
- Barrel files (`index.ts`) que exportaban exclusivamente código legacy
|
|
73
|
+
- Directorios vacíos que quedaron huérfanos tras la migración
|
|
74
|
+
- No dejar imports rotos ni archivos sin dueño
|
|
75
|
+
9. Verificar con `forge rollback verify` — si el score empeora, restaurar
|
|
76
|
+
10. Ejecutar `forge quench` para verificar 0 violaciones
|
|
77
|
+
11. Ejecutar `forge armorer` — confirmar ownership saludable (0 huérfanos, 0 duplicados)
|
|
78
|
+
12. Actualizar `ARCHITECTURE.md`
|
|
73
79
|
|
|
74
80
|
### Flags
|
|
75
81
|
|
|
@@ -88,11 +94,27 @@ forge rollback list
|
|
|
88
94
|
forge rollback restore <id>
|
|
89
95
|
```
|
|
90
96
|
|
|
97
|
+
## ⚠️ Regla crítica: Platform solo acepta backbone técnico
|
|
98
|
+
|
|
99
|
+
**Platform NO debe contener lógica de dominio.** Al refactorizar hacia `src/platform/`, verificar que el componente sea exclusivamente técnico:
|
|
100
|
+
|
|
101
|
+
| ✅ Permitido en Platform | ❌ Prohibido en Platform |
|
|
102
|
+
|---|---|
|
|
103
|
+
| config, server, logger, DI | Entidades de dominio |
|
|
104
|
+
| http, middleware, router | Casos de uso |
|
|
105
|
+
| cache, security, events | Repositorios (domain) |
|
|
106
|
+
| database, scheduler, observability | Mappers de dominio |
|
|
107
|
+
| Conexiones, clientes de infra | Schemas de entidades |
|
|
108
|
+
| Tokens de DI, contenedores | DTOs de negocio |
|
|
109
|
+
| Health checks, métricas | Lógica de reglas de negocio |
|
|
110
|
+
|
|
111
|
+
Si durante la refactorización un componente tiene lógica de dominio (entidades, `if/switch` con reglas de negocio, casos de uso), **debe ir a `src/features/<name>/`**, no a `platform/`. Violar esto introduce acoplamiento `platform → feature` (R2).
|
|
112
|
+
|
|
91
113
|
## Refactorización multi-capa
|
|
92
114
|
|
|
93
115
|
Reforge ahora considera las cuatro capas arquitectónicas:
|
|
94
116
|
|
|
95
|
-
- **Platform**: Mover componentes técnicos sueltos a `src/platform/`
|
|
117
|
+
- **Platform**: Mover componentes técnicos sueltos a `src/platform/` (nunca lógica de dominio)
|
|
96
118
|
- **Features**: Reestructurar features con violaciones
|
|
97
119
|
- **Shared**: Extraer código duplicado a `src/shared/`
|
|
98
120
|
- **Infra**: Organizar implementaciones concretas en `src/infra/`
|
|
@@ -25,10 +25,16 @@ También puede migrar componentes legacy a los layers Platform, Shared o Infrast
|
|
|
25
25
|
3. Crear la estructura target según el layer
|
|
26
26
|
4. Migrar archivos manteniendo la lógica intacta
|
|
27
27
|
5. Actualizar imports
|
|
28
|
-
6. Eliminar estructura legacy
|
|
28
|
+
6. **Eliminar estructura legacy por completo** — no dejar archivos huérfanos, barrel files (index.ts) vacíos, ni directorios legacy sin contenido. Verificar:
|
|
29
|
+
- `src/application/use-cases/<name>/` queda vacío y se elimina
|
|
30
|
+
- `src/adapters/in/http/controllers/` sin archivos del feature migrado
|
|
31
|
+
- `src/domain/entities/`, `src/domain/repositories/` sin duplicados
|
|
32
|
+
- `src/setting/dependencies/` sin `.di.ts` del feature migrado
|
|
33
|
+
- Barrel files (`index.ts`) que solo exportaban código legacy se eliminan
|
|
29
34
|
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.
|
|
35
|
+
8. Ejecutar `forge quench` para verificar 0 violaciones
|
|
36
|
+
9. Ejecutar `forge armorer` — confirmar que no hay huérfanos ni duplicados del código legacy
|
|
37
|
+
10. Actualizar `ARCHITECTURE.md`
|
|
32
38
|
|
|
33
39
|
## Rollback
|
|
34
40
|
|
|
@@ -41,6 +47,22 @@ forge rollback restore <id> # restaurar
|
|
|
41
47
|
|
|
42
48
|
El backup se almacena en `.forge/backups/<target>--<timestamp>/` y preserva la estructura original completa.
|
|
43
49
|
|
|
50
|
+
## ⚠️ Regla crítica: No insertar lógica de dominio en Platform
|
|
51
|
+
|
|
52
|
+
Al migrar componentes legacy, **nunca colocar lógica de dominio en `src/platform/`**. Platform es exclusivamente backbone técnico.
|
|
53
|
+
|
|
54
|
+
| Tipo de componente | Layer correcto |
|
|
55
|
+
|---|---|
|
|
56
|
+
| Configuración de framework, servidor, logger, DI | `src/platform/` |
|
|
57
|
+
| Middleware HTTP, routers, guards, interceptors | `src/platform/http/` |
|
|
58
|
+
| Conexiones a BD, clientes Redis, mail | `src/infra/` |
|
|
59
|
+
| Código utilitario puro (sin lógica de negocio) | `src/shared/` |
|
|
60
|
+
| **Entidades, value objects, reglas de dominio** | **`src/features/<name>/domain/`** |
|
|
61
|
+
| **Casos de uso, servicios de aplicación** | **`src/features/<name>/application/`** |
|
|
62
|
+
| **Controladores, repositorios, schemas** | **`src/features/<name>/adapters/`** |
|
|
63
|
+
|
|
64
|
+
Si un archivo contiene `class`, `interface` con reglas de negocio, `if/switch` con lógica de dominio, o importa desde `features/`, pertenece a un feature, no a platform.
|
|
65
|
+
|
|
44
66
|
## Estrategias por layer
|
|
45
67
|
|
|
46
68
|
| Layer | Desde | Hacia |
|
|
@@ -246,6 +246,27 @@ export function detectMisplaced(projectRoot = ROOT) {
|
|
|
246
246
|
suggestion: "Envolver en un adapter dentro de features/<name>/adapters/out/",
|
|
247
247
|
});
|
|
248
248
|
}
|
|
249
|
+
|
|
250
|
+
// R13: Platform con lógica de dominio
|
|
251
|
+
if (isPlatformFile) {
|
|
252
|
+
const basenamePath = basename(file);
|
|
253
|
+
const DOMAIN_PATTERNS = /\.(entity|uc|mapper|port|repository)\.(ts|js)$/i;
|
|
254
|
+
if (DOMAIN_PATTERNS.test(basenamePath)) {
|
|
255
|
+
misplaced.push({
|
|
256
|
+
file: relPath,
|
|
257
|
+
reason: "Platform contiene artefacto de dominio — violación R13",
|
|
258
|
+
suggestion: "Mover a src/features/<name>/domain/ o application/ según corresponda",
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
const featureImportMatch = content.match(featurePattern);
|
|
262
|
+
if (featureImportMatch) {
|
|
263
|
+
misplaced.push({
|
|
264
|
+
file: relPath,
|
|
265
|
+
reason: "Platform importa de features — violación R2",
|
|
266
|
+
suggestion: "Platform no debe conocer lógica de negocio. Extraer interfaz a shared/contracts/ o refactorizar.",
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
249
270
|
}
|
|
250
271
|
|
|
251
272
|
return misplaced;
|