@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.
Files changed (56) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +9 -0
  3. package/README.md +338 -0
  4. package/logo.png +0 -0
  5. package/package.json +47 -0
  6. package/skills/forge/SKILL.md +207 -0
  7. package/skills/forge/command/forge.md +110 -0
  8. package/skills/forge/profiles/express-mongodb.md +289 -0
  9. package/skills/forge/profiles/express-postgres.md +164 -0
  10. package/skills/forge/profiles/express-prisma.md +116 -0
  11. package/skills/forge/profiles/fastify-postgres.md +110 -0
  12. package/skills/forge/profiles/nestjs-prisma.md +160 -0
  13. package/skills/forge/reference/cast.md +77 -0
  14. package/skills/forge/reference/chain.md +73 -0
  15. package/skills/forge/reference/forge.md +44 -0
  16. package/skills/forge/reference/inscribe.md +129 -0
  17. package/skills/forge/reference/inspect.md +58 -0
  18. package/skills/forge/reference/patterns.md +108 -0
  19. package/skills/forge/reference/principles.md +29 -0
  20. package/skills/forge/reference/quench.md +74 -0
  21. package/skills/forge/reference/reforge.md +40 -0
  22. package/skills/forge/reference/relocate.md +38 -0
  23. package/skills/forge/reference/smelt.md +31 -0
  24. package/skills/forge/reference/temper.md +49 -0
  25. package/skills/forge/scripts/architecture.mjs +176 -0
  26. package/skills/forge/scripts/armorer.mjs +421 -0
  27. package/skills/forge/scripts/bootstrap.mjs +187 -0
  28. package/skills/forge/scripts/chain.mjs +258 -0
  29. package/skills/forge/scripts/context.mjs +237 -0
  30. package/skills/forge/scripts/detect.mjs +843 -0
  31. package/skills/forge/scripts/graph.mjs +594 -0
  32. package/skills/forge/scripts/inspect.mjs +193 -0
  33. package/skills/forge/scripts/profile.mjs +92 -0
  34. package/skills/forge/templates/feature/controller.ts.md +66 -0
  35. package/skills/forge/templates/feature/entity.ts.md +11 -0
  36. package/skills/forge/templates/feature/mapper.ts.md +18 -0
  37. package/skills/forge/templates/feature/repository-impl.ts.md +59 -0
  38. package/skills/forge/templates/feature/repository-interface.ts.md +12 -0
  39. package/skills/forge/templates/feature/routes.ts.md +17 -0
  40. package/skills/forge/templates/feature/schema.ts.md +16 -0
  41. package/skills/forge/templates/feature/use-case.ts.md +19 -0
  42. package/skills/forge/templates/infra/mail.ts.md +31 -0
  43. package/skills/forge/templates/infra/mongodb.ts.md +12 -0
  44. package/skills/forge/templates/infra/prisma.ts.md +21 -0
  45. package/skills/forge/templates/infra/redis.ts.md +30 -0
  46. package/skills/forge/templates/platform/config.ts.md +37 -0
  47. package/skills/forge/templates/platform/database.ts.md +40 -0
  48. package/skills/forge/templates/platform/di.ts.md +18 -0
  49. package/skills/forge/templates/platform/http.ts.md +29 -0
  50. package/skills/forge/templates/platform/logger.ts.md +38 -0
  51. package/skills/forge/templates/platform/server.ts.md +25 -0
  52. package/skills/forge/templates/shared/contract.ts.md +20 -0
  53. package/skills/forge/templates/shared/error.ts.md +27 -0
  54. package/skills/forge/templates/shared/type.ts.md +18 -0
  55. package/skills/forge/templates/shared/util.ts.md +23 -0
  56. package/src/cli.js +179 -0
