Created
December 7, 2025 10:04
-
-
Save sangdth/9af14eff206ce6c195fc8cbd179ffc9b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| description: Designs scalable NestJS applications using domain-driven modular patterns with clear separation of concerns and service-based business logic. | |
| alwaysApply: false | |
| --- | |
| # NestJS Architecture | |
| ## Modular Architecture Rules | |
| - Use modular architecture with clear separation of concerns | |
| - One module per main domain/route | |
| - Each module should be self-contained with its own controllers, services, and models | |
| ## Module Structure | |
| ```text | |
| src/ | |
| ├── users/ | |
| │ ├── dto/ | |
| │ │ ├── create-user.dto.ts | |
| │ │ └── update-user.dto.ts | |
| │ ├── users.controller.ts | |
| │ ├── users.service.ts | |
| │ └── users.module.ts | |
| ``` | |
| ## Controller Organization | |
| - One main controller per module for primary routes | |
| - Additional controllers for secondary/nested routes | |
| - Keep controllers thin - delegate business logic to services | |
| Example: | |
| ```typescript | |
| @Controller('users') | |
| export class UsersController { | |
| @Inject(UsersService) | |
| private readonly usersService: UsersService | |
| @Post() | |
| async createUser(@Body() createUserDto: CreateUserDto): Promise<UserResponse> { | |
| return this.usersService.createUser(createUserDto); | |
| } | |
| } | |
| @Controller('users/:userId/profile') | |
| export class UserProfileController { | |
| @Inject(UserProfileService) | |
| private readonly userProfileService: UserProfileService | |
| @Get() | |
| async getProfile(@Param('userId') userId: string): Promise<ProfileResponse> { | |
| return this.userProfileService.getProfile(userId); | |
| } | |
| } | |
| ``` | |
| ## DTO and Validation | |
| - Use DTOs with class-validator for all inputs | |
| - Define simple types for outputs | |
| - Validate at the boundary (controllers) | |
| Example: | |
| ```typescript | |
| import { IsEmail, IsNotEmpty, IsOptional, MinLength } from 'class-validator'; | |
| export class CreateUserDto { | |
| @IsNotEmpty() | |
| @MinLength(2) | |
| name: string; | |
| @IsEmail() | |
| email: string; | |
| @IsOptional() | |
| @MinLength(8) | |
| password?: string; | |
| } | |
| // Simple type for response | |
| export interface DemoResponse { | |
| id: string; | |
| createdAt: Date; | |
| } | |
| ``` | |
| ## Service Organization | |
| - One service per entity/domain concept | |
| - Services contain business logic and persistence coordination | |
| - Use dependency injection for service composition | |
| ```typescript | |
| @Injectable() | |
| export class UsersService { | |
| @Inject(UserRepository) | |
| private readonly userRepository: UserRepository | |
| @Inject(EmailService) | |
| private readonly emailService: EmailService | |
| @Inject(Logger) | |
| private readonly logger: Logger | |
| async createUser(createUserDto: CreateUserDto): Promise<UserResponse> { | |
| const user = await this.userRepository.create(createUserDto); | |
| await this.emailService.sendWelcomeEmail(user.email); | |
| this.logger.log(`User created: ${user.id}`); | |
| return this.mapToResponse(user); | |
| } | |
| } | |
| ``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment