@ronaldjdevfs/forge 1.0.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/LICENSE +201 -0
- package/NOTICE +9 -0
- package/README.md +338 -0
- package/logo.png +0 -0
- package/package.json +47 -0
- package/skills/forge/SKILL.md +207 -0
- package/skills/forge/command/forge.md +110 -0
- package/skills/forge/profiles/express-mongodb.md +289 -0
- package/skills/forge/profiles/express-postgres.md +164 -0
- package/skills/forge/profiles/express-prisma.md +116 -0
- package/skills/forge/profiles/fastify-postgres.md +110 -0
- package/skills/forge/profiles/nestjs-prisma.md +160 -0
- package/skills/forge/reference/cast.md +77 -0
- package/skills/forge/reference/chain.md +73 -0
- package/skills/forge/reference/forge.md +44 -0
- package/skills/forge/reference/inscribe.md +129 -0
- package/skills/forge/reference/inspect.md +58 -0
- package/skills/forge/reference/patterns.md +108 -0
- package/skills/forge/reference/principles.md +29 -0
- package/skills/forge/reference/quench.md +74 -0
- package/skills/forge/reference/reforge.md +40 -0
- package/skills/forge/reference/relocate.md +38 -0
- package/skills/forge/reference/smelt.md +31 -0
- package/skills/forge/reference/temper.md +49 -0
- package/skills/forge/scripts/architecture.mjs +176 -0
- package/skills/forge/scripts/armorer.mjs +421 -0
- package/skills/forge/scripts/bootstrap.mjs +187 -0
- package/skills/forge/scripts/chain.mjs +258 -0
- package/skills/forge/scripts/context.mjs +237 -0
- package/skills/forge/scripts/detect.mjs +843 -0
- package/skills/forge/scripts/graph.mjs +594 -0
- package/skills/forge/scripts/inspect.mjs +193 -0
- package/skills/forge/scripts/profile.mjs +92 -0
- package/skills/forge/templates/feature/controller.ts.md +66 -0
- package/skills/forge/templates/feature/entity.ts.md +11 -0
- package/skills/forge/templates/feature/mapper.ts.md +18 -0
- package/skills/forge/templates/feature/repository-impl.ts.md +59 -0
- package/skills/forge/templates/feature/repository-interface.ts.md +12 -0
- package/skills/forge/templates/feature/routes.ts.md +17 -0
- package/skills/forge/templates/feature/schema.ts.md +16 -0
- package/skills/forge/templates/feature/use-case.ts.md +19 -0
- package/skills/forge/templates/infra/mail.ts.md +31 -0
- package/skills/forge/templates/infra/mongodb.ts.md +12 -0
- package/skills/forge/templates/infra/prisma.ts.md +21 -0
- package/skills/forge/templates/infra/redis.ts.md +30 -0
- package/skills/forge/templates/platform/config.ts.md +37 -0
- package/skills/forge/templates/platform/database.ts.md +40 -0
- package/skills/forge/templates/platform/di.ts.md +18 -0
- package/skills/forge/templates/platform/http.ts.md +29 -0
- package/skills/forge/templates/platform/logger.ts.md +38 -0
- package/skills/forge/templates/platform/server.ts.md +25 -0
- package/skills/forge/templates/shared/contract.ts.md +20 -0
- package/skills/forge/templates/shared/error.ts.md +27 -0
- package/skills/forge/templates/shared/type.ts.md +18 -0
- package/skills/forge/templates/shared/util.ts.md +23 -0
- package/src/cli.js +179 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Forge
|
|
2
|
+
|
|
3
|
+
Inicializa un proyecto para trabajar con Forge como Backend Architecture Operating System.
|
|
4
|
+
|
|
5
|
+
## Cuándo usarlo
|
|
6
|
+
|
|
7
|
+
- Proyecto nuevo sin estructura definida
|
|
8
|
+
- Proyecto existente sin `ARCHITECTURE.md`
|
|
9
|
+
- Después de clonar un repositorio
|
|
10
|
+
- Para bootstrappear los layers Platform, Shared e Infrastructure
|
|
11
|
+
|
|
12
|
+
## Flujo
|
|
13
|
+
|
|
14
|
+
1. Ejecutar `scripts/context.mjs` para detectar stack actual (incluye platform, features, shared, infra)
|
|
15
|
+
2. Ejecutar `scripts/bootstrap.mjs` para crear layers faltantes (platform, shared, infra)
|
|
16
|
+
3. Ejecutar `scripts/profile.mjs` para determinar perfil tecnológico
|
|
17
|
+
4. Ejecutar `scripts/armorer.mjs` para detectar ownership y huérfanos
|
|
18
|
+
5. Ejecutar `scripts/graph.mjs` para construir grafo arquitectónico global
|
|
19
|
+
6. Ejecutar `scripts/chain.mjs` para analizar dependencias multi-capa
|
|
20
|
+
7. Si `ARCHITECTURE.md` no existe, crearlo con `forge inscribe`
|
|
21
|
+
8. Si faltan dependencias clave (según perfil), listarlas
|
|
22
|
+
9. Si el proyecto tiene código legacy, sugerir `forge relocate`
|
|
23
|
+
10. Si el proyecto está listo, sugerir `forge cast`
|
|
24
|
+
|
|
25
|
+
## Output esperado
|
|
26
|
+
|
|
27
|
+
- `ARCHITECTURE.md` creado en la raíz del proyecto
|
|
28
|
+
- Layers Platform, Shared e Infrastructure creados si no existían
|
|
29
|
+
- Perfil tecnológico detectado y registrado
|
|
30
|
+
- Ownership analizado
|
|
31
|
+
- Dependencias base verificadas
|
|
32
|
+
- Próximos pasos sugeridos según el estado del proyecto
|
|
33
|
+
|
|
34
|
+
## Severidades
|
|
35
|
+
|
|
36
|
+
| Condición | Severidad |
|
|
37
|
+
|---|---|
|
|
38
|
+
| Sin `src/` directory | ERROR |
|
|
39
|
+
| Sin `package.json` | ERROR |
|
|
40
|
+
| Sin perfil detectable | WARNING |
|
|
41
|
+
| Sin `ARCHITECTURE.md` | INFO |
|
|
42
|
+
| Platform layer ausente | SUGGESTION |
|
|
43
|
+
| Dependencias faltantes | WARNING |
|
|
44
|
+
| Ownership con huérfanos | WARNING |
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Inscribe
|
|
2
|
+
|
|
3
|
+
Genera y mantiene el archivo `ARCHITECTURE.md` del proyecto.
|
|
4
|
+
|
|
5
|
+
## Cuándo usarlo
|
|
6
|
+
|
|
7
|
+
- Proyecto nuevo (crear ARCHITECTURE.md inicial)
|
|
8
|
+
- Después de migrar un feature (actualizar estado)
|
|
9
|
+
- Después de refactorizar (actualizar decisiones)
|
|
10
|
+
- Cuando se detecta que ARCHITECTURE.md está desactualizado
|
|
11
|
+
- On demand: `forge inscribe`
|
|
12
|
+
|
|
13
|
+
## Formato generado
|
|
14
|
+
|
|
15
|
+
```md
|
|
16
|
+
# Architecture State
|
|
17
|
+
|
|
18
|
+
**Project Name:** <detectado>
|
|
19
|
+
**Framework:** <detectado>
|
|
20
|
+
**Runtime:** <detectado>
|
|
21
|
+
**Database:** <detectado>
|
|
22
|
+
**ORM:** <detectado>
|
|
23
|
+
**DI Strategy:** <detectado>
|
|
24
|
+
**Profile:** <detectado>
|
|
25
|
+
**Architecture:** hexagonal-feature (Platform + Features + Shared + Infra)
|
|
26
|
+
**Last Audit:** <fecha> (score: <puntaje>)
|
|
27
|
+
|
|
28
|
+
## Platform
|
|
29
|
+
- platform/config/
|
|
30
|
+
- platform/database/
|
|
31
|
+
- platform/http/
|
|
32
|
+
- platform/logger/
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
- features/users/
|
|
36
|
+
- features/payments/
|
|
37
|
+
|
|
38
|
+
## Shared
|
|
39
|
+
- shared/errors/
|
|
40
|
+
- shared/types/
|
|
41
|
+
- shared/utils/
|
|
42
|
+
|
|
43
|
+
## Infrastructure
|
|
44
|
+
- infra/prisma/
|
|
45
|
+
- infra/redis/
|
|
46
|
+
|
|
47
|
+
## Ownership
|
|
48
|
+
**Health:** healthy | degraded | critical
|
|
49
|
+
**Score:** 85/100
|
|
50
|
+
**Orphans:** 0
|
|
51
|
+
**Duplicates:** 0
|
|
52
|
+
**Misplaced:** 0
|
|
53
|
+
|
|
54
|
+
## Architecture Graph
|
|
55
|
+
**Nodes:** 15
|
|
56
|
+
**Edges:** 20
|
|
57
|
+
**Risk Score:** 12/100
|
|
58
|
+
**Health:** healthy
|
|
59
|
+
**Dependency Health:** 95%
|
|
60
|
+
|
|
61
|
+
### Platform Layer
|
|
62
|
+
- `platform:config` — config
|
|
63
|
+
|
|
64
|
+
### Feature Layer
|
|
65
|
+
- `feature:users` — users
|
|
66
|
+
|
|
67
|
+
### Shared Layer
|
|
68
|
+
- `shared:errors` — errors
|
|
69
|
+
|
|
70
|
+
### Infrastructure Layer
|
|
71
|
+
- `infra:prisma` — prisma
|
|
72
|
+
|
|
73
|
+
### Domain Layer
|
|
74
|
+
- `domain:users` — users/domain
|
|
75
|
+
|
|
76
|
+
### Adapter Layer
|
|
77
|
+
- `adapter:users` — users/adapters
|
|
78
|
+
|
|
79
|
+
### Violations
|
|
80
|
+
| Rule | From | To | Severity | Description |
|
|
81
|
+
|------|------|----|----------|-------------|
|
|
82
|
+
| R1 | `feature:users` | `infra:prisma` | CRITICAL | Features no acceden infraestructura directamente |
|
|
83
|
+
|
|
84
|
+
### Dependency Graph
|
|
85
|
+
- `feature:users` → [domain:users, adapter:users]
|
|
86
|
+
|
|
87
|
+
## Dependency Health
|
|
88
|
+
**Valid Edges:** 19/20
|
|
89
|
+
**Dependency Health:** 95%
|
|
90
|
+
**Risk Score:** 12/100
|
|
91
|
+
**Health:** healthy
|
|
92
|
+
|
|
93
|
+
## Violations
|
|
94
|
+
...
|
|
95
|
+
|
|
96
|
+
## Context
|
|
97
|
+
...
|
|
98
|
+
|
|
99
|
+
## Tech Stack
|
|
100
|
+
...
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Campos auto-detectados
|
|
104
|
+
|
|
105
|
+
| Campo | Fuente |
|
|
106
|
+
|---|---|
|
|
107
|
+
| Framework | `scripts/context.mjs` |
|
|
108
|
+
| Database | `scripts/context.mjs` |
|
|
109
|
+
| ORM | `scripts/context.mjs` |
|
|
110
|
+
| DI Strategy | `scripts/context.mjs` |
|
|
111
|
+
| Active Profile | `scripts/profile.mjs` |
|
|
112
|
+
| Platform | `scripts/context.mjs` → platform |
|
|
113
|
+
| Features | `scripts/context.mjs` → features |
|
|
114
|
+
| Shared | `scripts/context.mjs` → shared |
|
|
115
|
+
| Infra | `scripts/context.mjs` → infra |
|
|
116
|
+
| Ownership | `scripts/armorer.mjs` |
|
|
117
|
+
| Architecture Graph | `scripts/graph.mjs` |
|
|
118
|
+
| Risk Score | `scripts/graph.mjs` → stats.riskScore |
|
|
119
|
+
| Violations | `scripts/graph.mjs` → violations |
|
|
120
|
+
| Last Audit | `scripts/inspect.mjs` → fecha + score |
|
|
121
|
+
|
|
122
|
+
## Reglas
|
|
123
|
+
|
|
124
|
+
- ARCHITECTURE.md se guarda en la raíz del proyecto
|
|
125
|
+
- Forge lo lee antes de cada ejecución
|
|
126
|
+
- Si está desactualizado (última auditoría > 7 días), Forge sugiere actualizarlo
|
|
127
|
+
- Se actualiza automáticamente después de cada comando
|
|
128
|
+
- No editar manualmente los campos auto-detectados
|
|
129
|
+
- Forge preserva cualquier sección adicional que el usuario agregue
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Inspect
|
|
2
|
+
|
|
3
|
+
Inspecciona la conformidad arquitectónica del proyecto.
|
|
4
|
+
|
|
5
|
+
## Cuándo usarlo
|
|
6
|
+
|
|
7
|
+
- Diagnóstico inicial del proyecto
|
|
8
|
+
- Post-migración de feature
|
|
9
|
+
- On demand para verificar estado actual
|
|
10
|
+
- Pre-deploy para garantizar calidad arquitectónica
|
|
11
|
+
|
|
12
|
+
## Flujo
|
|
13
|
+
|
|
14
|
+
1. Ejecutar `scripts/context.mjs` → detectar stack y estructura
|
|
15
|
+
2. Ejecutar `scripts/profile.mjs` → determinar perfil activo
|
|
16
|
+
3. Ejecutar `scripts/chain.mjs` → construir cadena de dependencias
|
|
17
|
+
4. Ejecutar `scripts/detect.mjs` → detectar todas las violaciones
|
|
18
|
+
5. Construir reporte con puntuación y severidades
|
|
19
|
+
6. Mostrar resultado al usuario
|
|
20
|
+
|
|
21
|
+
## Categorías
|
|
22
|
+
|
|
23
|
+
| Categoría | Pts | Qué mide |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Estructura | 30 | Features completos (domain, application, adapters) |
|
|
26
|
+
| Capas | 25 | Imports prohibidos, lógica en controllers, BD directa |
|
|
27
|
+
| Decoradores | 20 | @injectable y @inject presentes donde corresponde |
|
|
28
|
+
| Legacy | 15 | Archivos residuales en ubicaciones antiguas |
|
|
29
|
+
| Configuración | 10 | tsconfig, dependencias, reflect-metadata |
|
|
30
|
+
| Grafo | 20 | Violaciones arquitectónicas (R1-R6), risk score, salud del grafo |
|
|
31
|
+
|
|
32
|
+
## Severidades
|
|
33
|
+
|
|
34
|
+
| Severidad | Significado | Ejemplo |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| CRITICAL | Viola principio fundamental de la arquitectura | Domain importa de adapters |
|
|
37
|
+
| ERROR | Viola una regla de capas o estructura | Controller con lógica de negocio |
|
|
38
|
+
| WARNING | Inconsistencia que requiere atención | Feature sin repository interface |
|
|
39
|
+
| INFO | Observación sobre el estado actual | Feature incompleto |
|
|
40
|
+
| SUGGESTION | Recomendación de mejora | Usar tokens de clase en @inject |
|
|
41
|
+
|
|
42
|
+
## Interpretación del score
|
|
43
|
+
|
|
44
|
+
| Rango | Nota | Significado |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| 90-100 | A | Arquitectura sólida. Cumple todos los principios. |
|
|
47
|
+
| 80-89 | B | Inconsistencias menores. Fáciles de corregir. |
|
|
48
|
+
| 65-79 | C | Varias violaciones. Requiere trabajo estructurado. |
|
|
49
|
+
| 50-64 | D | Arquitectura comprometida. Migración necesaria. |
|
|
50
|
+
| 0-49 | F | Proyecto no migrado o con violaciones generalizadas. |
|
|
51
|
+
|
|
52
|
+
## Ejecución
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
node .opencode/skills/forge/scripts/inspect.mjs
|
|
56
|
+
node .opencode/skills/forge/scripts/inspect.mjs --json
|
|
57
|
+
node .opencode/skills/forge/scripts/detect.mjs --severity ERROR
|
|
58
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Patterns — Naming Conventions
|
|
2
|
+
|
|
3
|
+
## Global
|
|
4
|
+
|
|
5
|
+
| Elemento | Formato | Ejemplo |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| Directorios | `kebab-case/` | `credit-card/`, `event-bus/` |
|
|
8
|
+
| Archivos | `<PascalCase>.<artefacto>.ts` | `User.entity.ts` |
|
|
9
|
+
| Interfaces | `I<PascalCase>.<artefacto>.ts` | `IUser.repository.ts` |
|
|
10
|
+
| Use cases | `<Action>.uc.ts` | `CreateUser.uc.ts` |
|
|
11
|
+
| Clases | `PascalCase` | `UserController`, `DatabaseConfig` |
|
|
12
|
+
| Funciones/variables | `camelCase` | `formatDate`, `userService` |
|
|
13
|
+
| Constantes | `UPPER_SNAKE_CASE` | `MAX_RETRY_COUNT` |
|
|
14
|
+
| Tipos (type/interface puros) | `PascalCase` | `UserPayload`, `PaginatedResult` |
|
|
15
|
+
| Enums | `PascalCase` | `UserRole`, `OrderStatus` |
|
|
16
|
+
| Barrel files | `index.ts` | named exports, no `export default` |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Platform Layer
|
|
21
|
+
|
|
22
|
+
| Directorio | Archivos |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `config/` | `App.config.ts`, `Env.config.ts`, `Database.config.ts` |
|
|
25
|
+
| `server/` | `Server.ts`, `App.ts` |
|
|
26
|
+
| `database/` | `Database.config.ts`, `Connection.ts` |
|
|
27
|
+
| `http/` | `Router.ts`, `Auth.middleware.ts`, `Error.middleware.ts`, `RateLimiter.middleware.ts` |
|
|
28
|
+
| `logger/` | `Logger.config.ts`, `Logger.service.ts` |
|
|
29
|
+
| `cache/` | `Cache.config.ts`, `Cache.service.ts` |
|
|
30
|
+
| `security/` | `Auth.middleware.ts`, `Encryption.service.ts` |
|
|
31
|
+
| `events/` | `EventBus.ts`, `EventHandler.ts` |
|
|
32
|
+
| `scheduler/` | `Scheduler.config.ts`, `Scheduler.service.ts` |
|
|
33
|
+
| `observability/` | `Metrics.ts`, `Tracing.ts`, `Health.ts` |
|
|
34
|
+
| `di/` | `Container.ts`, `Tokens.ts`, `Module.ts` |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Feature Layer
|
|
39
|
+
|
|
40
|
+
| Ruta | Archivo | Ejemplo |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `domain/` | `<Name>.entity.ts` | `User.entity.ts` |
|
|
43
|
+
| `domain/` | `I<Name>.repository.ts` | `IUser.repository.ts` |
|
|
44
|
+
| `application/use-cases/` | `<Action>.uc.ts` | `CreateUser.uc.ts`, `GetUser.uc.ts` |
|
|
45
|
+
| `application/mappers/` | `<Name>.mapper.ts` | `User.mapper.ts` |
|
|
46
|
+
| `adapters/in/http/` | `<Name>.controller.ts` | `User.controller.ts` |
|
|
47
|
+
| `adapters/in/http/` | `<Name>.routes.ts` | `User.routes.ts` |
|
|
48
|
+
| `adapters/out/persistence/` | `<Name>.repository.ts` | `User.repository.ts` |
|
|
49
|
+
| `adapters/out/persistence/` | `<Name>.schema.ts` | `User.schema.ts` |
|
|
50
|
+
|
|
51
|
+
Estructura de directorios:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
src/features/<feature-name>/
|
|
55
|
+
├── domain/
|
|
56
|
+
│ ├── <Domain>.entity.ts
|
|
57
|
+
│ └── I<Domain>.repository.ts
|
|
58
|
+
├── application/
|
|
59
|
+
│ ├── use-cases/
|
|
60
|
+
│ │ ├── Create<Domain>.uc.ts
|
|
61
|
+
│ │ ├── Get<Domain>.uc.ts
|
|
62
|
+
│ │ ├── List<Domain>.uc.ts
|
|
63
|
+
│ │ ├── Update<Domain>.uc.ts
|
|
64
|
+
│ │ └── Delete<Domain>.uc.ts
|
|
65
|
+
│ └── mappers/
|
|
66
|
+
│ └── <Domain>.mapper.ts
|
|
67
|
+
└── adapters/
|
|
68
|
+
├── in/http/
|
|
69
|
+
│ ├── <Domain>.controller.ts
|
|
70
|
+
│ └── <Domain>.routes.ts
|
|
71
|
+
└── out/persistence/
|
|
72
|
+
├── <Domain>.repository.ts
|
|
73
|
+
└── <Domain>.schema.ts
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Shared Layer
|
|
79
|
+
|
|
80
|
+
| Directorio | Archivos | Ejemplo |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `errors/` | `<Name>Error.ts` | `NotFoundError.ts`, `ValidationError.ts` |
|
|
83
|
+
| `contracts/` | `I<Name>.ts` | `IPaginatedResponse.ts` |
|
|
84
|
+
| `types/` | `<dominio>.types.ts` | `user.types.ts`, `api.types.ts` |
|
|
85
|
+
| `utils/` | `<util>.ts` (camelCase) | `formatDate.ts`, `pagination.ts` |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Infra Layer
|
|
90
|
+
|
|
91
|
+
| Directorio | Archivos | Ejemplo |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| `prisma/` | `Prisma.client.ts`, `Prisma.service.ts` | — |
|
|
94
|
+
| `mongodb/` | `Mongo.config.ts`, `<Name>.model.ts` | `User.model.ts` |
|
|
95
|
+
| `redis/` | `Redis.config.ts`, `Redis.service.ts` | — |
|
|
96
|
+
| `mail/` | `Mail.config.ts`, `Mail.service.ts` | — |
|
|
97
|
+
| `s3/` | `S3.config.ts`, `S3.service.ts` | — |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Export Conventions
|
|
102
|
+
|
|
103
|
+
- Cada directorio expone un `index.ts` barrel con named exports
|
|
104
|
+
- Usar `export * from "./<Name>.<artifact>.js"` en barrels
|
|
105
|
+
- Preferir `export function` / `export class` sobre `export default`
|
|
106
|
+
- Imports relativos dentro del mismo feature (`../../domain/`)
|
|
107
|
+
- Path alias para cross-layer: `@/platform/`, `@/shared/`, `@/infra/`
|
|
108
|
+
- Extension `.js` en imports (ESM compat): `import { X } from "./foo.js"`
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Principles
|
|
2
|
+
|
|
3
|
+
> Forge es una **disciplina arquitectónica**, no un template. Nace de la convicción de que el código limpio no se escribe, se forja. Combina **Arquitectura Hexagonal**, **DDD ligero** (sin sobreingeniería) y **vertical slices** para producir sistemas donde cada dominio de negocio es dueño absoluto de su destino. La inyección de dependencias no es un detalle técnico: es la herramienta que garantiza que el dominio nunca se contamine de infraestructura.
|
|
4
|
+
|
|
5
|
+
## Principios Inquebrantables
|
|
6
|
+
|
|
7
|
+
1. **Arquitectura hexagonal basada en features** — La unidad de organización es el feature, no la capa técnica. Cada dominio contiene su propio `domain/`, `application/` y `adapters/`. Las capas existen *dentro* de cada feature, no al revés.
|
|
8
|
+
|
|
9
|
+
2. **DDD ligero, sin sobreingeniería** — Usa la terminología y estructura de Domain-Driven Design (entidades, repositorios, casos de uso) pero sin la rigidez académica. No crees "value objects" donde basta un `string`. No fuerces aggregate roots donde una interfaz limpia resuelve el problema. Pragmatismo sobre dogma.
|
|
10
|
+
|
|
11
|
+
3. **Separación estricta entre dominio e infraestructura** — El dominio no sabe qué framework, base de datos o servicios externos existen. Las interfaces (puertos) están en `domain/`. Las implementaciones (adapters) están en `adapters/out/`. Esta frontera es la razón de ser de la arquitectura hexagonal.
|
|
12
|
+
|
|
13
|
+
4. **Un feature es una unidad autónoma** — Todo lo que pertenece a un dominio vive dentro de `features/<name>/`. Entidades, repositorios, casos de uso, controladores, rutas, esquemas, mappers, DTOs. Si un archivo importa código de otro feature fuera de su directorio, la separación está rota.
|
|
14
|
+
|
|
15
|
+
5. **Dependencias unidireccionales** — La flecha apunta SIEMPRE hacia adentro: `adapters → application → domain → (nada)`. Domain no importa nada. Application solo importa de domain y shared. Cualquier import que viole esto se rechaza en code review. No hay excepciones.
|
|
16
|
+
|
|
17
|
+
6. **Cero lógica de negocio en controladores** — El controller parsea la request, llama al caso de uso, y responde. No valida reglas, no calcula montos, no decide flujos. Si hay un `if` con lógica de dominio en un controller, está en el lugar equivocado.
|
|
18
|
+
|
|
19
|
+
7. **Cero acceso a BD fuera de infraestructura** — Los repositories son la ÚNICA puerta a la base de datos. Ningún use case, controller o servicio llama al ORM, toca esquemas o ejecuta queries directamente. Las operaciones de BD solo aparecen en los repositories.
|
|
20
|
+
|
|
21
|
+
8. **Código explícito sobre código mágico** — Prefiere imports explícitos, inyección por constructor y tipos declarados sobre decoradores ocultos, proxies automáticos o registros implícitos. El código debe leerse de arriba a abajo y entender su flujo sin herramientas externas de análisis.
|
|
22
|
+
|
|
23
|
+
9. **Inyección de dependencias disciplinada** — La inyección de dependencias es por constructor, sin service locators ni singletons globales. Si el proyecto es pequeño, DI manual basta. Si crece, usar el sistema de DI del framework o un contenedor externo. Nunca `container.resolve()` dentro de lógica de negocio.
|
|
24
|
+
|
|
25
|
+
10. **Escalabilidad horizontal de features** — Agregar un nuevo feature NUNCA implica modificar un feature existente. Nuevo dominio = nuevo directorio `features/<name>/`, nuevos casos de uso, nuevos adapters. El acoplamiento entre features solo ocurre mediante inyección de interfaces, nunca con imports directos entre features.
|
|
26
|
+
|
|
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
|
+
|
|
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.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Quench
|
|
2
|
+
|
|
3
|
+
Valida que el proyecto cumpla las reglas arquitectónicas.
|
|
4
|
+
|
|
5
|
+
## Cuándo usarlo
|
|
6
|
+
|
|
7
|
+
- Después de migrar un feature
|
|
8
|
+
- Después de crear un feature con `forge cast`
|
|
9
|
+
- Después de refactorizar con `forge reforge`
|
|
10
|
+
- Pre-commit o pre-deploy
|
|
11
|
+
|
|
12
|
+
## Reglas críticas
|
|
13
|
+
|
|
14
|
+
| Regla | Código | Severidad | Descripción |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| Domain no importa infraestructura | — | CRITICAL | Domain no puede importar adapters, setting ni infraestructura |
|
|
17
|
+
| Application no importa adapters | — | ERROR | Application solo importa de domain y shared |
|
|
18
|
+
| Sin container.resolve() en use cases | — | ERROR | El contenedor solo se usa en bootstrap |
|
|
19
|
+
| Sin lógica de negocio en controllers | — | ERROR | Controllers solo parsean, delegan y responden |
|
|
20
|
+
| Sin BD directa fuera de repositorios | — | ERROR | Repositories son la única puerta a datos |
|
|
21
|
+
| Sin imports directos entre features | — | WARNING | Comunicación via interfaces inyectadas |
|
|
22
|
+
| DI consistente dentro del feature | — | WARNING | No mezclar manual + contenedor en el mismo feature |
|
|
23
|
+
| Tests pasando | — | ERROR | Tests deben pasar después de cualquier cambio |
|
|
24
|
+
|
|
25
|
+
## Reglas del grafo arquitectónico
|
|
26
|
+
|
|
27
|
+
| Código | Regla | Severidad | Descripción |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| R1 | core → feature | CRITICAL | Core nunca debe depender de features |
|
|
30
|
+
| R2 | domain → infra | CRITICAL | Domain no puede importar infraestructura |
|
|
31
|
+
| R3 | feature → infra (directo) | CRITICAL | Features no acceden infraestructura sin adapter |
|
|
32
|
+
| R4 | feature → feature (directo) | ERROR | Features no se importan directamente entre sí |
|
|
33
|
+
| R5 | Ciclo de dependencias | ERROR | Ciclo detectado en el grafo de features |
|
|
34
|
+
| R6 | infra → domain/feature | WARNING | Infraestructura no debe importar dominio interno |
|
|
35
|
+
|
|
36
|
+
El grafo se construye automáticamente con `scripts/graph.mjs` y las violaciones se incluyen en `scripts/detect.mjs` (categoría `graph`).
|
|
37
|
+
|
|
38
|
+
## Checklist pre-migración
|
|
39
|
+
|
|
40
|
+
- [ ] Dependencias del perfil instaladas (tsyringe, reflect-metadata, etc.)
|
|
41
|
+
- [ ] Decoradores habilitados en tsconfig (si aplica)
|
|
42
|
+
- [ ] Entry point configurado
|
|
43
|
+
- [ ] Orden topológico definido
|
|
44
|
+
- [ ] Dependencias de cada feature identificadas
|
|
45
|
+
|
|
46
|
+
## Checklist post-migración (por feature)
|
|
47
|
+
|
|
48
|
+
- [ ] @injectable() en use cases, controller y repository
|
|
49
|
+
- [ ] @inject() con tokens de clase (no strings)
|
|
50
|
+
- [ ] Sin container.resolve() en lógica de negocio
|
|
51
|
+
- [ ] Imports actualizados (sin referencias legacy)
|
|
52
|
+
- [ ] Archivo .di.ts legacy eliminado
|
|
53
|
+
- [ ] Controller usa arrow-methods
|
|
54
|
+
- [ ] Use case tiene un único execute()
|
|
55
|
+
- [ ] Repository implementa la interfaz del dominio
|
|
56
|
+
- [ ] Mapper tiene toDomain() y toPersistence()
|
|
57
|
+
- [ ] Routes/index.ts actualizado
|
|
58
|
+
- [ ] Tests migrados y pasando
|
|
59
|
+
- [ ] pnpm lint pasa
|
|
60
|
+
- [ ] pnpm build pasa
|
|
61
|
+
- [ ] pnpm test pasa
|
|
62
|
+
|
|
63
|
+
## Ejecución
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Validación completa
|
|
67
|
+
node .opencode/skills/forge/scripts/detect.mjs
|
|
68
|
+
|
|
69
|
+
# Solo errores y críticos
|
|
70
|
+
node .opencode/skills/forge/scripts/detect.mjs --severity ERROR
|
|
71
|
+
|
|
72
|
+
# Solo un tipo específico
|
|
73
|
+
node .opencode/skills/forge/scripts/detect.mjs --type layers
|
|
74
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Reforge
|
|
2
|
+
|
|
3
|
+
Refactoriza la arquitectura de un feature o de un componente de platform/shared/infra.
|
|
4
|
+
|
|
5
|
+
## Cuándo usarlo
|
|
6
|
+
|
|
7
|
+
- Un feature tiene violaciones arquitectónicas
|
|
8
|
+
- Un feature legacy necesita reestructurarse
|
|
9
|
+
- Un componente de platform necesita refinarse
|
|
10
|
+
- Un componente de shared necesita rediseñarse
|
|
11
|
+
- El grafo arquitectónico muestra violaciones que requieren intervención
|
|
12
|
+
|
|
13
|
+
## Flujo básico
|
|
14
|
+
|
|
15
|
+
1. Ejecutar `forge inspect` para obtener estado actual
|
|
16
|
+
2. Identificar violaciones en el grafo arquitectónico
|
|
17
|
+
3. Identificar ownership problemático (huérfanos, duplicados, mal ubicados)
|
|
18
|
+
4. Decidir las acciones correctivas en orden:
|
|
19
|
+
- Violaciones CRITICAL primero (R1, R2, R5, R6)
|
|
20
|
+
- Violaciones ERROR después (R3, R4, R8, R9)
|
|
21
|
+
- Ownership problemático
|
|
22
|
+
- Warnings
|
|
23
|
+
5. Ejecutar cambios en el feature o componente
|
|
24
|
+
6. Ejecutar `forge quench` para verificar
|
|
25
|
+
7. Actualizar `ARCHITECTURE.md`
|
|
26
|
+
|
|
27
|
+
## Refactorización multi-capa
|
|
28
|
+
|
|
29
|
+
Reforge ahora considera las cuatro capas arquitectónicas:
|
|
30
|
+
|
|
31
|
+
- **Platform**: Mover componentes técnicos sueltos a `src/platform/`
|
|
32
|
+
- **Features**: Reestructurar features con violaciones
|
|
33
|
+
- **Shared**: Extraer código duplicado a `src/shared/`
|
|
34
|
+
- **Infra**: Organizar implementaciones concretas en `src/infra/`
|
|
35
|
+
|
|
36
|
+
## Post-refactorización
|
|
37
|
+
|
|
38
|
+
- `forge inspect` — confirmar mejora en puntuación
|
|
39
|
+
- `forge chain` — verificar que no se introdujeron ciclos
|
|
40
|
+
- `forge armorer` — verificar ownership saludable
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Relocate
|
|
2
|
+
|
|
3
|
+
Migra un feature existente desde estructura legacy hacia la arquitectura basada en features.
|
|
4
|
+
|
|
5
|
+
También puede migrar componentes legacy a los layers Platform, Shared o Infrastructure.
|
|
6
|
+
|
|
7
|
+
## Cuándo usarlo
|
|
8
|
+
|
|
9
|
+
- El proyecto tiene código legacy fuera de `src/features/`
|
|
10
|
+
- Hay componentes en directorios legacy que deben migrarse a:
|
|
11
|
+
- `src/platform/` (si es infraestructura técnica global)
|
|
12
|
+
- `src/shared/` (si es código reutilizable puro)
|
|
13
|
+
- `src/infra/` (si es implementación concreta)
|
|
14
|
+
- `src/features/<name>/` (si es lógica de negocio)
|
|
15
|
+
|
|
16
|
+
## Flujo
|
|
17
|
+
|
|
18
|
+
1. Identificar el componente a migrar
|
|
19
|
+
2. Clasificarlo en el layer correcto:
|
|
20
|
+
- Configuración, servidor, logger, DI → **Platform**
|
|
21
|
+
- Lógica de negocio, entidades, casos de uso → **Feature**
|
|
22
|
+
- Código reutilizable sin dependencias externas → **Shared**
|
|
23
|
+
- Implementaciones de BD, servicios externos → **Infra**
|
|
24
|
+
3. Crear la estructura target según el layer
|
|
25
|
+
4. Migrar archivos manteniendo la lógica intacta
|
|
26
|
+
5. Actualizar imports
|
|
27
|
+
6. Eliminar estructura legacy
|
|
28
|
+
7. Ejecutar `forge quench` para verificar
|
|
29
|
+
8. Actualizar `ARCHITECTURE.md`
|
|
30
|
+
|
|
31
|
+
## Estrategias por layer
|
|
32
|
+
|
|
33
|
+
| Layer | Desde | Hacia |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| Platform | `src/config/`, `src/setting/`, `src/middleware/` | `src/platform/<name>/` |
|
|
36
|
+
| Feature | `src/application/use-cases/<name>/` | `src/features/<name>/` |
|
|
37
|
+
| Shared | `src/utils/`, `src/helpers/`, `src/lib/` | `src/shared/<name>/` |
|
|
38
|
+
| Infra | `src/database/`, `src/providers/` | `src/infra/<name>/` |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Smelt
|
|
2
|
+
|
|
3
|
+
Extrae código reutilizable desde features hacia `shared/`.
|
|
4
|
+
|
|
5
|
+
## Cuándo usarlo
|
|
6
|
+
|
|
7
|
+
- Dos o más features usan el mismo tipo, interfaz o utility
|
|
8
|
+
- Un feature contiene lógica que no es de negocio y podría ser compartida
|
|
9
|
+
- Se detecta duplicación de código entre features
|
|
10
|
+
- Se necesita mover un tipo o utilidad a `shared/` para mantener el principio DRY
|
|
11
|
+
|
|
12
|
+
## Flujo
|
|
13
|
+
|
|
14
|
+
1. Identificar el código candidato a extraer
|
|
15
|
+
2. Verificar que no tenga dependencias de infraestructura
|
|
16
|
+
3. Verificar que no tenga lógica de negocio específica de un feature
|
|
17
|
+
4. Mover el código a `src/shared/<category>/`:
|
|
18
|
+
- Tipos → `src/shared/types/`
|
|
19
|
+
- Interfaces → `src/shared/contracts/`
|
|
20
|
+
- Errores → `src/shared/errors/`
|
|
21
|
+
- Utilidades → `src/shared/utils/`
|
|
22
|
+
5. Actualizar todos los imports en los features que lo usaban
|
|
23
|
+
6. Ejecutar `forge quench` para verificar que no hay violaciones
|
|
24
|
+
7. Actualizar `ARCHITECTURE.md`
|
|
25
|
+
|
|
26
|
+
## Reglas
|
|
27
|
+
|
|
28
|
+
- El código extraído NO debe importar de features
|
|
29
|
+
- El código extraído NO debe importar de infraestructura
|
|
30
|
+
- El código extraído debe ser puro o depender solo de otros componentes shared
|
|
31
|
+
- Si el código depende de platform, considerar moverlo a platform en lugar de shared
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Temper
|
|
2
|
+
|
|
3
|
+
Templa la arquitectura aplicando reglas de inyección de dependencias, seguridad y consistencia.
|
|
4
|
+
|
|
5
|
+
## Cuándo usarlo
|
|
6
|
+
|
|
7
|
+
- El proyecto tiene código legacy con DI manual que necesita migrar a contenedor
|
|
8
|
+
- Se detectaron violaciones de inyección de dependencias
|
|
9
|
+
- El proyecto usa strings como tokens de DI
|
|
10
|
+
- Hay container.resolve() esparcido en la lógica de negocio
|
|
11
|
+
|
|
12
|
+
## Reglas de DI
|
|
13
|
+
|
|
14
|
+
### Universal (aplica a cualquier perfil)
|
|
15
|
+
|
|
16
|
+
| Regla | Severidad |
|
|
17
|
+
|---|---|
|
|
18
|
+
| Siempre inyección por constructor | ERROR |
|
|
19
|
+
| Sin service locators | ERROR |
|
|
20
|
+
| Sin singletons globales | WARNING |
|
|
21
|
+
| Sin new de dependencias en clases inyectadas | WARNING |
|
|
22
|
+
|
|
23
|
+
### Para perfiles con tsyringe
|
|
24
|
+
|
|
25
|
+
- `@injectable()` en toda clase con dependencias
|
|
26
|
+
- `@inject(Token)` con tokens de clase, nunca strings
|
|
27
|
+
- `container.resolve()` solo en bootstrap (app.ts, routes)
|
|
28
|
+
- `container.registerSingleton()` para interfaces en app.ts
|
|
29
|
+
- `container.registerInstance()` para mocks en tests
|
|
30
|
+
|
|
31
|
+
### Para DI manual
|
|
32
|
+
|
|
33
|
+
- Crear instancias explícitamente en bootstrap
|
|
34
|
+
- Pasar dependencias por constructor
|
|
35
|
+
- Usar factories o functions para lazy initialization
|
|
36
|
+
|
|
37
|
+
### Para NestJS
|
|
38
|
+
|
|
39
|
+
- Usar `@Injectable()` de NestJS
|
|
40
|
+
- Configurar módulos con `providers` y `exports`
|
|
41
|
+
- Usar `@InjectRepository()` para TypeORM
|
|
42
|
+
|
|
43
|
+
## Prohibiciones
|
|
44
|
+
|
|
45
|
+
- ❌ `container.resolve()` dentro de use cases, entities o adapters
|
|
46
|
+
- ❌ `new UseCase(dep1, dep2)` en features migrados a contenedor
|
|
47
|
+
- ❌ Importar tsyringe en archivos de dominio
|
|
48
|
+
- ❌ Mezclar DI manual y contenedor en el mismo feature
|
|
49
|
+
- ❌ Proxies automáticos o decoradores ocultos que dificulten el rastreo
|