CLAUDE CODE ADAPTER · VERSION 1.0 · MARCH 2026

AI-Driven Frontend Application
Development Methodology

A-ADM Core 방법론의 Claude Code + React/TypeScript 구현 어댑터.
A-JADM이 생성한 openapi.yaml을 시작점으로 프론트엔드 SDLC를 자동화합니다.

5
SDLC 단계
4
Claude Code 스킬
2
계약 파일
3
슬래시 커맨드
A-ADM 시리즈
← A-JADM Java Backend · A-GADM Go Backend · ● A-FADM Frontend · React/TypeScript
← A-JADM (백엔드 방법론)

A-FADM이란

A-FADM은 A-JADM의 프론트엔드 확장입니다.
백엔드가 openapi.yaml을 생성한 시점부터 프론트엔드 파이프라인이 시작됩니다.
반복적인 프롬프트 재작성 대신 스킬·계약 파일·슬래시 커맨드로 일관된 React/TypeScript 코드를 생성합니다.

A-ADM CORE 참조

이 문서는 A-ADM CoreClaude Code + React/TypeScript 구현 어댑터입니다.
방법론 본질(설계 원칙 · 추적성 규칙 · 계약 파일 스키마)은 Core 문서를 참조하세요.

A-ADM Core 보기 → 이 어댑터 고유 내용: openapi.yaml 연동 · React/TS 고정 스택 · 프로토타이핑 ROI 분석
계약
파일 기반 스킬 연결
추론
제거 — 명세가 결정
선택
프로토타입 조건부 실행
추적
명세 1:1 테스트

A-JADM과의 연결 구조

A-FADM은 A-JADM의 /gen-openapi 커맨드가 openapi.yaml을 생성한 시점부터 시작합니다.
백엔드 팀이 API 명세를 확정하기 전에도 openapi.yaml 초안을 기반으로 프론트엔드 파이프라인을 병렬로 진행할 수 있습니다.
[ A-JADM 백엔드 파이프라인 ]
implement-bc 완료
    ↓
/gen-openapi → openapi.yaml   ← 두 방법론의 연결 지점
    ↓
[ A-FADM 프론트엔드 파이프라인 시작 ]

세 가지 핵심 축

스킬 (Skill)
재사용 가능한 프롬프트 모듈
SKILL.md 오케스트레이터 구조.
fe-prototype · fe-component-spec · fe-to-skeleton 세 스킬이 순서대로 실행되며 각 산출물이 다음 스킬의 입력이 된다.
계약 파일 (Contract)
스킬 간 인터페이스
openapi.yaml · fe-component-spec.md.
스킬이 서로를 직접 호출하지 않고 파일로 소통.
fe-component-spec.md가 없으면 fe-to-skeleton이 즉시 중단.
슬래시 커맨드
자동화 실행 단위
CLAUDE.md에 정의된 /implement-fe · /fe-gen-test.
계약 파일을 읽어 추론 없이 3단계 레이어 순서로 실행.

3대 설계 원칙

원칙의 전체 정의는 A-ADM Core → 설계 원칙을 참조하세요.
A-FADM은 Core 원칙 중 프론트엔드에 해당하는 세 가지를 적용합니다.

① API-Contract First
openapi.yaml이 시작점

백엔드 확정 전에도 초안 openapi.yaml로 병렬 개발 가능.

② Type Safety End-to-End
openapi-typescript 자동 생성

API 타입 수동 작성 금지. any 타입 사용 금지.

③ Prototype as Spec
프로토타입이 명세 역할

Claude Code 환경에서 ROI 변화.
목적은 컴포넌트 명세 도출.

5단계 파이프라인

각 단계는 명확한 입력·산출물·게이트를 가집니다.
fe-prototype은 조건에 따라 선택적으로 실행합니다.

fe-prototype (선택) → 검토 확정 → fe-component-spec fe-to-skeleton /implement-fe /fe-gen-test
0
프로토타이핑 — 선택적
fe-prototype · 단일 HTML · 검토 후 폐기
1
핵심 흐름 1~2개로 scope 한정
모든 케이스를 커버하지 않는다. 화면 구조가 불확실한 부분만 집중적으로 그린다.
2
단일 HTML 파일로 생성
Tailwind CDN · mock 데이터 · data-component 경계 표시 · 상태 시뮬레이터 패널 포함.
React/TS 구조 금지.
3
검토 확정 → 명세에 반영
data-component 속성이 fe-component-spec.md 컴포넌트 분리 기준이 된다.
파일은 명세 확정 후 삭제.
실행 조건 — 하나라도 해당하면 실행
  • 화면 구조가 불확실하다 (컴포넌트 수를 모른다)
  • 이해관계자 승인이 필요하다 (비개발자)
  • 새로운 인터랙션 패턴이 포함된다
