ttipo 750cd6362a
CI / Frontend (lint · type-check · test) (push) Has been cancelled
CI / Flutter (analyze · test) (push) Has been cancelled
CI / 에러 코드 SSOT 동기화 검사 (push) Has been cancelled
CI / Backend (lint · test · e2e · build) (push) Has been cancelled
fix(backend): multer 취약점 해소 — overrides 로 2.4.0 고정
@nestjs/platform-express@11 이 multer 를 2.2.0 으로 정확 고정하는데,
이 버전에는 깊게 중첩된 필드명으로 자원을 소모시키는 DoS 취약점(high)이 있다.
상위 패키지가 버전을 박아두어 npm audit fix 로는 해결되지 않았다.

platform-express@12 가 쓰는 multer 버전을 확인하니 2.4.0 이었다.
즉 v12 로 올려서 얻는 결과가 multer 상향이므로, overrides 로 하위 패키지만 올려
Nest 생태계(v11) 업그레이드 없이 동일한 결과를 얻는다.

- npm audit: 10건 → 0건
- 같은 메이저(2.x) 안에서의 상향이라 API 호환 위험이 낮고,
  lint·단위 31개·e2e 7개·빌드·런타임 기동·Docker 빌드까지 확인했다.
- 이 패턴(전이 의존성 취약점을 overrides 로 끊기)과 주의사항을 security.md 에 규칙으로 정리.
  platform-express 를 v12 로 올릴 때 override 를 제거해야 한다는 조건도 함께 기록.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 21:11:39 +09:00

풀스택 모노레포 기본 템플릿

NestJS(백엔드) · Vue 3(웹) · Flutter(모바일)를 하나의 저장소에서 운영하는 풀스택 템플릿입니다. 세 클라이언트는 동일한 표준 응답 포맷과 공통 에러 코드 맵을 공유하며, Docker Compose로 한 번에 구동됩니다.

구성

디렉터리 스택 역할 포트(기본)
backend/ NestJS + TypeORM REST API 서버 3000
frontend/ Vue 3 + Vite 웹 프론트엔드 5173
flutter/ Flutter + Riverpod 모바일 앱 -
db PostgreSQL 데이터베이스 5432
redis Redis 캐시 / 세션 (기본 비활성) 6379

사전 요구사항

  • Docker / Docker Compose — backend·frontend·db·redis 구동
  • Flutter SDK ^3.11 — 모바일 앱 실행용 (compose 대상 아님)

빠른 시작 (Docker)

# 1) 환경변수 파일 생성 (예제 복사)
#    실제 설정값은 루트 .env.development 한 곳에서 관리한다 (SSOT).
#    backend/frontend 는 docker-compose 가 값을 주입하므로 예제만 복사하면 된다.
cp .env.development.example .env.development                       # ← 여기에만 값 입력
cp backend/.env.development.example backend/.env.development       # (존재 필요: JWT 등 고유 시크릿)
# frontend 는 compose 가 빌드 시 값을 주입하므로 자체 env 복사 불필요

# 2) 개발 환경 기동 (코드만 수정 시)
docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.development up -d

# 3) 의존성 변경 시에만 --build
docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.development up -d --build

기동 후:

Redis 는 기본적으로 뜨지 않습니다. 필요해지면 루트 .env.{env} 에 COMPOSE_PROFILES=redis 를 설정하세요.

전체 실행/배포 명령어는 .claude/skills/docker/SKILL.md 참조.

모바일 앱 실행 (Flutter)

Flutter 는 Docker Compose 대상이 아니므로 로컬에서 직접 실행합니다.

cd flutter && cp .env.example .env && flutter pub get && flutter run

