CLAUDE.md — @boospatch/ui
부스패치 디자인시스템의 단일 출처. 토큰·primitive·Pretendard 폰트를 묶어 메인 레포(boospatch-frontend)와 카탈로그 앱(apps/lab/src/app/)이 동일 패키지로 소비.
전체 운영 룰: 루트
/CLAUDE.md. 자세한 컨벤션:.claude/skills/boospatch-component-conventions/SKILL.md.
패키지 구조 — Primitives · Charts · Maps
packages/design-system/
├── package.json ─ name="@boospatch/ui", peer react>=19, recharts (optional)
├── src/
│ ├── index.ts ─ primitives entry (Button·Txt·Badge 등). 컴포넌트·utility만 export, 토큰 X
│ ├── charts/ ─ 차트 카테고리 (`@boospatch/ui/charts`)
│ │ ├── ChartContainer.tsx (foundation, generic)
│ │ ├── ChartTooltip.tsx (foundation, generic)
│ │ ├── RadarChart.tsx (generic — recharts 의존하지만 도메인 무관)
│ │ ├── shared/ (axis ticks · gradient · scatter · utils)
│ │ ├── domain/ (부동산 데이터 모양과 결합)
│ │ │ ├── ListingPriceBandsChart.tsx
│ │ │ ├── RealTradesChart.tsx
│ │ │ ├── GapPriceChart.tsx
│ │ │ └── SaleQuantityChart.tsx
│ │ └── index.ts (foundation + generic + domain 일괄 re-export)
│ ├── maps/ ─ 맵 카테고리 (`@boospatch/ui/maps`)
│ │ ├── useNaverMapScript.ts (foundation)
│ │ ├── MapCanvas.tsx (foundation)
│ │ ├── MapTooltip.tsx (foundation)
│ │ ├── useTooltipHoverBridge.ts (foundation)
│ │ ├── naver-maps.d.ts (ambient SDK types)
│ │ ├── domain/ (부동산 마커)
│ │ │ ├── PillMarker.tsx
│ │ │ ├── DotMarker.tsx
│ │ │ └── ClusterBubble.tsx
│ │ └── index.ts
│ ├── tokens.css ─ 토큰 진입 (3계층 re-import: shared → web → app)
│ ├── tokens/
│ │ ├── shared.css ─ palette · semantic alias · font · 의미 typescale · 픽셀 alias · radius · animation 전체
│ │ ├── web.css ─ 용도 typescale (데스크탑) · spacing 0.5/1.5/2.5 (밀도형) · z-index · ring · gradient · scrollbar utility
│ │ └── app.css ─ typescale 모바일 톤다운 · spacing collapse · ring transparent · *신규* elevation/safe-area/touch-target ([data-platform="app"] 컨텍스트)
│ ├── fonts.css ─ Pretendard @font-face (Variable)
│ ├── fonts/ ─ PretendardVariable.woff2 자산
│ ├── components/ ─ <Name>.tsx primitive
│ └── utils/
│ └── cn.ts ─ clsx + tailwind-merge
└── CLAUDE.md
카테고리 구분 원칙:
- primitives (
src/components/, root entry): 순수 UI — 외부 도메인·라이브러리 의존 없음. Button/Tag/Input 등 어디서든 동작. - charts (
src/charts/,/chartssubpath): 시각화 카테고리. 직접 자식은 generic (RadarChart, foundations).domain/서브폴더는 부동산 데이터 모양과 강결합. - maps (
src/maps/,/mapssubpath): Naver Maps SDK 위의 인프라. 직접 자식은 generic (MapCanvas 등).domain/서브폴더는 부동산 단지 시각화 마커.
단일 entry 컨벤션: charts / maps 한 entry에서 generic + domain 모두 export. 구분은 폴더 트리 + 카탈로그 배지가 책임. 외부 호환 layer 없음.
소비측 import:
import "@boospatch/ui/tokens.css";
import "@boospatch/ui/fonts.css";
// primitives
import { Button, Txt, Badge } from "@boospatch/ui";
// charts (generic + domain 한 entry)
import { RadarChart, ChartContainer, ListingPriceBandsChart } from "@boospatch/ui/charts";
// maps (foundation + 도메인 마커)
import { MapCanvas, useNaverMapScript, PillMarker } from "@boospatch/ui/maps";
// recharts는 차트 사용 시 consumer가 별도 install (optional peer dep).
토큰 의미 계층 (palette → semantic → component)
토큰 의미는 3계층. 상위 계층은 하위만 참조, 역참조 금지.
| 계층 | 위치 | 역할 |
|---|---|---|
| palette | tokens/shared.css 상단 | 원시 색상 (--color-primary-400, --color-gray-50 등). hex/oklch 직접 정의 |
| semantic | tokens/shared.css 중단 | 의미 alias (--color-success: var(--color-primary-400), --color-surface: var(--color-gray-50) 등). palette만 참조 |
| component | components/*.tsx 안에서 | semantic만 참조 (bg-surface, text-fg-muted). palette 직접 참조 지양 (예외: brand identity가 강한 곳 bg-primary-400) |
규칙: 컴포넌트가 hex나 oklch 값을 직접 입력하면 PR 차단. 반드시 Tailwind utility class 또는 var(--color-*) 통해.
토큰 플랫폼 분리 (shared / web / app)
플랫폼별 값은 3파일 분할. 컴포넌트가 어떤 토큰을 쓰는지는 그대로 (e.g. text-display), 셀렉터 컨텍스트에서 변수 값만 cascade로 갈아끼움.
| 파일 | 적용 컨텍스트 | 내용 |
|---|---|---|
| shared.css | 모든 컨텍스트 | palette · semantic alias · font · 의미 typescale · radius · animation. 양쪽이 동일 |
| web.css | @theme default | 용도 typescale 데스크탑값(36/32/24/20) · spacing 추가(2/6/10) · z-index · ring · gradient |
| app.css | [data-platform="app"] 셀렉터 | typescale 모바일(32/28/22/18) · spacing collapse(4/8/12) · ring transparent · 신규 elevation/safe-area/touch-target |
전환은 지역 wrapper로: 카탈로그 <PlatformScope platform="app"> (apps/lab/src/app/_components/PlatformScope.tsx)이 <div data-platform="app">을 부착해 자식 트리만 cascade 발동. 전역(<html>)에 박지 않는 이유: PC 웹 카탈로그 메인 영역(매트릭스/표)이 모바일 토큰으로 바뀌면 어색해짐. 모바일 토큰은 지역적 검수 도구.
자세한 매핑은 tokens/{shared,web,app}.css 헤더 주석. 시각 비교는 카탈로그 /tokens Platform 탭.
컴포넌트 작성 룰 (요약)
자세한 명세는 .claude/skills/boospatch-component-conventions/SKILL.md. 여기서는 위반 시 PR 차단되는 핵심 룰만:
- tailwind-variants(tv) 사용.
class-variance-authority(CVA) 신규 작성 금지 (기존 코드 점진 전환) forwardRef금지. React 19 ref-as-prop —ref?: Ref<HTMLElement>직접 받기- 'use client' 최소화. 이벤트 핸들러·Radix hook·브라우저 API 사용 컴포넌트만. 정적(Badge/Txt/Icon/SvgIcon)은 server component
- boolean prop ≤2개. 그 이상은 union enum (
shape: 'rect' | 'pill') 또는 compound (Menu.Trigger / Menu.Content) - 토큰만 통한 스타일링. hex/oklch 직접 입력 금지.
bg-[#06b281]같은 arbitrary value도 PR 리뷰에서 토큰화 요청 - Txt variant 우선. 신규 텍스트는
<Txt variant="display|hero|h1|h2|body-l|body|body-bold|caption|tag">디자이너 프리셋. size+weight 자유 조합은 예외만 (DESIGN.md §3.2) - a11y 의무:
- interactive 컴포넌트는 focus-visible ring (
outline-ring) - touch target ≥44×44px (size 'm' 이상)
- 키보드 인터랙션 (Space/Enter/Backspace 등) 명세
- 장식 아이콘은
aria-hidden="true", 의미 아이콘은aria-label필수
- interactive 컴포넌트는 focus-visible ring (
신규 컴포넌트 PR 체크리스트
PR 머지 전 모두 통과해야 함:
- tv variants 정의, default variants 명시
- React 19 ref-as-prop, forwardRef 미사용
- 'use client'를 의식적으로 박았는가? (정적이면 제거)
- boolean prop 2개 이하
- semantic 토큰만 사용 (또는 brand identity 명분으로 palette 직접)
- focus-visible ring 시각 확인
- 키보드 인터랙션 매뉴얼 테스트 (Tab/Space/Enter/Backspace)
-
apps/lab/src/app/components/<Name>/page.tsx카탈로그 추가 - variant 매트릭스 시각 검증 (모든 size × color × state 조합)
- index.ts에 export 추가
- 카탈로그에 a11y 체크리스트 표 명시
- AI slop 자가검증 — 보라 그라디언트·Inter/Roboto·균등 SaaS 그리드 X
의존성 정책
| 카테고리 | 라이브러리 | 비고 |
|---|---|---|
| variant | tailwind-variants | CVA 대체. slot/extend 지원 |
| class merging | clsx, tailwind-merge | utils/cn.ts로 래핑 |
| 아이콘 | lucide-react | tree-shake 위해 named import 강제 |
| Radix (G3 도입 예정) | @radix-ui/react-{dialog,popover,tooltip,toast,slot} | peer로 |
| polymorphic | 자체 구현 | 외부 라이브러리(@radix-ui/react-slot)는 G3 시점 검토 |
peerDependencies: react ≥19, react-dom ≥19. 기타 외부 의존성은 최소화. 무거운 라이브러리(Framer Motion 등) 도입 전 PR에서 토론 의무.
참조 skill
이 패키지에서 작업할 때 호출 순서 (루트 CLAUDE.md와 동일):
boospatch-component-conventions— 부스패치 오버라이드 (필수)frontend-design— AI slop 회피ui-ux-pro-max— 색상·타이포 결정 재료vercel-composition-patterns— boolean → compoundvercel-react-best-practices— server-first, React 19web-design-guidelines— a11y/UX 최종 검증