디자이너가 토큰을 바꾸면 슬랙으로 전달받아 손으로 옮겨 적었고, 빠뜨린 건 QA에서 발견됐습니다.
"이걸 왜 사람이 하지?"가 시작이었습니다.
Figma를 SSOT로 두는 파이프라인을 만들고,
그 위에 신규 디자인 시스템을 구축해 전사 웹 프로덕트에 적용 중입니다.
자비스앤빌런즈(삼쩜삼) · FE 3인 팀 · 파이프라인 설계·구현 주도 (기여도 80%) · 디자이너와 토큰 컨벤션 공동 정의
⚠ 어디까지 반영됐는지 아무도 모름
$ pnpm figma:pull && pnpm build ✓ 571 tokens → CSS / Tailwind ✓ validator 571/571
누락이 있으면 QA가 아니라 빌드가 알려줍니다
surface-primarysurface-primary가 Figma 변수 → JSON → CSS 변수 → 컴포넌트까지 네 계층을 그대로 관통합니다 — 번역 과정이 없으니 어긋날 곳도 없습니다.Variables(토큰 컬렉션 4계층) + ComponentSet(컴포넌트 정의)
surface-primary
LightDark
:root { --surface-primary: #15b077 }
.dark { --surface-primary: #0e8a5f }
CSS 변수 571개 ×2 모드 + Tailwind v4 @theme — 누락은 validator가 빌드 실패로 차단
variant=primary · size=large
"variant=primary, size=large, …": {
"base": { "fill": "$surface-primary" }
}
variant·슬롯별 스타일을 담은 스펙 JSON 65종 — 구현의 단일 참조점
<Button variant="primary" size="large">
시안을 raw CSS/div로 다시 만들지 않도록, 사람에게도 AI에게도 실제 컴포넌트 코드를 바로 제공
버튼 색은 #15b077 같은 값이 아니라 "시맨틱 토큰을 따라간다"로 저장돼 있습니다 (var() 참조).
그래서 시맨틱 토큰 54개만 갈아끼우면 그걸 따라가는 모든 컴포넌트가 함께 바뀝니다. 직접 눌러보세요.
/* 빌드 산출물 — 컴포넌트 토큰은 참조를 보존한다 */ :root { --surface-primary: #15b077; } [data-theme="brand-b"] { --surface-primary: #d97a06; } /* 시맨틱 54개만 오버라이드 */ --primary-enabled-button-surface: var(--surface-primary); /* hex로 굳히지 않음 → 브랜드가 바뀌면 따라감 */
버튼 하나의 상태 조합이 120개(variant 5 × 형태 2 × 크기 4 × 상태 3) — 이걸 하나씩 클릭해 옮겨 적는 게 구현에서 가장 오래 걸리는 일이었습니다.
// After — 명령 한 번으로 생성되는 spec.json "size=small, state=enabled, value=selected": { "switch-track": { "fill": "$surface-primary", "cornerRadius": 999 }, "switch-thumb": { "fill": "$icon-basic-inverse" } }
디자인이 바뀌면 이 파일의 diff로 드러납니다 — 디자인 변경도 코드처럼 리뷰됩니다. 코드 생성까지는 자동화하지 않았습니다 — 인터페이스·접근성은 스펙만으로 판단할 수 없어, 사람이 결정합니다.
$ pnpm figma:sync 발견된 spec.json 파일: 65개 571개의 디자인 토큰 로드 완료 🔄 Button/spec.json 동기화 중... ⏭ 변경사항 없음 🔄 Switch/spec.json 동기화 중... ✅ 완료 (스타일 2건 갱신) 🔄 Input/spec.json 동기화 중... ⏭ 변경사항 없음 … 62개 생략 … 동기화 완료: 1개 갱신, 64개 변경 없음, 0개 실패
"잘 지켜달라"는 부탁 대신, 사람·AI·시간이 만드는 드리프트를 각 계층의 검증 게이트가 막습니다.
$ pnpm build ✗ css-validator — missing token: surface-tertiary (570/571) build failed
| 게이트 | 지키는 것 | 어기면 |
|---|---|---|
| 토큰 validator | 소스 토큰 ↔ 생성된 CSS 변수 1:1 (571개 전수 대조) | 빌드 실패 |
| 참조 치환 검사 | 깨진 토큰 참조가 CSS로 새어 나가 조용히 무효화되는 것 | 빌드 실패 |
| 자체 ESLint 룰 | 슬롯 오버라이드를 뒤따르는 className이 조용히 덮어쓰는 것 (타입이 못 잡아 lint가 맡음) | 린트 에러 |
| Code Connect 검사기 | Figma 속성 rename·옵션 변경으로 51종 매핑이 어긋나는 것 | exit 1 |
| 스킬 문서 검증 | 가이드 문서의 prop·값 ↔ 배포 타입(d.ts) 불일치, 예제 코드 컴파일 실패 | CI 에러 |
Dev Mode에서 시안을 클릭했을 때 보이는 코드를 바꿉니다.
display: flex; padding: 13px 20px; background: #15b077; border-radius: 12px; …
CSS 덩어리를 보고 raw CSS로 재구현 → 시스템 우회
<Button variant="primary" size="large"> 환급액 조회하기 </Button>
이 코드를 그대로 복사해 쓰면 됩니다
매핑 초안은 스크립트가 생성하고 판단만 사람이 검토 — Figma 속성이 바뀌어 어긋나면 자체 드리프트 검사기가 CI에서 차단
사용 가이드 35편을 스킬로 배포해, AI가 raw div 대신 시스템 컴포넌트로 구현하게 합니다.
<Button variant="primary" size="large">
가이드의 prop·예제 코드는 배포 타입 정의(d.ts) 기준으로 자동 검증됩니다
전사 웹 앱 18개 중 8개가 실사용 중입니다.
앱별 시스템 컴포넌트 import 파일 수 (2026-09 기준) · 사용 컴포넌트 최다 앱은 22종 사용