From nestjs-clean-arch
Guide for implementing new features following Clean Architecture with NestJS. Use this skill whenever the user asks to add a new feature, create a new resource/entity/module, write a use case, implement a repository, build a controller, set up dependency injection in a module, write tests, or asks anything about how code should be structured in this project — even if they don't mention "clean architecture" explicitly.
npx claudepluginhub tuannguyen151/foxdemon-plugins --plugin nestjs-clean-archThis skill uses the workspace's default tool permissions.
A complete guide for implementing new features following the project's architecture, covering all layers: Domain, Use Cases, Adapters (Controllers), Infrastructure, and Modules.
Guides NestJS API development with architecture, modules, DI, guards, interceptors, pipes, MongoDB/Mongoose integration, auth, DTOs, error handling, and production patterns.
Implements Clean Architecture, DDD, and Hexagonal Architecture patterns in NestJS/TypeScript apps for complex backend structuring, domain layers with entities/aggregates, ports/adapters, use cases, and refactoring anemic models.
Provides NestJS patterns for scalable Node.js/TypeScript backends: modular architecture, dependency injection, DTO validation, repositories, and events.
Share bugs, ideas, or general feedback.
A complete guide for implementing new features following the project's architecture, covering all layers: Domain, Use Cases, Adapters (Controllers), Infrastructure, and Modules.
For full TypeScript code examples for each layer, read
references/layer-examples.mdwhen implementing or explaining a specific layer.
Post, Comment, etc.)src/
├── domain/ # Pure business layer, no framework dependencies
│ ├── entities/ # Domain entities (business objects)
│ │ └── task.entity.ts
│ ├── utils/ # Pure functions and helpers shared across use cases
│ │ └── string.utils.ts
│ ├── repositories/ # Interfaces for the data access layer
│ │ └── task.repository.interface.ts
│ ├── services/ # Interfaces for infrastructure services
│ ├── config/ # Config interfaces
│ ├── exceptions/ # Custom exceptions
│ └── logger/ # Logger interface
│
├── use-cases/ # Application business rules
│ └── tasks/
│ ├── create-task.use-case.ts
│ ├── get-list-tasks.use-case.ts
│ └── update-task.use-case.ts
│
├── adapters/
│ ├── controllers/ # HTTP layer
│ │ ├── common/
│ │ │ ├── guards/
│ │ │ ├── decorators/
│ │ │ └── middlewares/
│ │ └── [feature]/
│ │ ├── dto/ # Input validation
│ │ ├── presenters/ # Output transformation
│ │ └── [feature].controller.ts
│ └── gateways/ # Real-time communication (WebSockets)
│ └── [feature]/
│ ├── dto/
│ ├── presenters/
│ └── [feature].gateway.ts
│
├── infrastructure/
│ ├── databases/postgresql/
│ │ ├── entities/ # TypeORM entities
│ │ ├── repositories/ # Repository implementations
│ │ ├── typeorm.config.ts
│ │ └── typeorm.module.ts
│ ├── services/ # bcrypt, casl, health, jwt
│ ├── common/ # filter, guards, interceptors, middlewares, pipes, strategies
│ ├── config/environment/
│ ├── exceptions/
│ └── logger/
│
└── modules/ # NestJS modules (DI wiring)
└── task.module.ts
database/
├── migrations/ # TypeORM migration files
└── seeds/ # Database seed files
├── main.ts
├── factories/
└── seeders/
test/
├── adapters/controllers/
├── infrastructure/ # filter, interceptors, pipes, strategies, config, databases, exceptions, logger, services
├── mocks/ # Reusable mock objects for dependency injection
├── stubs/ # Reusable stub data
└── use-cases/
Read
references/layer-examples.mdfor full TypeScript code examples when implementing any layer.
src/domain/The core layer. No imports from NestJS or TypeORM. Pure TypeScript only.
readonly id/timestamps. Use private _field + getter for fields with business rules. Add methods for state transitions (e.g., complete()).Symbol constant and an interface with the same name. Only accept/return domain entities — never TypeORM entities.src/use-cases/Contains application logic. Only depends on the domain layer (interfaces + entities).
execute() method[action]-[resource].use-case.ts / Class: [Action][Resource]UseCase@Inject(ITaskRepository) using the Symbol tokensrc/adapters/controllers/The HTTP layer — DTOs for input validation, Presenters for output transformation, Controllers for routing.
class-validator decorators + @ApiProperty for Swagger. Never put business logic here.if/else business logic. Use @User('id') to extract userId from JWT. Use @CheckPolicies({ action, subject }) for authorization.src/infrastructure/Implements the interfaces defined in domain.
implements ITaskRepository. Always has private toEntity() to convert TypeORM entity → domain entity. Never exposes TypeORM entities outside.src/modules/Wires dependency injection. No logic. Binds ITaskRepository Symbol → TaskRepository class in providers.
See
references/layer-examples.md(section 10) for a full test example.
src/ structure under test/ (e.g. src/use-cases/tasks/ → test/use-cases/tasks/)inputX, mockX, actualX, expectedXjest.fn() in providerstest/stubs/ for reusable data; put reusable mock provider objects in test/mocks/| Type | Convention | Example |
|---|---|---|
| File | kebab-case | create-task.use-case.ts |
| Class | PascalCase | CreateTaskUseCase |
| Method | camelCase + verb | execute(), findTasks() |
| Interface | PascalCase, prefix I | ITaskRepository |
| Enum | PascalCase + suffix Enum | TaskStatusEnum |
| DTO | PascalCase + suffix Dto | CreateTaskDto |
| Presenter | PascalCase + suffix Presenter | CreateTaskPresenter |
| Symbol token | Same name as interface | export const ITaskRepository = Symbol('ITaskRepository') |
| Boolean var | is, has, can prefix | isUpdated, hasError |
| Env variable | UPPER_SNAKE_CASE | DATABASE_HOST |
When adding a new resource (e.g., Comment), create files in this order:
src/domain/entities/comment.entity.tssrc/domain/repositories/comment.repository.interface.tssrc/use-cases/comments/create-comment.use-case.ts, etc.src/infrastructure/databases/postgresql/entities/comment.entity.tssrc/infrastructure/databases/postgresql/repositories/comment.repository.tssrc/adapters/controllers/comments/dto/src/adapters/controllers/comments/presenters/src/adapters/controllers/comments/comments.controller.tssrc/modules/comment.module.tsdatabase/migrations/database/seeds/factories/, database/seeds/seeders/test/use-cases/comments/, test/adapters/controllers/comments/infrastructure → domain, use-cases → domain, never in reverseSymbol instead of string tokens for repository injectionprivate toEntity() to convert TypeORM entities to domain entitiesif/else business logic — only delegate to use casesexecute() methodFor a quick summary, see
references/casl-authorization.md. For complete implementation details, code examples, and testing patterns, use the standalonecasl-authorizationskill.
| Layer | Responsibility |
|---|---|
| CASL / PoliciesGuard | Role-based coarse check: "is this role allowed to perform this action?" |
| UseCase / Repository | Ownership enforcement: "only access your own resources" — filter WHERE userId = ? |
CASL does not enforce ownership — that is the responsibility of the use-case/repository layer.
any type → use unknown or declare a proper typetest/stubs/*.stub.ts and import