first commit
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
---
|
||||
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/`) 적용 고려
|
||||
Reference in New Issue
Block a user