단순 CRUD 어드민·디자인 시스템 확정 화면은 이 단계를 건너뛴다.
1
컴포넌트 명세
fe-component-spec · API Contract · UI 동작 · 컴포넌트 분리
1
API Contract 추출
openapi.yaml에서 대상 도메인 엔드포인트·스키마 추출.
없으면 수동 입력.
fe-prototype 산출물이 있으면 data-component에서 컴포넌트 분리 초안 자동 추출.
2
화면 동작 명세화
초기 상태 · 인터랙션(트리거→처리→부작용) · 에러/로딩/빈 상태 처리를 모두 명문화.
추론 없는 구현의 기반.
3
품질 게이트 통과
6개 항목 체크 후 진행.
하나라도 누락이면 해당 항목 보완 후 진행.
품질 게이트 6항목
□ 모든 API 응답 타입이 TypeScript로 정의됐는가
□ 에러 코드별 UI 처리가 명시됐는가
□ 로딩·에러·빈 상태 세 가지가 정의됐는가
□ 컴포넌트 분리 기준과 Props가 정의됐는가
□ 인터랙션이 트리거→처리→부작용 형태인가
□ queryKey가 ['{domain}', params] 형태인가
산출물: fe-component-spec.md
2
스켈레톤 생성
fe-to-skeleton · 추론 없는 1:1 매핑 · 컴파일 가능한 껍데기
1
타입 파일 생성 (먼저)
spec의 타입 정의 섹션 → types/{domain}.types.ts.
다른 파일이 참조하므로 반드시 먼저 생성.
2
API stub · 훅 stub 생성
api/{domain}.api.ts (TODO placeholder) · hooks/use{Domain}.ts (enabled: false).
/implement-fe step2에서 채운다.
3
컴포넌트 파일 생성
spec의 컴포넌트 분리 테이블 기반으로 1:1 생성.
mock 데이터 사용, 상태 처리 분기는 TODO 주석.
spec에 없는 컴포넌트는 추가하지 않는다.
생성 순서 (강제)
1. types/{domain}.types.ts
2. api/{domain}.api.ts
3. hooks/use{Domain}*.ts
4. __mocks__/{domain}.mock.ts
5. components/*.tsx
spec에 없는 컴포넌트 추가 금지.
추론 없는 1:1 매핑.
3
구현
/implement-fe · 3단계 레이어 순서 강제
Step 1 — 구조
컴포넌트 파일 생성
타입 정의 확정
mock 데이터 사용
API 연동 없음
Step 2 — API 연동
useQuery/useMutation 구현
queryKey 패턴 적용
axios 함수 구현
openapi 타입 연결
Step 3 — 상태 처리
로딩 Skeleton
에러 toast + 재시도
빈 상태 Empty UI
409 충돌 등 도메인 에러
4
테스트
/fe-gen-test · Vitest + Testing Library · 명세 1:1 추적
hooks
useQuery 파라미터 검증
queryKey 패턴 확인
API mock 계약 테스트
components
렌더링 스냅샷
인터랙션 이벤트
로딩/에러/빈 상태 분기
contract
API mock 응답 계약
타입 일치 검증
에러 핸들링 경로
추적 원칙: fe-component-spec.md의 UI 동작 1개 = Vitest 테스트 케이스 1개.
명세가 없는 동작은 테스트하지 않는다.

4개 스킬 상세

각 스킬은 독립적인 SKILL.md로 구성됩니다.
스킬끼리는 계약 파일로만 소통합니다.

fe-prototype

UI 프로토타이핑 스킬

단일 HTML 파일 목업 생성.
핵심 흐름 1~2개 한정.
data-component 속성으로 컴포넌트 경계 표시.
상태 시뮬레이터(로딩/에러/빈 상태) 패널 내장. 검토 후 폐기.

입력: UC명세서 + openapi.yaml(선택) / 산출: prototype-{domain}.html
금지: React/TS 구조, 실제 API 호출, 픽셀 퍼펙트 디자인
fe-component-spec

컴포넌트 명세 스킬

API Contract · 화면 동작 · 상태 처리 · 컴포넌트 분리 · 타입 정의를 fe-component-spec.md에 명문화.
fe-prototype 산출물이 있으면 data-component에서 컴포넌트 분리 초안 자동 추출.

입력: openapi.yaml + UC명세서 + prototype(선택) / 산출: fe-component-spec.md
fe-to-skeleton

스켈레톤 생성 스킬

fe-component-spec.md를 유일한 입력으로 받아 컴파일 가능한 TypeScript 스켈레톤 생성.
spec에 없는 컴포넌트는 절대 추가하지 않는다.
/implement-fe step2가 이 구조 위에 API 연동을 추가한다.

입력: fe-component-spec.md / 산출: types · api · hooks · components
CLAUDE.md

프로젝트 고정 규칙

4개 값만 변경하면 배포 가능한 프로젝트 설정 파일.
스택·금지 규칙·파일 구조·슬래시 커맨드 정의를 포함.
모든 스킬과 커맨드가 이 파일을 준수한다.

설정: name · backend-api-base · openapi-spec · feature-root
계약 파일 스키마와 파이프라인 원칙은 A-ADM Core → 계약 파일을 참조하세요.
A-FADM은 A-JADM의 openapi.yaml을 추가 입력으로 사용합니다.

계약 파일 체계

스킬 간 인터페이스를 파일로 명문화합니다.
fe-component-spec.md가 없으면 fe-to-skeleton이 즉시 중단합니다.

openapi.yaml
A-JADM /gen-openapi 산출
paths → API 엔드포인트 목록
schemas → 요청/응답 TypeScript 타입 기반
operationId → axios 함수명 기반
error responses → UI 에러 처리 기준
소비자: fe-component-spec · fe-to-skeleton
fe-component-spec.md
fe-component-spec 스킬 산출
API Contract → 타입·에러 코드 정의
화면 동작 → 인터랙션 1:1 테스트 추적
상태 처리 → 로딩/에러/빈 상태 UI
컴포넌트 분리 → Props · 파일 경로
타입 정의 → openapi import 또는 직접 정의
소비자: fe-to-skeleton · /implement-fe · /fe-gen-test

파일 간 흐름

UC명세서 + openapi.yaml
       ↓
prototype-{domain}.html   ← fe-prototype 산출 (선택, 검토 후 폐기)
       ↓ [검토 확정 — data-component 경계 추출]
fe-component-spec.md      ← fe-component-spec 산출 (계약 파일)
       ↓
컴포넌트 스켈레톤         ← fe-to-skeleton   (추론 없는 1:1 매핑)
       ↓
Step1 구조 → Step2 API 연동 → Step3 상태 처리  ← /implement-fe
       ↓
테스트 스위트             ← /fe-gen-test      (명세 1:1 추적)

프로토타이핑 — 가치와 한계

Claude Code 환경에서 프로토타이핑의 목적은 "재작업 비용 절감"이 아닙니다.
fe-component-spec.md 품질 확보와 이해관계자 소통이 목적입니다.

Claude Code 환경에서 ROI 변화

구현 비용이 낮아질수록 "재작업 비용 절감" 명분이 약해진다
일반 개발:
  프로토타입(1일) + 구현(5일) = 6일
  바로 구현(5일) + 재작업(3일) = 8일
  → 프로토타입 ROI 명확

Claude Code:
  프로토타입(0.5일) + 구현(1일) = 1.5일
  바로 구현(1일) + 재작업(0.5일) = 1.5일
  → ROI 불명확 — 목적이 달라져야 함

달라진 목적

명세 품질 확보
fe-component-spec.md를 잘 쓰려면 화면 구조가 머릿속에 있어야 한다.
프로토타입이 그 직관을 만든다.
이해관계자 소통
문서보다 화면이 빠르게 피드백을 끌어낸다.
10페이지 명세보다 클릭 가능한 화면이 대화를 만든다.

본질적 한계 — 알고 사용할 것

착각 효과

프로토타입이 그럴듯할수록 이해관계자는 "거의 다 됐네"라고 생각한다.
실제 구현은 0%인데 일정 압박이 생긴다.
프로토타입 배너를 항상 표시해 차단.

표면적 피드백

색상·버튼 위치 같은 시각적 피드백은 쉽게 나오지만, 깊은 요구사항 발견은 어렵다.
프로토타입은 얕은 피드백을 빠르게 수집하는 도구다.

수렴 실패

"한 번만 더" 사이클이 반복된다.
검토 횟수를 명시적으로 한정하지 않으면 프로토타이핑 자체가 끝나지 않는다.
최대 2회 검토 후 확정 원칙.

핵심 규칙:
프로토타입 목적을 코드 작성 전에 명시적으로 결정한다.
"이해관계자 승인용 → 버린다" 또는 "컴포넌트 구조 확인용 → 명세에 반영 후 버린다".
목적이 정해지면 어느 수준까지 만들지, 언제 멈출지가 자연스럽게 결정된다.

fe-prototype 핵심 구현 패턴

컴포넌트 경계 표시 — fe-component-spec.md의 입력이 된다

<div data-component="RoomCard"
     data-props="room, nights, onBook">
  <!-- RoomCard 내용 -->
</div>

<div data-component="SearchSummaryBar"
     data-props="criteria">
  <!-- SearchSummaryBar 내용 -->
</div>

상태 시뮬레이터 패널 — 이해관계자 검토 시 엣지 케이스 확인

<div style="position:fixed;bottom:16px;right:16px;
  background:#1F2937;color:white;
  padding:12px;border-radius:8px;z-index:9999;">
  <div>상태 시뮬레이터</div>
  <button onclick="setUIState('loading')">로딩</button>
  <button onclick="setUIState('error')">에러</button>
  <button onclick="setUIState('empty')">빈 목록</button>
  <button onclick="setUIState('normal')">정상</button>
</div>
FIXED STACK React 18 TypeScript 5 TanStack Query v5 shadcn/ui + Tailwind openapi-typescript Vitest any 타입 금지

고정 스택 규칙

CLAUDE.md에 선언된 스택과 금지 규칙은 모든 스킬과 커맨드가 따릅니다.
A-JADM의 Lombok 금지 규칙과 동일한 역할입니다.

고정 스택

역할라이브러리
UI 프레임워크React 18 + TypeScript 5
서버 상태TanStack Query v5
클라이언트 상태Zustand
UI 컴포넌트shadcn/ui + Tailwind CSS
API 타입openapi-typescript
HTTP 클라이언트axios
테스트Vitest + Testing Library
라우팅React Router v6

절대 금지 규칙

금지  any 타입 사용
금지  useEffect로 서버 데이터 fetch → TanStack Query 사용
금지  CSS 인라인 style 속성 → Tailwind 클래스 사용
금지  prop drilling 3단 초과 → Zustand store 사용
금지  default export 혼용 → named export 통일
금지  컴포넌트 내 직접 axios 호출 → hooks/ 래퍼로 분리

핵심 코딩 패턴

TanStack Query — queryKey 패턴

// ✅ 올바른 패턴
const { data } = useQuery({
  queryKey: ['orders', { page, status }],
  queryFn: () => orderApi.getList({ page, status }),
})

// ✅ mutation 후 invalidate
const mutation = useMutation({
  mutationFn: orderApi.cancel,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['orders'] })
  },
})

에러·로딩·빈 상태 처리 패턴

// ✅ 올바른 순서
if (isPending) return <OrderListSkeleton />
if (isError) return (
  <ErrorState onRetry={() => refetch()} />
)
if (!data?.content.length) return <EmptyState />

// openapi 타입 사용 패턴
import type { components } from '@/types/api'
type Order = components['schemas']['OrderResponse']
type Summary = Pick<Order, 'orderId' | 'status'>

컴포넌트 파일 구조

src/
├── features/
│   └── {domain}/                      # 예: order, availability, booking
│       ├── components/
│       │   ├── {Domain}ListPage.tsx   # 페이지 컴포넌트 (라우팅 진입점)
│       │   ├── {Domain}Card.tsx       # 카드/행 렌더링
│       │   └── {Domain}Form.tsx       # 폼 컴포넌트
│       ├── hooks/
│       │   ├── use{Domain}List.ts     # useQuery 래퍼
│       │   └── use{Domain}Mutation.ts # useMutation 래퍼
│       ├── api/
│       │   └── {domain}.api.ts        # axios 호출 함수
│       ├── types/
│       │   └── {domain}.types.ts      # 로컬 타입 (openapi 타입 re-export)
│       └── fe-component-spec.md       # 계약 파일 (스킬 산출물)
├── shared/
│   ├── components/                    # 공통 UI (Button, Modal 등)
│   ├── stores/                        # Zustand stores
│   └── lib/
│       ├── axios.ts                   # axios 인스턴스
│       └── queryClient.ts             # TanStack Query 클라이언트
└── types/
    └── api.d.ts                       # openapi-typescript 자동 생성
CLAUDE CODE ADAPTER 고유 내용

슬래시 커맨드는 A-ADM Core 워크플로를 React/TypeScript 환경에서 실행하는 진입점입니다. A-JADM의 openapi.yaml에서 시작합니다.

슬래시 커맨드 레퍼런스

CLAUDE.md에 정의된 3개 커맨드가 셋업·구현·테스트를 자동화합니다.
모든 커맨드는 CLAUDE.md와 fe-component-spec.md를 읽어 추론 없이 실행합니다.

/setup-fe [--gen-types] [--dry-run]

프로젝트 셋업 커맨드

CLAUDE.md를 읽어 Vite 프로젝트 생성 · 패키지 설치 · 폴더 구조 · 공통 설정 파일 생성.
최초 1회 실행.
--gen-types로 openapi 타입까지 한 번에 생성.

/setup-fe                # 기본 셋업
/setup-fe --gen-types    # 셋업 + openapi 타입 생성
/setup-fe --dry-run      # 실행 계획만 출력
/implement-fe {domain} [step]

도메인 구현 커맨드

fe-component-spec.md를 읽어 step1→step2→step3 순서로 구현.
파일 없으면 즉시 중단하고 fe-component-spec 스킬 실행을 안내.

/implement-fe order          # 전체 3단계 순차
/implement-fe order step1    # 구조만 (컴포넌트 + 타입)
/implement-fe order step2    # API 연동 (TanStack Query)
/implement-fe order step3    # 상태 처리 (로딩/에러/빈)
/implement-fe order --dry-run  # 생성 파일 목록만 출력
/fe-gen-test {domain} [scope]

테스트 생성 커맨드

fe-component-spec.md의 UI 동작 명세 → Vitest + Testing Library 테스트 생성.
명세 1개 동작 = 테스트 케이스 1개 (1:1 추적).

/fe-gen-test order              # 전체
/fe-gen-test order hooks        # hooks/ 단위 테스트만
/fe-gen-test order components   # 컴포넌트 렌더링만
/fe-gen-test order --contract   # API mock 계약 테스트

전체 커맨드 실행 시퀀스 — 호텔 예약 시스템 예시

# 사전 — 프로젝트 환경 구성 (최초 1회)
/setup-fe --gen-types         → Vite 설치 · 패키지 · 폴더 구조 · openapi 타입 생성

# 0단계 — 프로토타이핑 (화면 구조 불확실 + 이해관계자 승인 필요)
fe-prototype                  → prototype-availability.html (검토 후 폐기)
fe-prototype                  → prototype-booking.html      (검토 후 폐기)

# 1단계 — 컴포넌트 명세 (openapi.yaml + 프로토타입 검토 결과 반영)
fe-component-spec availability → fe-component-spec.md (search · availability · detail)
fe-component-spec booking      → fe-component-spec.md (booking form · confirm)

# 2단계 — 스켈레톤 생성
fe-to-skeleton availability    → types · api · hooks · components (stub)
fe-to-skeleton booking         → types · api · hooks · components (stub)

# 3단계 — 구현 (도메인 단위)
/implement-fe search step1     → SearchPage + DateRangePicker + GuestRoomCounter
/implement-fe search step2     → Zustand store (searchCriteria)
/implement-fe availability step1  → AvailabilityPage + RoomCard + PackageCard
/implement-fe availability step2  → useAvailability (TanStack Query)
/implement-fe availability step3  → 로딩 Skeleton · 에러 · 빈 상태
/implement-fe booking step1    → BookingFormPage + BookingSummaryCard
/implement-fe booking step2    → useCreateBooking (useMutation) · 409 충돌 처리
/implement-fe booking step3    → BookingConfirmPage

# 4단계 — 테스트
/fe-gen-test availability      → useAvailability · RoomCard · PackageCard 테스트
/fe-gen-test availability --contract  → API mock 계약 테스트
/fe-gen-test booking           → useCreateBooking · BookingFormPage 테스트

실행 환경

코드 생성 후 실제로 실행하기 위한 환경 구성 절차입니다.
/setup-fe 커맨드가 대부분을 자동화하며, 수동 개입이 필요한 단계를 명시합니다.

전제 조건: Node.js 20 LTS 이상, npm 10 이상.
CLAUDE.md의 4개 값(name · backend-api-base · openapi-spec · feature-root)이 채워진 상태에서 실행합니다.
1
프로젝트 초기 셋업
/setup-fe · 최초 1회 실행
1
CLAUDE.md 준비
fe-skill-pipeline의 CLAUDE.md를 프로젝트 루트에 복사.
name · backend-api-base · openapi-spec · feature-root 4개 값 수정.
2
/setup-fe 실행
Vite 프로젝트 생성 → 고정 스택 패키지 설치 → 폴더 구조 생성 → 공통 설정 파일 생성.
openapi.yaml이 준비됐다면 --gen-types 옵션 추가.
3
환경변수 설정 (수동)
cp .env.example .envVITE_API_BASE_URL을 실제 백엔드 주소로 변경.
이 파일은 Git에 커밋하지 않는다.
# CLAUDE.md 4개 값 수정 후
/setup-fe --gen-types

# 생성되는 파일들
src/shared/lib/axios.ts
src/shared/lib/queryClient.ts
src/app/routes.tsx
src/test/setup.ts
src/types/api.d.ts    # --gen-types 시
vite.config.ts
vitest.config.ts
.env.example

# 수동 단계
cp .env.example .env
# VITE_API_BASE_URL 수정
2
openapi-typescript 타입 생성
A-JADM /gen-openapi 완료 후 · API 변경 시마다

백엔드 openapi.yaml을 TypeScript 타입으로 변환합니다.
이 타입이 모든 컴포넌트의 타입 추론 기반이 됩니다.

타입 동기화 원칙: 백엔드 API가 변경되면 npm run gen:types를 먼저 실행합니다.
타입 에러가 변경 영향 범위를 자동으로 알려줍니다.
# 최초 생성
npm run gen:types

# API 변경 감지 모드
npm run gen:types:watch

# 생성된 타입 사용 패턴
import type { components } from '@/types/api'
type Room = components['schemas']['RoomAvailability']
type Booking = components['schemas']['BookingResponse']
3
개발 서버 실행 및 백엔드 연동
Vite dev server · 프록시 · CORS
1
개발 서버 시작
npm run dev 실행. 포트 3000.
/api/* 요청은 vite.config.ts 프록시를 통해 백엔드로 전달 — 브라우저에서 CORS 발생 없음.
2
백엔드 없이 개발 시
msw(Mock Service Worker)로 API를 모킹.
/fe-gen-test --contract가 생성한 핸들러를 개발 환경에서 활성화해 사용.
# 개발 서버 실행
npm run dev  →  http://localhost:3000

# 프록시 동작
브라우저 → localhost:3000/api/rooms
  → Vite 프록시
    → localhost:8080/api/rooms (백엔드)

# vite.config.ts (자동 생성)
proxy: {
  '/api': {
    target: 'http://localhost:8080',
    changeOrigin: true,
  }
}
4
빌드 및 배포
production build · 환경별 .env · 정적 파일 서빙
1
프로덕션 빌드
빌드 전 npm run gen:types로 타입 최신화 필수.
npm run build로 TypeScript 컴파일 + Vite 번들링.
결과물은 dist/.
2
환경별 .env 분리
.env.development · .env.production으로 환경별 API 주소 분리.
프로덕션에서 VITE_API_BASE_URL이 실제 서버를 가리킨다.
3
SPA 라우팅 폴백
dist/는 순수 정적 파일.
Nginx · S3 + CloudFront 어디든 서빙 가능.
SPA 라우팅을 위해 404 → index.html 폴백 설정이 필수.
# 빌드 전 타입 최신화
npm run gen:types

# 프로덕션 빌드
npm run build   →  dist/

# 빌드 결과 로컬 확인
npm run preview  →  http://localhost:4173

# 환경별 .env
.env.development  VITE_API_BASE_URL=http://localhost:8080
.env.production   VITE_API_BASE_URL=https://api.example.com

# Nginx SPA 폴백 (배포 시 필수)
location / {
  try_files $uri $uri/ /index.html;
}

npm scripts 요약

명령어역할실행 시점
npm run dev개발 서버 (port 3000, 프록시 포함)개발 중 항상
npm run buildTypeScript 컴파일 + Vite 번들링 → dist/배포 전
npm run preview빌드 결과물 로컬 확인 (port 4173)배포 전 검증
npm run testVitest 테스트 실행구현 완료 후, CI
npm run test:uiVitest UI 모드 (브라우저 결과 확인)개발 중
npm run gen:typesopenapi.yaml → src/types/api.d.tsAPI 변경 시마다
npm run gen:types:watchopenapi.yaml 변경 감지 모드API 활발히 변경 중