refactor: .claude 규칙 체계를 skills·rules 구조로 재편
- 슬래시 커맨드(nestjs/vue3/flutter)를 정식 스킬(.claude/skills)로 전환하고 docker 스킬을 신설(루트 command.md 이관) - 공통 규칙을 .claude/rules 로 모듈화(coding-common·response-format·error-codes· git-convention·security·env-structure·testing·checklist)하고 CLAUDE.md 에서 @import - 파일·식별자 네이밍 규약, 테스트 규칙 추가 - .claude/settings.json(권한·환경) 추가 - CLAUDE.md·README.md 참조 갱신, 단독 실행(non-Docker) 안내 정리 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
---
|
||||
name: nestjs
|
||||
description: NestJS 백엔드(backend/) 개발 규칙 — 컨트롤러/서비스/DTO 관심사 분리, 표준 응답 인터셉터, 전역 예외 필터, Swagger, JWT 인증, 캐싱/Rate Limiting/페이지네이션. backend/ 에서 작업하거나 REST API·모듈·DTO·인터셉터·필터를 만들 때 사용한다.
|
||||
---
|
||||
|
||||
> 이 스킬은 `.claude/skills/nestjs/SKILL.md`에 위치한다.
|
||||
> 사용법: `/nestjs [요청 내용]` 또는 backend/ 작업 시 자동 적용.
|
||||
> 공통 규칙: [[response-format]] · [[error-codes]] · [[security]] · [[coding-common]]
|
||||
|
||||
---
|
||||
|
||||
## 템플릿 기본 제공 골격
|
||||
|
||||
> 이 템플릿은 아래 인프라를 **기본 제공**한다. 새 코드는 이 파일들의 패턴을 재사용한다(같은 역할을 새로 만들지 말 것).
|
||||
|
||||
| 제공 항목 | 위치 | 비고 |
|
||||
| --- | --- | --- |
|
||||
| 표준 응답 인터셉터 | `src/common/interceptors/transform.interceptor.ts` | main.ts 전역 등록 — 컨트롤러는 raw 데이터만 반환 |
|
||||
| 전역 예외 필터 | `src/common/filters/http-exception.filter.ts` | `HttpException` → `{success:false,error:{code,message}}` ([[error-codes]]) |
|
||||
| 전역 ValidationPipe | `main.ts` | `whitelist/forbidNonWhitelisted/transform` |
|
||||
| Swagger | `main.ts` → `/api-docs` | 모든 엔드포인트 데코레이터 |
|
||||
| 보안 미들웨어 | `main.ts` | helmet · CORS 화이트리스트 · Rate Limiting(`express-rate-limit`) |
|
||||
| 로깅 | `shared/logger/winston.config.ts` | `console.log` 대신 사용 |
|
||||
| 예제 모듈(참조용) | `modules/user`(DTO+Swagger), `modules/health`(`/health`) | 새 모듈 패턴 참고. user 예제는 in-memory 데모 저장소 |
|
||||
| 순수 유틸 | `shared/utils/` | 순수 함수 분리 위치 |
|
||||
|
||||
> **확장 시 따르는 규칙** (기능이 필요해지면 규칙대로 구현):
|
||||
> - **인증(JWT)**: `@nestjs/jwt`·`@nestjs/passport` 설치 → `common/guards/` 생성 → AUTH_001/AUTH_003 흐름 검증
|
||||
> - **DB 영속화**: TypeORM 엔티티/리포지토리 추가 (예제의 in-memory 저장 대체)
|
||||
> - **페이지네이션**: 목록 API 에 커서/오프셋 적용
|
||||
> - `common/{guards,decorators,pipes}/` 는 해당 관심사 등장 시 생성 (아래 "모듈 구조"는 목표 구조)
|
||||
|
||||
---
|
||||
|
||||
## 아키텍처 원칙
|
||||
|
||||
### 관심사 분리 (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가 생성한다.
|
||||
- 응답 포맷 SSOT는 [[response-format]] 참조.
|
||||
|
||||
---
|
||||
|
||||
## 전역 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 등 에러 맵은 [[error-codes]] 참조
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
이 필터는 세 플랫폼 공유 에러 코드 맵의 **단일 진실 공급원(SSOT)** 이다. 메시지 수정 시 [[error-codes]] 의 3개 파일을 함께 갱신한다.
|
||||
|
||||
---
|
||||
|
||||
## 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)
|
||||
|
||||
> 📐 **확장 지점.** 이 템플릿은 JWT 인증을 강제하지 않는다(규칙만 제공). **인증이 필요해지면** 아래 규칙대로 구현한다: `@nestjs/jwt`·`@nestjs/passport` 설치 → `common/guards/` 생성 → AUTH_001/AUTH_003 흐름 검증.
|
||||
|
||||
- Access Token: 만료 시간 짧게 (15분 ~ 1시간)
|
||||
- Refresh Token: HttpOnly Secure 쿠키로 전달
|
||||
- `@nestjs/jwt` + `@nestjs/passport` 사용
|
||||
- Guard를 통한 라우트 보호
|
||||
- 토큰 저장·전송 보안 규칙은 [[security]] 참조.
|
||||
|
||||
---
|
||||
|
||||
## 성능 & 최신 트렌드 추가 규칙
|
||||
|
||||
- **캐싱**: 자주 조회되는 데이터는 `@nestjs/cache-manager` (Redis) 활용 고려
|
||||
- **Rate Limiting**: 템플릿은 `main.ts` 에서 `express-rate-limit`(초과 시 `SYS_001`)로 API 남용을 방지한다. 라우트 단위 데코레이터 제어가 필요하면 `@nestjs/throttler` 로 전환 고려
|
||||
- **Pagination**: 목록 API는 반드시 커서 기반 또는 오프셋 페이지네이션 적용
|
||||
- **Logging**: `winston` 또는 `@nestjs/common Logger` 사용, `console.log` 지양
|
||||
- **Health Check**: `@nestjs/terminus`로 `/health` 엔드포인트 구성 권장
|
||||
- **Versioning**: API 버전 관리 (`/v1/`, `/v2/`) 적용 고려
|
||||
|
||||
---
|
||||
|
||||
## 작업 점검 체크리스트
|
||||
|
||||
코드 작성/수정 후 아래를 점검한다. (전체 확장 지점·점검 목록은 [[checklist]])
|
||||
|
||||
- [ ] **응답 포맷**: 컨트롤러는 raw 데이터만 반환 — `{success,data}` 래핑은 인터셉터가 담당. 직접 래핑 금지.
|
||||
- [ ] **에러**: 사용자 노출 실패는 `HttpException` 으로 던져 필터가 코드 매핑하게 한다. 새 코드 추가 시 [[error-codes]] 의 3개 파일 동시 갱신.
|
||||
- [ ] **DTO**: 모든 입력 DTO 에 `class-validator` + 한국어 메시지 + `@ApiProperty()`.
|
||||
- [ ] **Swagger**: 새 엔드포인트에 `@ApiTags`/`@ApiOperation`/`@ApiResponse`.
|
||||
- [ ] **lint**: 커밋 전 `npm run lint` 통과 (Warning 0).
|
||||
- [ ] **DB 전환 시**: in-memory Map → TypeORM 엔티티/리포지토리로 교체.
|
||||
- [ ] **인증 추가 시**: `@nestjs/jwt`·`@nestjs/passport` 설치 → `common/guards/` 생성 → AUTH_001/003 흐름 확인.
|
||||
- [ ] **env**: DB/Redis/CORS/포트는 루트 `.env` 에서 주입된다. 백엔드 고유 시크릿(`JWT_SECRET` 등)만 `backend/.env.{env}` 에 작성(compose `env_file` 로 로드).
|
||||
Reference in New Issue
Block a user