@@ -0,0 +1,207 @@
1
+ ---
2
+ name: forge
3
+ description: >
4
+ Architecture Operating System especializado en diseñar, construir, auditar,
5
+ proteger y evolucionar arquitecturas backend escalables basadas en features
6
+ (vertical slices), hexagonal architecture y DDD pragmático. Triggers:
7
+ "arquitectura", "migrar", "refactorizar", "features", "hexagonal",
8
+ "puertos y adaptadores", "clean architecture", "cast", "inspect",
9
+ "quench", "chain", "grafo", "graph", "nodo", "architecture graph",
10
+ "violaciones", "ownership", "platform", "infraestructura". Excluye
11
+ infraestructura (Docker, CI/CD), optimización de queries y cambios de
12
+ lógica de negocio sin reestructuración.
13
+ ---
14
+
15
+ # Forge — Backend Architecture Operating System
16
+
17
+ Forge es un **sistema operativo arquitectónico**. Diseña, construye, audita, protege y evoluciona arquitecturas backend completas. Opera sobre cualquier stack moderno modelando **cuatro dominios arquitectónicos**: **Platform**, **Features**, **Shared** e **Infrastructure**.
18
+
19
+ No es un template ni una guía. Es un orquestador.
20
+
21
+ ---
22
+
23
+ ## Modelo Arquitectónico
24
+
25
+ Todo backend se modela en cuatro dominios:
26
+
27
+ | Layer | Propósito | Ejemplos |
28
+ |-------|-----------|----------|
29
+ | **Platform** | Backbone técnico global | config, database, http, server, logger, cache, security, events, di |
30
+ | **Features** | Capacidades de negocio | auth, users, payments |
31
+ | **Shared** | Componentes reutilizables puros | errors, contracts, types, utils |
32
+ | **Infrastructure** | Implementaciones concretas | prisma, mongodb, redis, mail |
33
+
34
+ ### Dependency Rules
35
+
36
+ Permitido:
37
+ - `feature → platform`
38
+ - `feature → shared`
39
+ - `platform → infra`
40
+ - `adapter → infra`
41
+ - `feature → domain`
42
+
43
+ Prohibido:
44
+ - `feature → infra`
45
+ - `platform → feature`
46
+ - `shared → feature`
47
+ - `shared → infra`
48
+ - `domain → infra`
49
+ - `domain → platform`
50
+ - `infra → feature`
51
+
52
+ ---
53
+
54
+ ## Architecture Guidance
55
+
56
+ Ver `reference/principles.md` para el manifiesto completo y los 12 principios inquebrantables.
57
+ Ver `reference/patterns.md` para las convenciones de nomenclatura (PascalCase.artifact, kebab dirs, etc.).
58
+ En esencia:
59
+
60
+ | Principio | Regla |
61
+ |---|---|
62
+ | Cuatro dominios arquitectónicos | Platform, Features, Shared, Infrastructure con ownership estricto |
63
+ | Unidades autónomas | Cada feature es dueño de su dominio, aplicación y adapters |
64
+ | Dependencias unidireccionales | adapters → application → domain → (nada) |
65
+ | Cero lógica en controllers | El controller parsea, delega y responde |
66
+ | Cero BD fuera de repositorios | Los repositories son la única puerta a datos |
67
+ | DI disciplinada | Constructor injection, sin service locators |
68
+ | Cero acoplamiento directo entre features | Siempre vía interfaces inyectadas |
69
+ | Ownership obligatorio | Cada componente tiene un único propietario arquitectónico |
70
+
71
+ ---
72
+
73
+ ## Boot Sequence (OBLIGATORIO — ejecutar siempre antes de responder)
74
+
75
+ ANTES de cualquier acción, Forge DEBE ejecutar esta secuencia. Si no lo haces, puedes dar respuestas incorrectas:
76
+
77
+ 1. **context.mjs** — Detectar stack, platform, features, shared, infra, grafo, estado
78
+ 2. **armorer.mjs** — Detectar ownership, huérfanos, duplicados, mal ubicados
79
+ 3. **profile.mjs** — Determinar perfil tecnológico
80
+ 4. **graph.mjs** — Construir grafo arquitectónico global (4 capas + 9 reglas)
81
+ 5. **chain.mjs** — Analizar dependencias multi-capa
82
+ 6. **inspect.mjs** — Auditoría completa con ownership + platform
83
+ 7. **architecture.mjs** — Generar/actualizar ARCHITECTURE.md
84
+ 8. **Ejecutar comando solicitado** — cast, quench, temper, etc.
85
+ 9. **Actualizar ARCHITECTURE.md** — Reflejar nuevo estado
86
+
87
+ ```bash
88
+ # Template de setup que debes ejecutar:
89
+ ctx=$(node .opencode/skills/forge/scripts/context.mjs --json 2>/dev/null)
90
+ armorer=$(node .opencode/skills/forge/scripts/armorer.mjs --json 2>/dev/null)
91
+ profile=$(node .opencode/skills/forge/scripts/profile.mjs --extended 2>/dev/null)
92
+ graph=$(node .opencode/skills/forge/scripts/graph.mjs --json 2>/dev/null)
93
+ deps=$(node .opencode/skills/forge/scripts/chain.mjs --json 2>/dev/null)
94
+ inspect=$(node .opencode/skills/forge/scripts/inspect.mjs --json 2>/dev/null)
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Command Routing
100
+
101
+ | Lenguaje natural | Comando | Archivo |
102
+ |---|---|---|
103
+ | "inicializar", "setup", "empezar" | `forge` | `reference/forge.md` |
104
+ | "crear feature", "nuevo dominio" | `cast` | `reference/cast.md` |
105
+ | "inspeccionar", "diagnóstico", "evaluar" | `inspect` | `reference/inspect.md` |
106
+ | "trasladar", "mover", "reestructurar feature" | `relocate` | `reference/relocate.md` |
107
+ | "refactorizar", "rediseñar", "cambiar estructura" | `reforge` | `reference/reforge.md` |
108
+ | "verificar", "quench", "checklist" | `quench` | `reference/quench.md` |
109
+ | "templar", "endurecer", "mejorar" | `temper` | `reference/temper.md` |
110
+ | "cadena", "grafo", "acoplamiento" | `chain` | `scripts/chain.mjs` |
111
+ | "inscribir", "grabar", "ARCHITECTURE.md" | `inscribe` | `reference/inscribe.md` |
112
+ | "grafo", "graph", "nodo", "violaciones", "risk score" | `graph` | `scripts/graph.mjs` |
113
+ | "fundir", "compartir", "mover a shared" | `smelt` | `reference/smelt.md` |
114
+ | "ownership", "huérfanos", "armorer" | `inspect` | (incluido en auditoría) |
115
+
116
+ ---
117
+
118
+ ## Execution Flow
119
+
120
+ Para cada comando, Forge sigue este flujo:
121
+
122
+ 1. **Contexto**: Ejecutar `context.mjs` + `armorer.mjs` + `profile.mjs`
123
+ 2. **Grafo**: Ejecutar `graph.mjs` + `chain.mjs`
124
+ 3. **Auditoría**: Ejecutar `inspect.mjs`
125
+ 4. **Referencia**: Cargar `reference/<command>.md`
126
+ 5. **Ejecutar**: Aplicar el flujo definido en la referencia, usando los scripts según corresponda
127
+ 6. **Verificar**: Ejecutar `scripts/detect.mjs` para verificar que no se introdujeron violaciones
128
+ 7. **Actualizar ARCHITECTURE.md**: Reflejar el nuevo estado (`architecture.mjs`)
129
+ 8. **Reportar**: Mostrar resultado al usuario con severidades
130
+
131
+ ---
132
+
133
+ ## Routing Rules
134
+
135
+ - Si el lenguaje natural matchea exactamente un comando, ejecutarlo directamente.
136
+ - Si hay ambigüedad, preguntar al usuario: "¿Quieres decir: cast, relocate o reforge?"
137
+ - Si el comando requiere un perfil que no está detectado, preguntar antes de continuar.
138
+ - Si el proyecto no tiene `src/features/` y el comando es `cast`, sugerir `forge` primero.
139
+ - Si el proyecto no tiene `src/platform/`, ejecutar `bootstrapPlatform()` automáticamente.
140
+ - Si `ARCHITECTURE.md` está desactualizado (fecha de auditoría > 7 días), sugerir `forge inscribe`.
141
+ - Todos los resultados se muestran con severidades: `[CRITICAL]`, `[ERROR]`, `[WARNING]`, `[INFO]`, `[SUGGESTION]`.
142
+
143
+ ## ARCHITECTURE.md
144
+
145
+ Forge mantiene un archivo `ARCHITECTURE.md` en la raíz del proyecto con el contexto persistente. Contiene:
146
+
147
+ ```md
148
+ # Architecture State
149
+
150
+ Project Name: <name>
151
+ Framework: <detectado>
152
+ Runtime: <detectado>
153
+ Database: <detectado>
154
+ ORM: <detectado>
155
+ DI Strategy: <detectado>
156
+ Profile: <detectado>
157
+ Architecture: hexagonal-feature (Platform + Features + Shared + Infra)
158
+ Last Audit: <fecha> (score: <puntaje>)
159
+
160
+ ## Platform
161
+ - platform/config/
162
+ - platform/server/
163
+ ...
164
+
165
+ ## Features
166
+ - features/users/
167
+ ...
168
+
169
+ ## Shared
170
+ - shared/errors/
171
+ ...
172
+
173
+ ## Infrastructure
174
+ - infra/prisma/
175
+ ...
176
+
177
+ ## Ownership
178
+ Health: healthy | degraded | critical
179
+ Score: 0-100
180
+ Orphans: 0
181
+ Duplicates: 0
182
+ Misplaced: 0
183
+
184
+ ## Architecture Graph
185
+ ...
186
+
187
+ ## Dependency Health
188
+ ...
189
+ ```
190
+
191
+ El agente DEBE leer este archivo al inicio de cada interacción y actualizarlo al finalizar cada comando.
192
+
193
+ ---
194
+
195
+ ## Module Index
196
+
197
+ | Módulo | Propósito |
198
+ |---|---|
199
+ | `reference/principles.md` | Manifiesto y 12 principios inquebrantables |
200
+ | `reference/patterns.md` | Convenciones de nomenclatura globales (PascalCase.artifact, kebab dirs, etc.) |
201
+ | `profiles/` | Perfiles tecnológicos detallados (Express, Fastify, NestJS, etc.) |
202
+ | `scripts/` | Scripts de análisis: context, detect, inspect, chain, profile, graph, architecture, armorer, bootstrap |
203
+ | `templates/feature/` | Templates de feature (entity, repository, uc, controller, routes, schema, mapper) |
204
+ | `templates/platform/` | Templates de platform (config, server, database, logger, http, di) |
205
+ | `templates/shared/` | Templates de shared (errors, contracts, types, utils) |
206
+ | `templates/infra/` | Templates de infra (prisma, mongodb, redis, mail) |
207
+ | `command/forge.md` | Definición del comando `/forge` para opencode |
@@ -0,0 +1,110 @@
1
+ ---
2
+ description: Forge — Backend Architecture OS. Subcomandos: forge, cast, inspect, relocate, reforge, quench, temper, chain, inscribe, smelt.
3
+ agent: build
4
+ ---
5
+
6
+ Ejecuta herramientas de Forge según el subcomando especificado en $ARGUMENTS.
7
+
8
+ ## Build
9
+
10
+ ### forge
11
+
12
+ Inicializa el proyecto arquitectónicamente (incluye platform, shared, infra).
13
+
14
+ ```
15
+ node .opencode/skills/forge/scripts/context.mjs
16
+ node .opencode/skills/forge/scripts/bootstrap.mjs
17
+ node .opencode/skills/forge/scripts/armorer.mjs
18
+ ```
19
+
20
+ ### cast
21
+
22
+ Crea un nuevo feature (verifica platform/shared/infra primero).
23
+
24
+ ### relocate
25
+
26
+ Migra un feature existente.
27
+
28
+ ### inscribe
29
+
30
+ Genera ARCHITECTURE.md con grafo arquitectónico, ownership y platform.
31
+
32
+ ```
33
+ node .opencode/skills/forge/scripts/architecture.mjs
34
+ ```
35
+
36
+ ### architecture
37
+
38
+ Construye el grafo arquitectónico del proyecto (4 capas: platform, feature, shared, infra).
39
+
40
+ ```
41
+ node .opencode/skills/forge/scripts/graph.mjs
42
+ ```
43
+
44
+ Para salida JSON:
45
+
46
+ ```
47
+ node .opencode/skills/forge/scripts/graph.mjs --json
48
+ ```
49
+
50
+ ### smelt
51
+
52
+ Extrae código reutilizable a shared/.
53
+
54
+ ### bootstrap
55
+
56
+ Inicializa platform, shared e infra layers (interno, se ejecuta automáticamente).
57
+
58
+ ```
59
+ node .opencode/skills/forge/scripts/bootstrap.mjs
60
+ ```
61
+
62
+ ## Evaluate
63
+
64
+ ### inspect
65
+
66
+ Inspecciona la conformidad arquitectónica (incluye ownership y platform).
67
+
68
+ ```
69
+ node .opencode/skills/forge/scripts/inspect.mjs
70
+ ```
71
+
72
+ Para salida JSON:
73
+
74
+ ```
75
+ node .opencode/skills/forge/scripts/inspect.mjs --json
76
+ ```
77
+
78
+ ### quench
79
+
80
+ Verifica reglas arquitectónicas.
81
+
82
+ ```
83
+ node .opencode/skills/forge/scripts/detect.mjs
84
+ ```
85
+
86
+ ### chain
87
+
88
+ Analiza dependencias multi-capa (platform, features, shared, infra).
89
+
90
+ ```
91
+ node .opencode/skills/forge/scripts/chain.mjs
92
+ ```
93
+
94
+ ### armorer
95
+
96
+ Detecta ownership, huérfanos, duplicados y mal ubicados.
97
+
98
+ ```
99
+ node .opencode/skills/forge/scripts/armorer.mjs
100
+ ```
101
+
102
+ ## Refine
103
+
104
+ ### reforge
105
+
106
+ Refactoriza la arquitectura de un feature.
107
+
108
+ ### temper
109
+
110
+ Fortalece la arquitectura (DI, seguridad, consistencia).
@@ -0,0 +1,289 @@
1
+ # Profile: Express + MongoDB + Mongoose
2
+
3
+ ## Metadata
4
+
5
+ ```yaml
6
+ framework: Express
7
+ runtime: Node 20+
8
+ database: MongoDB
9
+ orm: Mongoose
10
+ di_strategy: tsyringe
11
+ architecture: hexagonal-feature
12
+ ```
13
+
14
+ ## Project Structure
15
+
16
+ ```
17
+ ├── src/
18
+ │ ├── features/
19
+ │ │ └── <domain>/
20
+ │ │ ├── domain/
21
+ │ │ │ ├── <Domain>.entity.ts # Interfaz pura del dominio
22
+ │ │ │ └── I<Domain>Repository.ts # Puerto de repositorio
23
+ │ │ ├── application/
24
+ │ │ │ ├── use-cases/
25
+ │ │ │ │ ├── Create.ts / Add.ts
26
+ │ │ │ │ ├── Get.ts / FindById.ts
27
+ │ │ │ │ ├── List.ts
28
+ │ │ │ │ ├── Update.ts
29
+ │ │ │ │ └── Delete.ts
30
+ │ │ │ ├── dto/ # Data Transfer Objects
31
+ │ │ │ │ └── <Domain>DTO.ts
32
+ │ │ │ └── mappers/
33
+ │ │ │ └── <Domain>.mapper.ts # Dominio ↔ Persistencia
34
+ │ │ └── adapters/
35
+ │ │ ├── in/http/
36
+ │ │ │ ├── <Domain>Controller.ts
37
+ │ │ │ └── <domain>.routes.ts
38
+ │ │ └── out/
39
+ │ │ └── persistence/
40
+ │ │ ├── <Domain>Repository.ts
41
+ │ │ └── <Domain>Schema.ts
42
+ │ ├── shared/
43
+ │ │ ├── errors/
44
+ │ │ ├── port/ # Puertos globales (ILogger, IHttpClient, etc.)
45
+ │ │ └── utils/
46
+ │ ├── infrastructure/
47
+ │ │ └── db.ts # Conexión MongoDB
48
+ │ ├── adapters/out/ # Adapters transversales
49
+ │ │ ├── email/
50
+ │ │ ├── scheduler/
51
+ │ │ └── auth/
52
+ │ ├── setting/ # Configuración global
53
+ │ ├── app.ts # Express app + DI container bootstrap
54
+ │ └── server.ts # Entry point
55
+ ```
56
+
57
+ ## DI Setup (tsyringe)
58
+
59
+ ### Dependencies
60
+
61
+ ```json
62
+ {
63
+ "dependencies": {
64
+ "tsyringe": "^4.8.0",
65
+ "reflect-metadata": "^0.2.2"
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### tsconfig
71
+
72
+ ```jsonc
73
+ {
74
+ "compilerOptions": {
75
+ "experimentalDecorators": true,
76
+ "emitDecoratorMetadata": true
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### Entry point (server.ts)
82
+
83
+ ```typescript
84
+ import "reflect-metadata"; // Antes que cualquier otro import
85
+ import { createApp } from "./app.js";
86
+ // ...
87
+ ```
88
+
89
+ ### Container registration (app.ts)
90
+
91
+ ```typescript
92
+ import { container } from "tsyringe";
93
+
94
+ // Interfaces se registran como singletons
95
+ container.registerSingleton<ICreditRepository>(
96
+ ICreditRepository as symbol,
97
+ CreditRepository
98
+ );
99
+ ```
100
+
101
+ ## DI Rules
102
+
103
+ - `@injectable()` en toda clase con dependencias (use cases, controllers, repositories)
104
+ - `@inject(Token)` con tokens de clase, nunca strings
105
+ - `container.resolve()` solo en bootstrap (app.ts, routes)
106
+ - Prohibido `container.resolve()` en use cases, entities o adapters
107
+ - Prohibido `new UseCase(dep1, dep2)` en features migrados a DI
108
+
109
+ ## Routes & Controllers
110
+
111
+ ### Controller pattern
112
+
113
+ ```typescript
114
+ @injectable()
115
+ export class CreditController {
116
+ constructor(
117
+ @inject(AddCredit) private readonly addCredit: AddCredit,
118
+ @inject(GetCredit) private readonly getCredit: GetCredit,
119
+ ) {}
120
+
121
+ add = async (req: Request, res: Response, next: NextFunction) => {
122
+ try {
123
+ const data = req.body;
124
+ const result = await this.addCredit.execute(data);
125
+ res.status(201).json({ data: result });
126
+ } catch (error) {
127
+ next(error);
128
+ }
129
+ };
130
+ }
131
+ ```
132
+
133
+ ### Routes pattern
134
+
135
+ ```typescript
136
+ import { Router } from "express";
137
+ import { container } from "tsyringe";
138
+ import { CreditController } from "./CreditController.js";
139
+
140
+ const router = Router();
141
+ const controller = container.resolve(CreditController);
142
+
143
+ router.post("/", controller.add);
144
+ router.get("/:id", controller.getById);
145
+
146
+ export default router;
147
+ ```
148
+
149
+ ## Persistence (Mongoose)
150
+
151
+ ### Schema pattern
152
+
153
+ ```typescript
154
+ import { model, Schema } from "mongoose";
155
+ import type { Credit } from "../../../domain/Credit.entity.js";
156
+
157
+ const creditSchema = new Schema<Credit>(
158
+ { /* fields */ },
159
+ { timestamps: true }
160
+ );
161
+
162
+ export default model<Credit>("Credit", creditSchema);
163
+ ```
164
+
165
+ ### Repository pattern
166
+
167
+ ```typescript
168
+ @injectable()
169
+ export class CreditRepository implements ICreditRepository {
170
+ async create(data: Partial<Credit>): Promise<Credit> {
171
+ const doc = await CreditModel.create(data);
172
+ return CreditMapper.toDomain(doc.toObject());
173
+ }
174
+
175
+ async findById(id: string): Promise<Credit | null> {
176
+ const doc = await CreditModel.findById(id).lean();
177
+ return doc ? CreditMapper.toDomain(doc) : null;
178
+ }
179
+ }
180
+ ```
181
+
182
+ ### Transactions
183
+
184
+ ```typescript
185
+ import { ClientSession } from "mongoose";
186
+
187
+ @injectable()
188
+ export class CreditRepository implements ICreditRepository {
189
+ async create(data: Partial<Credit>, session?: ClientSession): Promise<Credit> {
190
+ const doc = session
191
+ ? (await CreditModel.create([data], { session }))[0]
192
+ : await CreditModel.create(data);
193
+ return CreditMapper.toDomain(doc.toObject());
194
+ }
195
+ }
196
+ ```
197
+
198
+ Usar transacciones desde el use case:
199
+
200
+ ```typescript
201
+ import mongoose from "mongoose";
202
+
203
+ @injectable()
204
+ export class CreateCredit {
205
+ async execute(data: CreditInput): Promise<Credit> {
206
+ const session = await mongoose.startSession();
207
+ try {
208
+ session.startTransaction();
209
+ const credit = await this.creditRepo.create(data, session);
210
+ await session.commitTransaction();
211
+ return credit;
212
+ } catch (error) {
213
+ await session.abortTransaction();
214
+ throw error;
215
+ } finally {
216
+ session.endSession();
217
+ }
218
+ }
219
+ }
220
+ ```
221
+
222
+ ## Testing Strategy
223
+
224
+ ### Unit test (use case)
225
+
226
+ ```typescript
227
+ import "reflect-metadata";
228
+ import { container } from "tsyringe";
229
+ import { ICreditRepository } from "@/features/credit/domain/ICreditRepository.js";
230
+
231
+ const mockRepo = { create: jest.fn() };
232
+
233
+ beforeEach(() => {
234
+ container.registerInstance(ICreditRepository as symbol, mockRepo);
235
+ });
236
+
237
+ afterEach(() => {
238
+ container.clearInstances();
239
+ });
240
+
241
+ it("creates a credit", async () => {
242
+ mockRepo.create.mockResolvedValue({ id: "1" });
243
+ const useCase = container.resolve(AddCredit);
244
+ const result = await useCase.execute({ amount: 100 });
245
+ expect(result.id).toBe("1");
246
+ });
247
+ ```
248
+
249
+ ### Integration test (repository)
250
+
251
+ ```typescript
252
+ import mongoose from "mongoose";
253
+ import { CreditRepository } from "./CreditRepository.js";
254
+
255
+ beforeAll(async () => {
256
+ await mongoose.connect(global.__MONGO_URI__);
257
+ });
258
+
259
+ afterAll(async () => {
260
+ await mongoose.disconnect();
261
+ });
262
+
263
+ it("persists a credit", async () => {
264
+ const repo = new CreditRepository();
265
+ const credit = await repo.create({ amount: 100 });
266
+ expect(credit.id).toBeDefined();
267
+ });
268
+ ```
269
+
270
+ ## Naming Conventions
271
+
272
+ | Elemento | Convención | Ejemplo |
273
+ |---|---|---|
274
+ | Entidad (archivo) | `<Domain>.entity.ts` | `Credit.entity.ts` |
275
+ | Interfaz repositorio | `I<Domain>Repository.ts` | `ICreditRepository.ts` |
276
+ | Use case (archivo) | `Create.ts`, `Get.ts`, etc. | `Create.ts` |
277
+ | Controller | `<Domain>Controller.ts` | `CreditController.ts` |
278
+ | Routes | `<domain>.routes.ts` | `credit.routes.ts` |
279
+ | Schema | `<Domain>Schema.ts` | `CreditSchema.ts` |
280
+ | Repository impl | `<Domain>Repository.ts` | `CreditRepository.ts` |
281
+ | Mapper | `<Domain>.mapper.ts` | `Credit.mapper.ts` |
282
+ | DTO | `<Domain>DTO.ts` | `CreditDTO.ts` |
283
+
284
+ ## Imports
285
+
286
+ - Usar `@/` alias para imports absolutos (mapeado a `src/`)
287
+ - Extensión `.js` en imports locales (ESM)
288
+ - En imports dentro del mismo feature, usar rutas relativas: `../../domain/X.entity.js`
289
+ - Para imports entre features, inyectar la interfaz, nunca importar directamente