From nestjs-clean-arch
Structured workflow for diagnosing, fixing, and verifying bugs in the NestJS Clean Architecture project. Use this skill when the user reports a "bug", "error", "failing test", "not working", "broken", "unexpected behavior", "500 error", "null reference", "type error", or needs to debug, troubleshoot, or fix an issue in any layer of the application.
npx claudepluginhub tuannguyen151/foxdemon-plugins --plugin nestjs-clean-archThis skill uses the workspace's default tool permissions.
A structured 5-phase methodology for diagnosing and fixing bugs in this project. Follow these phases in order. Do not skip phases — each one narrows the search space and prevents wasted effort.
Provides Nest.js expertise on enterprise architecture, dependency injection, decorators, middleware, guards, interceptors, pipes, testing strategies, database integration, and authentication.
Reviews NestJS applications for module structure, dependency injection, controllers, services, guards, interceptors, pipes, security, testing, and database patterns before PR merges or feature implementation.
Executes hypothesis-driven debugging workflow: triage and reproduce bugs, investigate with evidence, analyze root causes, fix and verify, then report. For 'fix this bug' or debug requests.
Share bugs, ideas, or general feedback.
A structured 5-phase methodology for diagnosing and fixing bugs in this project. Follow these phases in order. Do not skip phases — each one narrows the search space and prevents wasted effort.
For a catalog of common bugs with symptoms, root causes, and TypeScript code fixes, read
references/common-bugs.md.
Start every bugfix by establishing what is actually broken.
test/ for specs related to the affected feature.test/ subdirectory mirroring src/.Key questions to answer before moving on:
Use the error type and HTTP status code to narrow down the layer, then trace the call chain.
| Symptom | Likely Layer | Where to Look |
|---|---|---|
| HTTP 400 / 422 | Adapter | DTO validation decorators in src/adapters/controllers/[feature]/dto/ |
| HTTP 401 | Infrastructure | JWT guard, strategy in src/infrastructure/common/strategies/ |
| HTTP 403 | Infrastructure | CASL ability factory in src/infrastructure/services/casl/ |
| HTTP 404 | Use Case / Infra | Repository query or missing route registration |
| HTTP 500 | Use Case / Domain | Use case logic, domain entity method, or repository implementation |
| Wrong data returned | Adapter / Infra | Presenter mapping or repository toEntity() |
| Type error at compile | Any | Check imports, constructor signatures, interface conformance |
Cannot resolve dependencies | Module | Missing or wrong Symbol binding in module providers |
| Test failure | Test | Mock setup, stub data, or assertion mismatch |
Use Serena tools to trace the data flow through layers:
find_symbol to locate the endpoint handler.find_referencing_symbols to find where the use case's execute() is invoked.find_symbol on the repository interface method, then find its implementation.Trace the full data transformation chain:
Request → DTO (validation) → Controller → Use Case → Repository Interface
→ Repository Impl → TypeORM Entity → Database
→ TypeORM Entity → toEntity() → Domain Entity → Presenter → Response
Every arrow is a potential failure point. Identify which transformation breaks.
Read the suspected code carefully. Use find_symbol with include_body: true to examine the implementation.
Walk through each transformation step and verify data integrity:
execute()?toEntity() map every column to the domain entity constructor in the correct order?toEntity() call arguments — a mismatch here silently swaps fields.@Inject(IXxxRepository) with the one in the module's provide: — they must be the same Symbol.Apply the fix where the bug originates, not where it manifests:
toEntity(), not in the presenter.When a fix spans multiple layers, work inside-out:
toEntity(), TypeORM entity, queriestoEntity() → presenter → DTO (if input) → stubs → tests.Run verification commands in order. Stop at the first failure and fix before continuing.
# 1. Run the specific test that demonstrates the bug (should now pass)
docker exec -it app-api npm run test:watch <test-file>
# 2. Run the full test suite (no regressions)
docker exec -it app-api npm run test
# 3. Build (no compilation errors)
docker exec -it app-api npm run build
# 4. Lint (no style violations)
docker exec -it app-api npm run lint
migration:run to apply itsrc/domain/new XxxEntity(...) call site.complete() throws if status is not OnGoing. Verify the entity is in the expected state.src/use-cases/@Inject() token — must use the Symbol (e.g., ITaskRepository), not a string literal.execute() parameter types — must match what the controller passes in.userId for ownership filtering.dto.priority ?? TaskPriorityEnum.Medium.@Injectable() decorator is present on the class.src/adapters/controllers/@IsString(), @IsOptional(), @IsEnum(), etc. A missing @IsOptional() rejects valid partial updates.@User('id') — extracts id from the JWT payload. Verify the JWT strategy puts id in the right place.@CheckPolicies({ action, subject }) — the subject string must match what CASL defines in TSubject.@Get(), @Post(), @Patch(':id') must match the intended HTTP method and path.src/infrastructure/toEntity() maps ALL fields in the correct order — this is the single most common bug in this architecture..andWhere() with conditional logic.@InjectRepository() uses the correct TypeORM entity class (not the domain entity).@Column() decorators match the database schema.src/modules/{ provide: IXxxRepository, useClass: XxxRepository } — both sides must be correct.providers.app.module.ts.forwardRef() if unavoidable.Use this tree to quickly narrow down the root cause:
| Error Message / Symptom | Root Cause | Fix Location |
|---|---|---|
Nest can't resolve dependencies of XxxUseCase | Missing Symbol binding in module | Module providers array |
Cannot read properties of undefined | Missing field in toEntity() or presenter | Repository toEntity() or presenter constructor |
Unexpected token / compile error | Wrong import path or missing type | Check import statements and tsconfig paths |
401 Unauthorized | JWT missing, expired, or guard not applied | Auth strategy or @UseGuards(JwtAuthGuard) |
403 Forbidden | CASL ability does not allow this action | casl-ability.factory.ts or TSubject type |
Entity not found / empty result | Repository query missing WHERE clause | Repository implementation query |
Duplicate entry | Missing unique constraint or no upsert logic | Migration or repository save logic |
Column "xxx" does not exist | Migration not run or TypeORM entity out of sync | Generate + run migration |
mockResolvedValue not working | jest.fn() not configured or wrong method name | Test mock setup in beforeEach |
| Fields appear swapped | toEntity() argument order mismatch | Repository toEntity() method |
| New field missing from response | Presenter not updated | Presenter constructor |
| Valid input rejected with 400 | DTO decorator too strict or missing @IsOptional() | DTO class decorators |
After every fix, verify these items:
npm run test:cov if the fix touches critical paths.test/stubs/ factories to include it.testing-patterns — exact patterns for writing regression tests after a fixexception-handling — if the bug involves incorrect error handling or missing exceptions