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.
How this skill is triggered — by the user, by Claude, or both
Slash command
/nestjs-clean-arch:brownfield-workflowThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Guide for safely modifying, extending, or refactoring existing features in the NestJS Clean Architecture project.
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 actionsnpx claudepluginhub tuannguyen151/foxdemon-plugins --plugin nestjs-clean-archEnforces 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.
Provides expert Nest.js guidance on enterprise Node.js architecture, dependency injection, decorators, middleware, guards, interceptors, pipes, testing strategies, database integration, and authentication. Validates with typecheck, unit, integration, e2e tests.
Generates database migrations with schema changes and rollback, detecting framework (Knex, Prisma, TypeORM, raw SQL) and validating safety.