A-ADM Core 방법론의 Claude Code + React/TypeScript 구현 어댑터.
A-JADM이 생성한 openapi.yaml을 시작점으로 프론트엔드 SDLC를 자동화합니다.
A-FADM은 A-JADM의 프론트엔드 확장입니다.
백엔드가 openapi.yaml을 생성한 시점부터 프론트엔드 파이프라인이 시작됩니다.
반복적인 프롬프트 재작성 대신 스킬·계약 파일·슬래시 커맨드로 일관된 React/TypeScript 코드를 생성합니다.
이 문서는 A-ADM Core의 Claude Code + React/TypeScript 구현 어댑터입니다.
방법론 본질(설계 원칙 · 추적성 규칙 · 계약 파일 스키마)은 Core 문서를 참조하세요.
openapi.yaml을 생성한 시점부터 시작합니다. [ A-JADM 백엔드 파이프라인 ]
implement-bc 완료
↓
/gen-openapi → openapi.yaml ← 두 방법론의 연결 지점
↓
[ A-FADM 프론트엔드 파이프라인 시작 ]
원칙의 전체 정의는 A-ADM Core → 설계 원칙을 참조하세요.
A-FADM은 Core 원칙 중 프론트엔드에 해당하는 세 가지를 적용합니다.
백엔드 확정 전에도 초안 openapi.yaml로 병렬 개발 가능.
API 타입 수동 작성 금지. any 타입 사용 금지.
Claude Code 환경에서 ROI 변화.
목적은 컴포넌트 명세 도출.
각 단계는 명확한 입력·산출물·게이트를 가집니다.
layout-prototype은 프로젝트당 1회, fe-prototype은 도메인별 조건부 실행합니다.
data-route 속성으로 경로를 명시한다. data-slot="content" 속성으로 도메인 화면이 삽입될 영역을 표시한다. data-slot="content" 영역에 도메인 화면 삽입. fe-component-spec {domain} 커맨드 실행 = 프로토타입 확정 선언. fe-component-spec Step 0에서 역추출. 각 스킬은 독립적인 SKILL.md로 구성됩니다.
스킬끼리는 계약 파일로만 소통합니다.
전체 앱의 Shell 구조를 단일 HTML로 생성한다.
GNB · 사이드바 · 콘텐츠 영역 · 브레드크럼 · 토스트 위치를 배치하고, 메뉴 항목에 data-route로 라우팅 구조를 표현한다.
콘텐츠 영역에 data-slot="content"를 마킹하여 fe-prototype이 삽입할 위치를 지정한다.
프로젝트당 1회 실행.
prototype-layout.html의 Shell 안에 도메인 화면을 배치하는 단일 HTML 파일 목업 생성.
필수 실행 — 모든 도메인에 대해 실행 (단순 CRUD는 간소화 모드).
HTML 직접 수정으로 빠른 피드백 루프. fe-screen-spec 개입 없음.
확정 시점: fe-component-spec {domain} 실행.
Step 0: 확정된 prototype HTML에서 fe-screen-spec.md를 역추출 + 개발자 확인.
Step 1~4: fe-screen-spec + openapi.yaml로 fe-component-spec.md 생성.
prototype-{domain}.html이 Hard gate — 미존재 시 중단.
fe-component-spec.md를 유일한 입력으로 받아 컴파일 가능한 TypeScript 스켈레톤 생성.
spec에 없는 컴포넌트는 절대 추가하지 않는다.
/implement-fe step2가 이 구조 위에 API 연동을 추가한다.
4개 값만 변경하면 배포 가능한 프로젝트 설정 파일.
스택·금지 규칙·파일 구조·슬래시 커맨드 정의를 포함.
모든 스킬과 커맨드가 이 파일을 준수한다.
스킬 간 인터페이스를 파일로 명문화합니다.
fe-component-spec.md가 없으면 fe-to-skeleton이 즉시 중단합니다.
DESIGN.md (외부 제공 · 프로젝트 루트)
│ Silent 참조 │ Soft gate 참조
↓ ↓
usecases/*.md (전체 화면 목록) Step1: shadcn 선택 · Tailwind 토큰
↓ Step3: 에러/빈 상태 색상
prototype-layout.html ← layout-prototype 산출 (프로젝트당 1회 · Shell 구조)
↓ [Shell 템플릿 제공]
fe-ui-patterns.md (프로젝트 초기 1회 작성 · CRUD 인터랙션 패턴)
↓ [Soft gate — 없으면 기본 패턴]
usecases/*.md + openapi.yaml
↓
fe-prototype {domain} → prototype-{domain}.html (필수 · 반복 수정 · 확정 후 폐기)
↓ 개발자: "이 정도면 됐다"
fe-component-spec {domain}
├→ Step 0: prototype HTML → fe-screen-spec.md (역추출 · 확인 · 보존)
└→ Step 1~4: fe-screen-spec + openapi → fe-component-spec.md (구현 명세)
↓
컴포넌트 스켈레톤 ← fe-to-skeleton (추론 없는 1:1 매핑 · DESIGN.md 비참조)
↓
Step1 구조 → Step2 API 연동 → Step3 상태 처리 ← /implement-fe (fe-component-spec + fe-screen-spec 콘텐츠 + DESIGN.md)
↓
테스트 스위트 ← /fe-gen-test (명세 1:1 추적 · DESIGN.md 비참조)
A-FADM의 프로토타이핑은 2단계로 구성됩니다.
layout-prototype이 앱 Shell을 확정한 뒤, fe-prototype이 Shell 안에 도메인 화면을 배치합니다.
fe-component-spec {domain} 실행 시일반 개발: 프로토타입(1일) + 구현(5일) = 6일 바로 구현(5일) + 재작업(3일) = 8일 → 프로토타입 ROI 명확 Claude Code: 프로토타입(0.5일) + 구현(1일) = 1.5일 바로 구현(1일) + 재작업(0.5일) = 1.5일 → ROI 불명확 — 목적이 달라져야 함
fe-component-spec {domain} 실행 시 Step 0에서 확정된 HTML을 역추출하여 fe-screen-spec.md를 자동 생성. 프로토타입이 그럴듯할수록 이해관계자는 "거의 다 됐네"라고 생각한다.
실제 구현은 0%인데 일정 압박이 생긴다.
프로토타입 배너를 항상 표시해 차단.
색상·버튼 위치 같은 시각적 피드백은 쉽게 나오지만, 깊은 요구사항 발견은 어렵다.
프로토타입은 얕은 피드백을 빠르게 수집하는 도구다.
"한 번만 더" 사이클이 반복된다.
검토 횟수를 명시적으로 한정하지 않으면 프로토타이핑 자체가 끝나지 않는다.
최대 2회 검토 후 확정 원칙.
Shell 구조 + 콘텐츠 슬롯 — fe-prototype이 이 슬롯에 화면을 삽입
<!-- prototype-layout.html -->
<div class="app-shell">
<nav data-component="GNB">
<a data-route="/" class="logo">Hotel App</a>
<a data-route="/search">검색</a>
<a data-route="/bookings">예약 내역</a>
<div data-component="UserMenu">...</div>
</nav>
<div class="layout-body">
<aside data-component="Sidebar">
<a data-route="/availability">객실 조회</a>
<a data-route="/booking/new">예약하기</a>
<a data-route="/admin/rooms">객실 관리</a>
</aside>
<main data-slot="content">
<!-- 도메인 화면이 여기에 삽입됨 -->
<div class="placeholder">
콘텐츠 영역 (fe-prototype이 채움)
</div>
</main>
</div>
<div data-slot="toast"
style="position:fixed;top:16px;right:16px;">
<!-- 토스트 알림 위치 -->
</div>
</div>
반응형 breakpoint 데모 — 레이아웃 검증용
<!-- 반응형 규칙 (Tailwind CDN) -->
<style>
.layout-body {
display: grid;
grid-template-columns: 240px 1fr;
}
/* tablet */
@media (max-width: 1024px) {
.layout-body {
grid-template-columns: 64px 1fr;
}
aside span.label { display: none; }
}
/* mobile */
@media (max-width: 640px) {
.layout-body {
grid-template-columns: 1fr;
}
aside { display: none; }
}
</style>
<!-- 레이아웃 시뮬레이터 -->
<div style="position:fixed;bottom:16px;left:16px;
background:#1F2937;color:white;
padding:12px;border-radius:8px;z-index:9999;">
<div>레이아웃 시뮬레이터</div>
<button onclick="setViewport('mobile')">
Mobile
</button>
<button onclick="setViewport('tablet')">
Tablet
</button>
<button onclick="setViewport('desktop')">
Desktop
</button>
</div>
컴포넌트 경계 표시 — 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>
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 사용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/
├── app/
│ ├── layout/ # Shell 컴포넌트 (prototype-layout.html 기반)
│ │ ├── AppShell.tsx # GNB + Sidebar + Content 레이아웃
│ │ ├── GNB.tsx # 글로벌 네비게이션 바
│ │ ├── Sidebar.tsx # 사이드바 네비게이션
│ │ └── Breadcrumb.tsx # 브레드크럼
│ └── routes.tsx # React Router 설정
├── 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 자동 생성
슬래시 커맨드는 A-ADM Core 워크플로를 React/TypeScript 환경에서 실행하는 진입점입니다. A-JADM의 openapi.yaml에서 시작합니다.
CLAUDE.md에 정의된 3개 커맨드가 셋업·구현·테스트를 자동화합니다.
모든 커맨드는 CLAUDE.md와 fe-component-spec.md를 읽어 추론 없이 실행합니다.
/implement-fe는 추가로 DESIGN.md를 Soft gate로 참조합니다.
CLAUDE.md를 읽어 Vite 프로젝트 생성 · 패키지 설치 · 폴더 구조 · 공통 설정 파일 생성.
최초 1회 실행.
--gen-types로 openapi 타입까지 한 번에 생성.
/setup-fe # 기본 셋업 /setup-fe --gen-types # 셋업 + openapi 타입 생성 /setup-fe --dry-run # 실행 계획만 출력
fe-component-spec.md를 읽어 step1→step2→step3 순서로 구현.
fe-component-spec.md 없으면 즉시 중단하고 fe-component-spec 스킬 실행을 안내.
DESIGN.md Soft gate: DESIGN.md 없으면 경고 후 Tailwind 기본값으로 진행. Step1(shadcn 선택·Tailwind 토큰) · Step3(에러/빈 상태 색상)에 참조.
/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-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 타입 생성
# 사전 — 디자인 시스템 파일 배치 (외부 제공)
DESIGN.md → 프로젝트 루트에 배치 (layout-prototype·fe-prototype·/implement-fe가 참조)
# 0-L단계 — 레이아웃 프로토타이핑 (프로젝트당 1회)
layout-prototype → prototype-layout.html (Shell 구조 · 라우팅 · 반응형 breakpoint)
(DESIGN.md: Silent 참조 · 계약 파일로 보존)
# 0-D단계 — 도메인 화면 프로토타이핑 (v1.4: 필수 · 반복 가능)
fe-prototype availability → prototype-availability.html
[반복: "카드로 바꿔줘" → HTML 직접 수정 → 즉시 확인 → 만족할 때까지]
fe-prototype booking → prototype-booking.html
[반복: "위자드 2단계로 줄여줘" → HTML 직접 수정 → 즉시 확인]
# ①단계 — 컴포넌트 명세 (v1.4: Step 0에서 fe-screen-spec 역추출 + 확인)
fe-component-spec availability
→ Step 0: prototype HTML → fe-screen-spec.md (역추출·확인)
→ Step 1~4: fe-screen-spec + openapi → fe-component-spec.md
fe-component-spec booking
→ Step 0: prototype HTML → fe-screen-spec.md (역추출·확인)
→ Step 1~4: fe-screen-spec + openapi → fe-component-spec.md
# ②단계 — 스켈레톤 생성
fe-to-skeleton availability → types · api · hooks · components (stub · DESIGN.md 비참조)
fe-to-skeleton booking → types · api · hooks · components (stub · DESIGN.md 비참조)
# ③단계 — 구현 (도메인 단위 · DESIGN.md: Soft gate · prototype-layout.html: Shell 참조)
/implement-fe search step1 → SearchPage + DateRangePicker + GuestRoomCounter (DESIGN.md → shadcn 선택 · 토큰)
/implement-fe search step2 → Zustand store (searchCriteria)
/implement-fe availability step1 → AvailabilityPage + RoomCard + PackageCard (DESIGN.md → shadcn 선택 · 토큰)
/implement-fe availability step2 → useAvailability (TanStack Query)
/implement-fe availability step3 → 로딩 Skeleton · 에러 · 빈 상태 (DESIGN.md → 상태 색상)
/implement-fe booking step1 → BookingFormPage + BookingSummaryCard (DESIGN.md → shadcn 선택 · 토큰)
/implement-fe booking step2 → useCreateBooking (useMutation) · 409 충돌 처리
/implement-fe booking step3 → BookingConfirmPage (DESIGN.md → 상태 색상)
# ④단계 — 테스트
/fe-gen-test availability → useAvailability · RoomCard · PackageCard 테스트
/fe-gen-test availability --contract → API mock 계약 테스트
/fe-gen-test booking → useCreateBooking · BookingFormPage 테스트
코드 생성 후 실제로 실행하기 위한 환경 구성 절차입니다.
/setup-fe 커맨드가 대부분을 자동화하며, 수동 개입이 필요한 단계를 명시합니다.
--gen-types 옵션 추가.cp .env.example .env 후 VITE_API_BASE_URL을 실제 백엔드 주소로 변경. # 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 수정
백엔드 openapi.yaml을 TypeScript 타입으로 변환합니다.
이 타입이 모든 컴포넌트의 타입 추론 기반이 됩니다.
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']
npm run dev 실행. 포트 3000. /api/* 요청은 vite.config.ts 프록시를 통해 백엔드로 전달 — 브라우저에서 CORS 발생 없음./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,
}
}
npm run gen:types로 타입 최신화 필수. npm run build로 TypeScript 컴파일 + Vite 번들링. dist/..env.development · .env.production으로 환경별 API 주소 분리. VITE_API_BASE_URL이 실제 서버를 가리킨다.dist/는 순수 정적 파일. # 빌드 전 타입 최신화
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 run dev | 개발 서버 (port 3000, 프록시 포함) | 개발 중 항상 |
npm run build | TypeScript 컴파일 + Vite 번들링 → dist/ | 배포 전 |
npm run preview | 빌드 결과물 로컬 확인 (port 4173) | 배포 전 검증 |
npm run test | Vitest 테스트 실행 | 구현 완료 후, CI |
npm run test:ui | Vitest UI 모드 (브라우저 결과 확인) | 개발 중 |
npm run gen:types | openapi.yaml → src/types/api.d.ts | API 변경 시마다 |
npm run gen:types:watch | openapi.yaml 변경 감지 모드 | API 활발히 변경 중 |