ttipo 20754edf26
CI / Flutter (analyze · test) (push) Has been cancelled
CI / Backend (lint · test · e2e · build) (push) Has been cancelled
CI / Frontend (lint · type-check · test) (push) Has been cancelled
CI / 에러 코드 SSOT 동기화 검사 (push) Has been cancelled
fix: 회귀 점검에서 드러난 계약 테스트 실패와 compose 경고 수정
FILE_001/FILE_002 를 추가하면서 클라이언트 계약 테스트의 기대 목록을 갱신하지 않아
frontend·flutter 테스트가 깨져 있었다. 테스트가 제 역할을 한 셈이지만,
전수 목록 비교라는 설계 자체가 문제였다.

세 플랫폼의 사전은 backend 레지스트리에서 생성되므로 목록 일치는 구조적으로 보장되고
CI 가 드리프트를 검사한다. 전수 비교는 도메인 코드를 추가할 때마다 무의미하게 깨질 뿐이다.
검증 대상을 "클라이언트 로직이 실제로 참조하는 코드의 존재"와 네이밍 규약으로 바꾼다.
(flutter 에는 누락돼 있던 네이밍 규약 검사도 추가)

또한 기존 .env 에 없는 키들(DB_SYNCHRONIZE, THROTTLE_*)로 compose 가 매번 경고를
출력하고 있었다. 코드 기본값과 동일한 값을 compose 레벨 기본값으로 명시해 해소한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 22:00:11 +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%