--- description: NestJS 백엔드 개발 규칙 --- > 이 파일은 `.claude/commands/nestjs.md`에 위치한다. > 사용법: `/nestjs [요청 내용]` --- ## 아키텍처 원칙 ### 관심사 분리 (Separation of Concerns) ``` Controller → HTTP 라우팅, 요청/응답 파싱만 담당 Service → 모든 비즈니스 로직 처리 Repository → 데이터 접근 계층 (TypeORM) DTO → 요청/응답 데이터 형식 정의 및 검증 ``` - `Controller`에 비즈니스 로직 작성 **금지** - `new` 키워드로 수동 객체 생성 **지양** → 의존성 주입(DI) 활용 ### 모듈 구조 ``` src/ ├── modules/ │ └── user/ │ ├── user.module.ts │ ├── user.controller.ts │ ├── user.service.ts │ ├── user.repository.ts ← 커스텀 Repository (선택) │ └── dto/ │ ├── create-user.dto.ts │ └── update-user.dto.ts ├── common/ │ ├── interceptors/ ← 응답 래핑, 에러 처리 │ ├── filters/ ← 전역 Exception Filter │ ├── guards/ ← 인증/권한 Guard │ ├── decorators/ ← 커스텀 데코레이터 │ └── pipes/ ← 전역 Validation Pipe └── shared/ └── utils/ ← 순수 유틸 함수 ``` --- ## DTO 작성 규칙 ```typescript import { IsString, IsEmail, IsNotEmpty, MinLength } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; export class CreateUserDto { @ApiProperty({ description: '사용자 이메일', example: 'user@example.com' }) @IsEmail({}, { message: '올바른 이메일 형식을 입력해 주세요.' }) @IsNotEmpty() email: string; @ApiProperty({ description: '비밀번호 (최소 8자)', example: 'password123' }) @IsString() @MinLength(8, { message: '비밀번호는 최소 8자 이상이어야 합니다.' }) password: string; } ``` - 모든 DTO는 `class-validator` + `class-transformer` 사용 - 에러 메시지는 **한국어**로 작성 - `@ApiProperty()` 반드시 포함 (Swagger 명세용) --- ## 표준 응답 인터셉터 ```typescript // common/interceptors/transform.interceptor.ts @Injectable() export class TransformInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable { return next.handle().pipe( map((data) => ({ success: true, data: data ?? null, })), ); } } ``` - `main.ts`에서 전역 등록: `app.useGlobalInterceptors(new TransformInterceptor())` - 실패 응답(`success: false`)은 아래 Exception Filter가 생성한다. --- ## 전역 Exception Filter ```typescript // common/filters/http-exception.filter.ts @Catch() export class HttpExceptionFilter implements ExceptionFilter { catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); // HTTP 상태 → 에러 코드 매핑 후 { success: false, error: { code, message } } 반환 // SYS_001 / AUTH_001 / VAL_001 등 CLAUDE.md 에러 맵 참조 } } ``` --- ## Swagger 필수 적용 ```typescript // main.ts const config = new DocumentBuilder() .setTitle('API 문서') .setDescription('프로젝트 API 명세서') .setVersion('1.0') .addBearerAuth() .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api-docs', app, document); ``` - 모든 Controller에 `@ApiTags()` 적용 - 모든 엔드포인트에 `@ApiOperation()`, `@ApiResponse()` 작성 - 모든 DTO에 `@ApiProperty()` 작성 --- ## 인증 (JWT) - Access Token: 만료 시간 짧게 (15분 ~ 1시간) - Refresh Token: HttpOnly Secure 쿠키로 전달 - `@nestjs/jwt` + `@nestjs/passport` 사용 - Guard를 통한 라우트 보호 --- ## 성능 & 최신 트렌드 추가 규칙 - **캐싱**: 자주 조회되는 데이터는 `@nestjs/cache-manager` (Redis) 활용 고려 - **Rate Limiting**: `@nestjs/throttler`로 API 남용 방지 - **Pagination**: 목록 API는 반드시 커서 기반 또는 오프셋 페이지네이션 적용 - **Logging**: `winston` 또는 `@nestjs/common Logger` 사용, `console.log` 지양 - **Health Check**: `@nestjs/terminus`로 `/health` 엔드포인트 구성 권장 - **Versioning**: API 버전 관리 (`/v1/`, `/v2/`) 적용 고려