---
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<T> implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    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<Response>();

    // 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/`) 적용 고려
