@ronaldjdevfs/forge 1.3.1 → 1.3.3
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 +11 -4
- package/package.json +1 -1
- package/skills/forge/scripts/detect.mjs +18 -6
- package/skills/forge/scripts/rename.mjs +77 -22
- package/skills/forge/templates/feature/acl-repository.ts.md +2 -2
- package/skills/forge/templates/feature/acl-translator.ts.md +1 -1
- package/skills/forge/templates/feature/entity.ts.md +1 -1
- package/skills/forge/templates/feature/mapper.ts.md +1 -1
- package/skills/forge/templates/feature/repository-impl.ts.md +2 -2
- package/skills/forge/templates/feature/repository-interface.ts.md +2 -2
- package/skills/forge/templates/feature/saga-orchestrator.ts.md +2 -2
- package/skills/forge/templates/feature/schema.ts.md +1 -1
- package/skills/forge/templates/feature/use-case.ts.md +2 -2
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.2** — Domain Subdirectory Structure & Port Support
|
|
4
4
|
|
|
5
5
|
## Forge — Backend Architecture Operating System
|
|
6
6
|
|
|
@@ -58,8 +58,10 @@ Crea un nuevo feature (vertical slice) con estructura hexagonal completa. Antes
|
|
|
58
58
|
```
|
|
59
59
|
src/features/<name>/
|
|
60
60
|
├── domain/
|
|
61
|
-
│ ├── <Domain>.entity.ts
|
|
62
|
-
│
|
|
61
|
+
│ ├── entities/ (<Domain>.entity.ts)
|
|
62
|
+
│ ├── repositories/ (I<Domain>.repository.ts)
|
|
63
|
+
│ ├── errors/ (<Domain>NotFound.error.ts)
|
|
64
|
+
│ └── events/ (<Domain>Created.event.ts)
|
|
63
65
|
├── application/
|
|
64
66
|
│ ├── use-cases/ (<Action>.uc.ts)
|
|
65
67
|
│ └── mappers/ (<Domain>.mapper.ts)
|
|
@@ -262,6 +264,10 @@ src/
|
|
|
262
264
|
├── features/ ← Capacidades de negocio
|
|
263
265
|
│ └── <name>/
|
|
264
266
|
│ ├── domain/
|
|
267
|
+
│ │ ├── entities/ (<Domain>.entity.ts)
|
|
268
|
+
│ │ ├── repositories/ (I<Domain>.repository.ts)
|
|
269
|
+
│ │ ├── errors/ (<Domain>NotFound.error.ts)
|
|
270
|
+
│ │ └── events/ (<Domain>Created.event.ts)
|
|
265
271
|
│ ├── application/
|
|
266
272
|
│ └── adapters/
|
|
267
273
|
│
|
|
@@ -291,6 +297,7 @@ src/
|
|
|
291
297
|
| Directorios | `kebab-case/` | `credit-card/`, `event-bus/` |
|
|
292
298
|
| Archivos | `<PascalCase>.<artefacto>.ts` | `User.entity.ts` |
|
|
293
299
|
| Interfaces | `I<PascalCase>.<artefacto>.ts` | `IUser.repository.ts` |
|
|
300
|
+
| Puertos (domain) | `<Name>.port.ts` | `PaymentPort.port.ts` |
|
|
294
301
|
| Use cases | `<Action>.uc.ts` | `CreateUser.uc.ts` |
|
|
295
302
|
| Clases | `PascalCase` | `UserController` |
|
|
296
303
|
| Funciones | `camelCase` | `formatDate` |
|
|
@@ -378,7 +385,7 @@ Donde vive toda la inteligencia arquitectónica:
|
|
|
378
385
|
| `reference/assay.md` | Documentación del comando assay |
|
|
379
386
|
| `reference/hooks.md` | Documentación del sistema de hooks |
|
|
380
387
|
| `profiles/` | 10 perfiles tecnológicos detallados |
|
|
381
|
-
| `templates/feature/` |
|
|
388
|
+
| `templates/feature/` | 17 templates TypeScript para features |
|
|
382
389
|
| `templates/platform/` | 6 templates para componentes de platform |
|
|
383
390
|
| `templates/shared/` | 4 templates para shared (errors, contracts, types, utils) |
|
|
384
391
|
| `templates/infra/` | 4 templates para infra (prisma, mongodb, redis, mail) |
|
package/package.json
CHANGED
|
@@ -232,17 +232,29 @@ export function checkStructure(features) {
|
|
|
232
232
|
|
|
233
233
|
if (hasSubdir(fDir, "domain")) {
|
|
234
234
|
const dDir = join(fDir, "domain");
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
const entitiesDir = join(dDir, "entities");
|
|
236
|
+
const reposDir = join(dDir, "repositories");
|
|
237
|
+
|
|
238
|
+
// Check domain/entities/ subdirectory (preferred)
|
|
239
|
+
if (hasSubdir(dDir, "entities") && hasFile(entitiesDir, /\.entity\.ts$/)) {
|
|
240
|
+
checks.push({ ...severity(`${feat}: domain/entities/<Name>.entity.ts`, SEVERITY.INFO), pass: true });
|
|
237
241
|
featScore += 3;
|
|
242
|
+
} else if (hasFile(dDir, /\.entity\.ts$/)) {
|
|
243
|
+
checks.push({ ...severity(`${feat}: domain/<Name>.entity.ts (plano — migrar a domain/entities/)`, SEVERITY.WARNING), pass: false, fix: `Mover a ${feat}/domain/entities/` });
|
|
244
|
+
featScore += 1;
|
|
238
245
|
} else {
|
|
239
|
-
checks.push({ ...severity(`${feat}: falta entity en domain/`, SEVERITY.ERROR), pass: false, fix: `Crear ${feat}
|
|
246
|
+
checks.push({ ...severity(`${feat}: falta entity en domain/`, SEVERITY.ERROR), pass: false, fix: `Crear ${feat}/domain/entities/<Name>.entity.ts` });
|
|
240
247
|
}
|
|
241
|
-
|
|
242
|
-
|
|
248
|
+
|
|
249
|
+
// Check domain/repositories/ subdirectory (preferred)
|
|
250
|
+
if (hasSubdir(dDir, "repositories") && hasFile(reposDir, /\.repository\.ts$/)) {
|
|
251
|
+
checks.push({ ...severity(`${feat}: domain/repositories/I<Name>.repository.ts`, SEVERITY.INFO), pass: true });
|
|
243
252
|
featScore += 2;
|
|
253
|
+
} else if (hasFile(dDir, /^I[A-Z]/)) {
|
|
254
|
+
checks.push({ ...severity(`${feat}: domain/I<Name>Repository.ts (plano — migrar a domain/repositories/)`, SEVERITY.WARNING), pass: false, fix: `Mover a ${feat}/domain/repositories/I<Name>.repository.ts` });
|
|
255
|
+
featScore += 1;
|
|
244
256
|
} else {
|
|
245
|
-
checks.push({ ...severity(`${feat}: falta repository interface en domain/`, SEVERITY.WARNING), pass: false, fix: `Crear I${feat.charAt(0).toUpperCase() + feat.slice(1)}
|
|
257
|
+
checks.push({ ...severity(`${feat}: falta repository interface en domain/`, SEVERITY.WARNING), pass: false, fix: `Crear ${feat}/domain/repositories/I${feat.charAt(0).toUpperCase() + feat.slice(1)}.repository.ts` });
|
|
246
258
|
}
|
|
247
259
|
} else {
|
|
248
260
|
checks.push({ ...severity(`${feat}: falta domain/`, SEVERITY.ERROR), pass: false, fix: `Crear ${feat}/domain/` });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { existsSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "fs";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "fs";
|
|
4
4
|
import { join, relative, dirname, basename, extname, parse } from "path";
|
|
5
5
|
|
|
6
6
|
const ROOT = process.cwd();
|
|
@@ -40,6 +40,13 @@ function toPascalCase(str) {
|
|
|
40
40
|
.join("");
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function toPascalCaseI(str) {
|
|
44
|
+
if (/^I[A-Za-z]/.test(str)) {
|
|
45
|
+
return "I" + toPascalCase(str.slice(1));
|
|
46
|
+
}
|
|
47
|
+
return toPascalCase(str);
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
function toCamelCase(str) {
|
|
44
51
|
const pascal = toPascalCase(str);
|
|
45
52
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
@@ -66,7 +73,10 @@ const PLATFORM_RULES = {
|
|
|
66
73
|
};
|
|
67
74
|
|
|
68
75
|
const FEATURE_SUBDIR_RULES = [
|
|
76
|
+
{ subdir: "domain/entities", pattern: "entity", case: "pascal", description: "<Name>.entity.ts" },
|
|
77
|
+
{ subdir: "domain/repositories", pattern: "repository", prefix: "I", case: "pascal", description: "I<Name>.repository.ts" },
|
|
69
78
|
{ subdir: "domain", pattern: "entity", case: "pascal", description: "<Name>.entity.ts" },
|
|
79
|
+
{ subdir: "domain", pattern: "port", case: "pascal", description: "<Name>.port.ts" },
|
|
70
80
|
{ subdir: "domain", pattern: "repository", prefix: "I", case: "pascal", description: "I<Name>.repository.ts" },
|
|
71
81
|
{ subdir: "application/use-cases", pattern: "uc", case: "pascal", description: "<Action>.uc.ts" },
|
|
72
82
|
{ subdir: "application/mappers", pattern: "mapper", case: "pascal", description: "<Name>.mapper.ts" },
|
|
@@ -178,37 +188,73 @@ export function computeExpectedName(filePath) {
|
|
|
178
188
|
if (featureSubpath === rule.subdir || featureSubpath.startsWith(rule.subdir + "/")) {
|
|
179
189
|
const stemLower = stem.toLowerCase();
|
|
180
190
|
|
|
181
|
-
// For domain/
|
|
182
|
-
|
|
183
|
-
if (rule.subdir === "domain" && rule.pattern === "entity") {
|
|
191
|
+
// For domain/entities/: <Name>.entity.ts
|
|
192
|
+
if (rule.subdir === "domain/entities") {
|
|
184
193
|
let inferredEntity;
|
|
185
194
|
if (hasSuffix(stem, "entity")) {
|
|
186
195
|
inferredEntity = stem.replace(/\.entity$/i, "");
|
|
187
196
|
} else {
|
|
188
|
-
|
|
189
|
-
inferredEntity = noEntity || featureName;
|
|
197
|
+
inferredEntity = stem;
|
|
190
198
|
}
|
|
191
|
-
const entityStem =
|
|
199
|
+
const entityStem = toPascalCaseI(inferredEntity);
|
|
192
200
|
const expectedName = `${entityStem}.entity${ext}`;
|
|
193
201
|
if (expectedName !== filename) {
|
|
194
|
-
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `feature/${featureName}/domain: ${rule.description}` };
|
|
202
|
+
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `feature/${featureName}/domain/entities: ${rule.description}` };
|
|
195
203
|
}
|
|
196
204
|
}
|
|
197
205
|
|
|
198
|
-
// For domain/
|
|
199
|
-
if (rule.subdir === "domain"
|
|
206
|
+
// For domain/repositories/: I<Name>.repository.ts
|
|
207
|
+
if (rule.subdir === "domain/repositories") {
|
|
200
208
|
const expectedStem = `I${entityName}.repository`;
|
|
201
209
|
const expectedName = `${expectedStem}${ext}`;
|
|
202
210
|
const currentMatches = stem === expectedStem;
|
|
203
211
|
if (!currentMatches) {
|
|
212
|
+
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `feature/${featureName}/domain/repositories: ${rule.description}` };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// For flat domain/entity: migrates to domain/entities/<Name>.entity.ts
|
|
217
|
+
if (rule.subdir === "domain" && rule.pattern === "entity" && featureSubpath === "domain") {
|
|
218
|
+
let inferredEntity;
|
|
219
|
+
if (hasSuffix(stem, "entity")) {
|
|
220
|
+
inferredEntity = stem.replace(/\.entity$/i, "");
|
|
221
|
+
} else {
|
|
222
|
+
const noEntity = stem.replace(/[Ee]ntity$/, "");
|
|
223
|
+
inferredEntity = noEntity || featureName;
|
|
224
|
+
}
|
|
225
|
+
const entityStem = toPascalCaseI(inferredEntity);
|
|
226
|
+
const expectedName = `${entityStem}.entity${ext}`;
|
|
227
|
+
const expectedPath = join(dirname(filePath), "entities", expectedName);
|
|
228
|
+
return { current: filePath, expected: expectedPath, relPath: join(dirname(relPath), "entities", expectedName), rule: `feature/${featureName}/domain → domain/entities: ${rule.description}` };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// For domain/port: <Name>.port.ts
|
|
232
|
+
if (rule.subdir === "domain" && rule.pattern === "port") {
|
|
233
|
+
let inferredPort;
|
|
234
|
+
if (hasSuffix(stem, "port")) {
|
|
235
|
+
inferredPort = stem.replace(/\.port$/i, "");
|
|
236
|
+
} else {
|
|
237
|
+
inferredPort = stem;
|
|
238
|
+
}
|
|
239
|
+
const portStem = toPascalCaseI(inferredPort);
|
|
240
|
+
const expectedName = `${portStem}.port${ext}`;
|
|
241
|
+
if (expectedName !== filename) {
|
|
204
242
|
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `feature/${featureName}/domain: ${rule.description}` };
|
|
205
243
|
}
|
|
206
|
-
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// For flat domain/repository: migrates to domain/repositories/I<Entity>.repository.ts
|
|
247
|
+
if (rule.subdir === "domain" && rule.pattern === "repository" && featureSubpath === "domain") {
|
|
248
|
+
const expectedStem = `I${entityName}.repository`;
|
|
249
|
+
const expectedName = `${expectedStem}${ext}`;
|
|
250
|
+
const expectedPath = join(dirname(filePath), "repositories", expectedName);
|
|
251
|
+
return { current: filePath, expected: expectedPath, relPath: join(dirname(relPath), "repositories", expectedName), rule: `feature/${featureName}/domain → domain/repositories: ${rule.description}` };
|
|
207
252
|
}
|
|
208
253
|
|
|
209
254
|
// For use-cases: <Action>.uc.ts
|
|
210
255
|
if (rule.subdir === "application/use-cases") {
|
|
211
|
-
const
|
|
256
|
+
const cleanStem = hasSuffix(stem, "uc") ? stem.replace(/\.uc$/i, "") : stem;
|
|
257
|
+
const expectedName = `${toPascalCase(cleanStem)}.uc${ext}`;
|
|
212
258
|
if (expectedName !== filename) {
|
|
213
259
|
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `feature/${featureName}/application/use-cases: ${rule.description}` };
|
|
214
260
|
}
|
|
@@ -237,15 +283,21 @@ export function computeExpectedName(filePath) {
|
|
|
237
283
|
}
|
|
238
284
|
}
|
|
239
285
|
|
|
240
|
-
// Check domain/ for files
|
|
286
|
+
// Check domain/ for loose files without suffix → migrate to subdirectory
|
|
241
287
|
if (featureSubpath === "domain" && !stem.includes(".")) {
|
|
242
288
|
const lower = stem.toLowerCase();
|
|
243
289
|
if (lower.includes("repository") || stem.startsWith("I")) {
|
|
244
290
|
const expectedName = `I${entityName}.repository${ext}`;
|
|
245
|
-
|
|
291
|
+
const expectedPath = join(dirname(filePath), "repositories", expectedName);
|
|
292
|
+
return { current: filePath, expected: expectedPath, relPath: join(dirname(relPath), "repositories", expectedName), rule: `feature/${featureName}/domain → domain/repositories: I<Name>.repository.ts` };
|
|
293
|
+
}
|
|
294
|
+
if (lower.includes("port")) {
|
|
295
|
+
const expectedName = `${entityName}.port${ext}`;
|
|
296
|
+
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `feature/${featureName}/domain: <Name>.port.ts` };
|
|
246
297
|
}
|
|
247
298
|
const expectedName = `${entityName}.entity${ext}`;
|
|
248
|
-
|
|
299
|
+
const expectedPath = join(dirname(filePath), "entities", expectedName);
|
|
300
|
+
return { current: filePath, expected: expectedPath, relPath: join(dirname(relPath), "entities", expectedName), rule: `feature/${featureName}/domain → domain/entities: <Name>.entity.ts` };
|
|
249
301
|
}
|
|
250
302
|
|
|
251
303
|
return null;
|
|
@@ -291,13 +343,13 @@ export function computeExpectedName(filePath) {
|
|
|
291
343
|
if (subdir === "contracts") {
|
|
292
344
|
const hasI = stem.startsWith("I");
|
|
293
345
|
if (hasI) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
346
|
+
const fixedStem = toPascalCaseI(stem);
|
|
347
|
+
if (fixedStem !== stem) {
|
|
348
|
+
const expectedName = `${fixedStem}${ext}`;
|
|
349
|
+
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `shared/contracts: ${rule.description}` };
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
const expectedName = `I${toPascalCaseI(stem)}${ext}`;
|
|
301
353
|
return { current: filePath, expected: join(dirname(filePath), expectedName), relPath: join(dirname(relPath), expectedName), rule: `shared/contracts: ${rule.description}` };
|
|
302
354
|
}
|
|
303
355
|
}
|
|
@@ -536,6 +588,9 @@ export function renameFile(oldPath, newPath, projectRoot = ROOT) {
|
|
|
536
588
|
return { success: true, updatedImports: [], note: "El archivo ya tiene el nombre correcto" };
|
|
537
589
|
}
|
|
538
590
|
|
|
591
|
+
// Ensure target directory exists
|
|
592
|
+
mkdirSync(dirname(newPath), { recursive: true });
|
|
593
|
+
|
|
539
594
|
// Physical rename
|
|
540
595
|
try {
|
|
541
596
|
renameSync(oldPath, newPath);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
```typescript
|
|
2
2
|
// src/features/<domain>/adapters/out/legacy-<system>/<Domain>ACL.ts
|
|
3
3
|
import { injectable, inject } from "tsyringe";
|
|
4
|
-
import type { I<Domain>Repository } from "../../domain/I<Domain
|
|
5
|
-
import type { <Domain>Entity } from "../../domain/<Domain
|
|
4
|
+
import type { I<Domain>Repository } from "../../domain/repositories/I<Domain>.repository.js";
|
|
5
|
+
import type { <Domain>Entity } from "../../domain/entities/<Domain>.entity.js";
|
|
6
6
|
import { <Domain>Gateway } from "./<Domain>Gateway.js";
|
|
7
7
|
import { <Domain>Translator } from "./<Domain>Translator.js";
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
```typescript
|
|
2
2
|
// src/features/<domain>/adapters/out/legacy-<system>/<Domain>Translator.ts
|
|
3
|
-
import type { <Domain>Entity } from "../../../domain/<Domain
|
|
3
|
+
import type { <Domain>Entity } from "../../../domain/entities/<Domain>.entity.js";
|
|
4
4
|
import type { External<Domain>DTO } from "./External<Domain>DTO.js";
|
|
5
5
|
|
|
6
6
|
export class <Domain>Translator {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
```typescript
|
|
2
2
|
// src/features/<domain>/application/mappers/<Domain>.mapper.ts
|
|
3
|
-
import type { <Domain> } from "../domain/<Domain>.entity.js";
|
|
3
|
+
import type { <Domain> } from "../domain/entities/<Domain>.entity.js";
|
|
4
4
|
|
|
5
5
|
export class <Domain>Mapper {
|
|
6
6
|
static toDomain(doc: Record<string, any>): <Domain> {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
```typescript
|
|
2
2
|
// src/features/<domain>/adapters/out/persistence/<Domain>.repository.ts
|
|
3
3
|
import { injectable } from "tsyringe";
|
|
4
|
-
import type { <Domain> } from "../../../domain/<Domain>.entity.js";
|
|
5
|
-
import type { I<Domain>Repository } from "../../../domain/I<Domain>.repository.js";
|
|
4
|
+
import type { <Domain> } from "../../../domain/entities/<Domain>.entity.js";
|
|
5
|
+
import type { I<Domain>Repository } from "../../../domain/repositories/I<Domain>.repository.js";
|
|
6
6
|
import { <Domain>Mapper } from "../../../application/mappers/<Domain>.mapper.js";
|
|
7
7
|
import <Domain>Model from "./<Domain>.schema.js";
|
|
8
8
|
import { RepositoryError } from "@/shared/errors/RepositoryError.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
```typescript
|
|
2
|
-
// src/features/<domain>/domain/I<Domain>.repository.ts
|
|
3
|
-
import type { <Domain> } from "
|
|
2
|
+
// src/features/<domain>/domain/repositories/I<Domain>.repository.ts
|
|
3
|
+
import type { <Domain> } from "../entities/<Domain>.entity.js";
|
|
4
4
|
|
|
5
5
|
export interface I<Domain>Repository {
|
|
6
6
|
create(data: Partial<<Domain>>, session?: unknown): Promise<<Domain>>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
```typescript
|
|
2
2
|
// src/features/<domain>/adapters/out/saga/SagaOrchestrator.ts
|
|
3
3
|
import { injectable, inject } from "tsyringe";
|
|
4
|
-
import type { SagaInstance, SagaStatus } from "../../domain/SagaInstance.entity.js";
|
|
5
|
-
import type { ISagaRepository } from "../../domain/ISagaRepository.js";
|
|
4
|
+
import type { SagaInstance, SagaStatus } from "../../domain/entities/SagaInstance.entity.js";
|
|
5
|
+
import type { ISagaRepository } from "../../domain/repositories/ISagaRepository.repository.js";
|
|
6
6
|
import type { IEventBus } from "@/platform/events/IEventBus.js";
|
|
7
7
|
import type { ILogger } from "@/platform/logger/ILogger.js";
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
```typescript
|
|
2
2
|
// src/features/<domain>/adapters/out/persistence/<Domain>.schema.ts
|
|
3
3
|
import { model, Schema } from "mongoose";
|
|
4
|
-
import type { <Domain> } from "../../../domain/<Domain>.entity.js";
|
|
4
|
+
import type { <Domain> } from "../../../domain/entities/<Domain>.entity.js";
|
|
5
5
|
|
|
6
6
|
const <Domain>Schema = new Schema<<Domain>>(
|
|
7
7
|
{
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
```typescript
|
|
2
2
|
// src/features/<domain>/application/use-cases/Create<Domain>.uc.ts
|
|
3
3
|
import { injectable, inject } from "tsyringe";
|
|
4
|
-
import type { <Domain> } from "../../domain/<Domain>.entity.js";
|
|
5
|
-
import type { I<Domain>Repository } from "../../domain/I<Domain>.repository.js";
|
|
4
|
+
import type { <Domain> } from "../../domain/entities/<Domain>.entity.js";
|
|
5
|
+
import type { I<Domain>Repository } from "../../domain/repositories/I<Domain>.repository.js";
|
|
6
6
|
import { UseCaseError } from "@/shared/errors/UseCaseError.js";
|
|
7
7
|
// Opcional: errores de dominio y eventos
|
|
8
8
|
// import { <Domain>NotFoundError } from "../../domain/errors/<Domain>NotFound.error.js";
|