Modules + DI + pipes at the edge. Contracts: api-design. Micro/transporters: nestjs-microservices. Types: typescript-strict. ORM: database-prisma / database-drizzle.
Stack and scope
| Part | Role |
|---|---|
| NestJS | Modules, DI, lifecycle |
| Controllers | HTTP |
| class-validator + ValidationPipe | DTOs |
| Guards | Authn/authz |
| Config | @nestjs/config + schema |
Do not introduce Kafka/NATS in this skill — use nestjs-microservices.
Organization
src/
main.ts
app.module.ts
orders/
orders.module.ts
orders.controller.ts
orders.service.ts
dto/
orders.repository.ts
- One module per domain. Thin controller; service with the rule.
main.ts: global pipes, CORS, shutdown hooks.
Non-negotiable rules
ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }).- Input/output DTOs; do not return a raw Prisma/TypeORM entity.
- Authn ≠ Authz:
JwtAuthGuard+ ownership guard/policy in the service. - Exception filter → stable JSON
{ statusCode, code, message }(or the product's contract). - Config validated at boot (
Joi/Zod); secrets only in env. enableShutdownHooks(); close Prisma/Redis inonModuleDestroy.
@Controller('api/v1/orders')
@UseGuards(JwtAuthGuard)
export class OrdersController {
constructor(private readonly orders: OrdersService) {}
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string, @CurrentUser() user: User) {
return this.orders.getForUser(user.id, id);
}
}
Modules and DI
importsexplicit. AvoidforwardRefin a chain — extract a shared module.providersscoped:defaultsingleton;REQUESTonly when the state is per request.- Repositories in the domain module; not a
DatabaseModulethat leaks everything.
Pipes, interceptors, filters
- Pipes: parse/validate. Interceptors: logging, mapping, timeout.
TimeoutInterceptoron expensive routes. Do not swallow errors in the interceptor.- Correlation id: interceptor + header
x-request-id.
Auth and docs
- Passport/JWT or the project's guard. Policies by permission.
@nestjs/swaggeraligned with the DTOs; do not document what the pipe rejects.- Deep authz:
authentication-authorization.
Tests
- Unit: services with fake repos. e2e:
INestApplication+supertest. testing-fullstackcomplements JS e2e; do not replace the Nest module.
Anti-patterns
- Logic in the controller
anyin the DTOsTypeOrmModule.forFeaturefrom another bounded context- Exception filter that returns 200
- Hybrid micro “just a little bit” without the micro skill
Integration with other skills
- Transporters:
nestjs-microservices - i18n:
i18n-backend - Prisma/Drizzle:
database-prisma/database-drizzle - TS libs:
typescript-librariesif publishing the SDK - General production:
production-readiness
Completion criteria
- Module per domain; global ValidationPipe
- Authz in the service that owns the data
- Stable errors and statuses
- Config validated; shutdown cleans up
- e2e or unit tests for the risk flows