--- description: NestJS module, controller, service, and DTO conventions globs: src/**/*.ts alwaysApply: false --- # NestJS Module Pattern Each feature: `*.module.ts` → `*.controller.ts` → `*.service.ts` → `dto/` ## Controllers ```typescript @Controller('businesses/:businessId/products') @UseGuards(JwtAuthGuard, BusinessPermissionGuard) export class ProductsController { @Get() @RequireBusinessPermission('products.read') list(@Param('businessId') businessId: string, @CurrentUser() user: AuthUser) { return this.service.list(businessId, user); } } ``` ## Services - Convert route IDs with `BigInt(idRaw)` - Inject `PrismaService` + `PermissionsService` - Add private `assertPermission(businessId, userId, 'slug')` (defense in depth) - Use `$transaction` for multi-step writes - Private `serialize()` methods; return IDs as strings ## DTOs - `class-validator` on all request bodies and query params - `@Type(() => Number)` for query coercion - Slug: `^[a-z0-9]+(?:-[a-z0-9]+)*$` - Cell: E.164 `^\+[1-9]\d{6,14}$` ## Nested replace resources For sub-resources like variations or technical forms: `GET` returns state, `PUT` validates → delete-all → recreate in transaction. See `CategoryVariationsService`. ## Errors Use Nest exceptions: `NotFoundException`, `ForbiddenException`, `BadRequestException`, `ConflictException`.