From nestjs-clean-arch
Workflow for safely modifying, extending, or refactoring existing features in the NestJS Clean Architecture project. Use this skill when the user asks to "add a field", "add an endpoint", "modify existing", "extend", "refactor", "change existing feature", "brownfield", "update entity", "add column", "add relation", or needs to change something that already exists — including impact analysis, migration strategy, and backward compatibility.
npx claudepluginhub tuannguyen151/foxdemon-plugins --plugin nestjs-clean-archThis skill uses the workspace's default tool permissions.
Guide for safely modifying, extending, or refactoring existing features in the NestJS Clean Architecture project.
Provides expert Nest.js guidance on enterprise architecture, dependency injection, decorators, middleware, guards, interceptors, pipes, testing strategies, database integration, and authentication. Detects projects, applies best practices, validates with typecheck, unit, integration, e2e tests.
Enforces NestJS best practices for modular architecture, dependency injection scoping, exception filters, class-validator DTO validation, and Drizzle ORM integration. Use when designing modules, providers, filters, DTOs, or ORM in NestJS apps.
Applies opinionated NestJS conventions for backends: module structure, dependency injection, controllers/services, DTOs with class-validator, guards/interceptors/pipes, JWT auth, TypeORM/Prisma.
Share bugs, ideas, or general feedback.
Guide for safely modifying, extending, or refactoring existing features in the NestJS Clean Architecture project.
For before/after code examples of every change type, read
references/change-patterns.md.
Before touching any code, answer these questions:
find_symbol or grep to locate all references to the entity, interface, or method being changed.test/ for imports of the affected entity, stub, or use case. Check test/stubs/ first — stub changes propagate everywhere.Record the answers before proceeding. This prevents half-finished changes across layers.
Identify which type matches the requested change and follow its file modification order.
Modify files in this exact order:
src/domain/entities/<entity>.entity.ts) — Add the field to the constructor. Use public for simple fields, private _field + getter if there is a business rule. Optional fields use ? suffix.src/domain/repositories/<entity>.repository.interface.ts) — Update param interfaces (ISearch*Params, ICount*Params) if the field is filterable or sortable.src/infrastructure/databases/postgresql/entities/<entity>.entity.ts) — Add @Column() with appropriate options ({ nullable: true } for optional, { default: value } for defaults). Import enums from domain entity.src/infrastructure/databases/postgresql/repositories/<entity>.repository.ts) — Update toEntity() to pass the new field. Update buildWhereCondition() if the field is filterable. Update query select or find options if needed.src/adapters/controllers/<feature>/dto/) — Add the field with class-validator decorators and @ApiProperty. Add to create DTO if settable on creation, update DTO if editable.src/adapters/controllers/<feature>/presenters/) — Add the field mapping in the constructor. Add @ApiProperty for Swagger documentation.docker exec -it app-api npm run migration:generate --name=add-<field>-to-<table>test/stubs/<entity>.stub.ts) — Add the new field to the stub factory. This is critical — stubs propagate to all tests.Create/modify files in this order:
src/use-cases/<feature>/) — Create a new file: <action>-<entity>.use-case.ts. One class, one execute() method. Inject repository via @Inject(IEntityRepository).deleteTask).src/adapters/controllers/<feature>/dto/) — Create a new DTO if the endpoint accepts a request body or query params.src/adapters/controllers/<feature>/presenters/) — Create a new presenter if the endpoint returns data in a new shape.src/adapters/controllers/<feature>/<feature>.controller.ts) — Add the new method. Inject the new use case in the constructor. Apply @CheckPolicies, @ApiBearerAuth. Follow the thin controller pattern: receive → delegate → present.src/modules/<feature>.module.ts) — Register the new use case in providers.delete), update casl-ability.factory.ts to grant the permission and add 'delete' action handling for the subject.test/use-cases/<feature>/<action>-<entity>.use-case.spec.ts. Update test/adapters/controllers/<feature>/<feature>.controller.spec.ts to cover the new method.Modify files in this order:
public comments?: CommentEntity[]). Do NOT import TypeORM here.@ManyToOne, @OneToMany, or @ManyToMany decorator with @JoinColumn. Use { nullable: true } for optional relations. Always specify the inverse side.relations: ['relatedEntity'] where needed. Update toEntity() to map nested entities.docker exec -it app-api npm run migration:generate --name=add-<entity>-<related>-relationModify files in this order:
src/domain/entities/<entity>.entity.ts) — Add or modify enum values. Never remove values that exist in the database.@Column({ default: ... }) still references a valid value. Update if the default changes.@IsEnum() validators. If the new value should be accepted in create/update, verify the DTO allows it.test/.Modify files in this order:
src/use-cases/<feature>/) — Modify the execute() method. If new data is needed, inject additional repositories or services.test/use-cases/<feature>/ to cover the new logic paths. Add test cases for edge cases and error conditions.Follow this safety procedure:
find_referencing_symbols or grep across the entire src/ and test/ trees. List every file that imports the symbol being moved.import statement found in step 2. Use path aliases (@domain/*, @use-cases/*, @adapters/*, @infrastructure/*).docker exec -it app-api npm run build and look for circular dependency warnings.docker exec -it app-api npm run test to verify nothing broke.Command: docker exec -it app-api npm run migration:generate --name=<kebab-case-description>
Command: docker exec -it app-api npm run migration:create --name=<kebab-case-description>
Use kebab-case, be descriptive: add-due-date-to-tasks, add-task-comment-relation, backfill-task-priorities.
docker exec -it app-api npm run migration:rundocker exec -it app-api npm run migration:revertBefore finalizing any change, verify:
nullable: true) or have sensible defaults — never add a required column without a default to a table with existing data.Follow this order to minimize cascading test failures:
test/stubs/<entity>.stub.ts) — Stubs are imported by many tests. Updating them first ensures consistency across the test suite.test/use-cases/, test/adapters/controllers/, and test/infrastructure/ as needed.docker exec -it app-api npm run testdocker exec -it app-api npm run test:cov — Verify coverage did not drop.inputX, mockX, actualX, expectedXdescribe block per method, one it block per behavior| Change Type | Domain | Repo Interface | Use Case | TypeORM Entity | Repo Impl | DTO | Presenter | Controller | Module | Migration | Tests |
|---|---|---|---|---|---|---|---|---|---|---|---|
| A: Add field | ✅ | Maybe | — | ✅ | ✅ | ✅ | ✅ | — | — | ✅ | ✅ |
| B: Add endpoint | — | Maybe | ✅ New | — | Maybe | ✅ | ✅ | ✅ | ✅ | — | ✅ |
| C: Add relation | ✅ | Maybe | Maybe | ✅ | ✅ | — | Maybe | — | — | ✅ | ✅ |
| D: Change enum | ✅ | — | — | Maybe | — | ✅ | Maybe | — | — | Maybe | ✅ |
| E: Modify business logic | — | Maybe | ✅ | — | Maybe | — | — | — | — | — | ✅ |
| F: Refactor/move code | Maybe | Maybe | Maybe | Maybe | Maybe | — | — | Maybe | Maybe | — | ✅ |
testing-patterns — exact patterns for writing/updating tests after brownfield changesexception-handling — adding error handling when extending use casesswagger-api-docs — updating Swagger decorators when adding/modifying endpointscasl-authorization — updating CASL rules when adding new subjects or actions