flutter/.env 의 API_URL 을 백엔드 주소로 설정합니다. (Android 에뮬레이터는 http://10.0.2.2:3000/api)

환경변수

.env* 는 커밋하지 않습니다. 각 디렉터리의 *.example 파일을 복사해 사용하세요.

루트 .env.{env} 가 단일 진실 공급원(SSOT) 입니다. backend·frontend 는 docker-compose 가 루트 값을 주입하므로 자체 env 에 값을 중복 작성하지 않습니다. (자세한 위임 구조는 CLAUDE.md 의 "환경변수 구조" 참조)

파일 용도 값 작성 위치
.env.{env}.example 루트 — 모든 설정의 SSOT (compose 주입) ✅ 여기에 작성
backend/.env.{env}.example 백엔드 — 고유 시크릿(JWT 등)만 최소 (존재 필수)
frontend/.env.{env}.example 프론트 — 빌드 시 루트 BACKEND_API_URL 주입 작성 불필요
flutter/.env.example 모바일 — API_URL (compose 비대상) ✅ 독립 관리

{env} = development | production

표준 응답 포맷

// 성공
{ "success": true, "data": { /* ... */ } }

// 실패 — 사용자에게 보이는 모든 실패는 에러 코드를 가진다
{ "success": false, "error": { "code": "VAL_001", "message": "...", "traceId": "3f1c0a2e-..." } }

// 목록 — data 안의 형태가 고정되어 있다
{ "success": true, "data": { "items": [], "pageInfo": { "hasNext": false, "nextCursor": null, "total": 0 } } }

traceId 는 요청마다 발급되는 추적 ID(x-request-id 헤더와 동일)로, 서버 로그에 같은 값이 남습니다. 사용자 문의가 들어오면 이 값으로 로그를 검색하면 됩니다.

/api/health 는 예외입니다. 모니터링 도구가 읽는 엔드포인트라 래퍼 없이 원본 형식을 반환합니다.

에러 코드는 한 곳에서 관리됩니다

backend/src/common/errors/error-codes.ts   ← 여기만 수정
        │  cd backend && npm run sync:error-codes
        ├─▶ frontend/src/shared/constants/error-codes.generated.ts   (자동 생성)
        └─▶ flutter/lib/core/api/error_lexicon.g.dart                (자동 생성)

생성 파일은 직접 수정하지 마세요. CI 가 동기화 여부를 검사합니다. 자세한 규칙은 .claude/rules/error-codes.md 참조.

로컬 개발 (Docker 없이)

DB 는 컨테이너로 띄우고 앱만 호스트에서 실행하는 방식이 가장 간단합니다.

# 1) DB 만 컨테이너로 기동 (127.0.0.1:5432 로 노출된다)
docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.development up -d db

# 2) backend — DB_HOST 기본값이 localhost 라 그대로 붙는다
cd backend && npm ci && npm run start:dev

# 3) frontend — vite dev 서버가 /api 를 localhost:3000 으로 프록시한다
cd frontend && npm ci && npm run dev

# 4) flutter
cd flutter && flutter pub get && flutter run

프론트엔드의 API 요청은 /api 상대경로로 나가고 vite dev 프록시가 백엔드로 넘깁니다. 백엔드를 다른 주소에서 띄웠다면 VITE_DEV_API_PROXY 로 대상을 바꾸세요.

커밋 전 검사

cd backend  && npm run lint && npm run test && npm run build
cd frontend && npm run lint && npm run type-check && npm run test:unit
cd flutter  && flutter analyze && flutter test

lint 는 --max-warnings 0 이라 경고 하나만 있어도 실패합니다. 자동 수정은 npm run lint:fix. 같은 검사를 CI(.github/workflows/ci.yml)가 PR 마다 수행합니다.

⚠️ 의존성을 추가·제거할 때는 컨테이너 안에서 실행하세요. Windows 에서 npm install 하면 Linux 전용 패키지가 lock 에서 잘려 Docker 빌드가 깨집니다.

docker compose -f docker-compose.yml -f docker-compose.dev.yml --env-file .env.development exec backend npm install <패키지>

개발 규칙

영역 문서
공통/보안 CLAUDE.md · .claude/rules/
응답·에러 response-format.md · error-codes.md
API 설계 api-design.md
로깅 logging.md
체크리스트 checklist.md
NestJS .claude/skills/nestjs/SKILL.md
Vue 3 .claude/skills/vue3/SKILL.md
Flutter .claude/skills/flutter/SKILL.md
Docker .claude/skills/docker/SKILL.md

디렉터리 구조

.
├── backend/    # NestJS API (Controller / Service / DTO / 공통 필터·인터셉터)
├── frontend/   # Vue 3 (pages / components / composables / stores / router)
├── flutter/    # Flutter (core / features / shared)
├── docker-compose.yml         # 베이스 정의
├── docker-compose.dev.yml     # 개발 오버라이드 (핫리로드, 포트 노출)
├── CLAUDE.md   # 프로젝트 개요 + 공통 규칙 @import
├── .github/
│   ├── workflows/ci.yml       # lint·test·build + 에러 코드 동기화 검사
│   └── pull_request_template.md
└── .claude/
    ├── settings.json   # Claude Code 권한·환경 설정
    ├── rules/          # 공통 규칙 (코딩·응답 포맷·에러 코드·API 설계·로깅·보안·환경변수·테스트)
    └── skills/         # 도메인별 개발 규칙 (nestjs·vue3·flutter·docker)
S
Description
No description provided
Readme 2 MiB
Languages
TypeScript 56.5%
C++ 14.7%
CMake 11.5%
Dart 8.9%
JavaScript 2%
Other 6.3%