SkillLens Zero 디자인 시스템 심층 독립 검토
원본: projects/skill-lens/engineering/03-design-system-deep-audit.md
- 작성: 2026-11-09
- 범위: IDEBER 디자인 정본, Zero React UI 어댑터, 토큰·컴포넌트 동기화, 접근성·시각 검증 체계
- 목적: 기존 Worker/API/E2E 인계와 겹치지 않는 디자인 시스템 전용 검토와 Claude 후속 질문
- 검토 방식: GitHub 소스 정적 분석 및 W3C/WAI 공식 기준 대조
- 실행 한계: 앱 빌드, Playwright, 브라우저 스크린리더, 실제 키보드 시험은 실행하지 않았다.
0. 기존 인계 문서와의 경계
기존 02-gpt-independent-review-claude-handoff.md의 Worker Zero flow, API 여정, .dev.vars, 화면 수, 일반 E2E 항목은 반복하지 않는다.
이 문서는 디자인 시스템만 다룬다. 기존 문서의 0.18.0 동기화 기록과 Lens 검사기 지적을 구체화하고, 컴포넌트 계약, 키보드 동작, 토큰 대비, 검증 범위를 추가한다.
확인 기준:
- ideber/dev: 8e57443a95e2778734936effe0cb7a6602b39321
- skill-lens/zero: 6b4dd59fd02eb45ccba0148a4efa7d4eeddeaf40
최근 Claude 커밋에서 확인된 변경은 redline 테스트와 화면 수 문서 정정이었다. 이번 검토에서 디자인 시스템 원본 파일의 최근 수정은 확인하지 못했다.
1. 전체 판단
디자인 시스템의 기본 구조는 다시 만들 필요가 없다. 토큰 원본, CSS 생성, 동기화 해시, 컴포넌트 HTML 기준본, React 렌더링 비교가 이미 분리돼 있다. 이 파이프라인은 유지하는 편이 낫다.
현재 핵심 문제는 토큰 수가 많다는 사실이 아니다. 실제 문제는 네 가지다.
- 디자인 안정도와 React 구현 완성도가 한눈에 구분되지 않는다.
- 컴포넌트 명세, React 구현, 접근성 동작이 서로 다르게 적힌 곳이 있다.
- 컴포넌트 시각 비교는 넓게 되어 있지만 반응형 기초와 상호작용 검증은 약하다.
- 임시 화면 실험 코드가 공용 UI 경계 안에 남아 있다.
따라서 토큰을 무작정 줄이거나 Radix 등 새 패키지를 추가하기보다, 현재 컴포넌트 계약과 검증 게이트를 맞추는 것이 우선이다.
2. 현재 구조에서 잘된 부분
2.1 단일 디자인 원본과 생성 흐름
- 디자인 정본은 ideber/projects/skill-lens/design/이다.
- tokens.json이 값의 원본이고 build-tokens.mjs가 tokens.css를 생성한다.
- components/bundle.css는 Zero의 ui/css/sl.css로 복사된다.
- 로고, Ambient, Lucide sprite, Pretendard 폰트, 컴포넌트 preview도 동기화된다.
- sync-ds.mjs는 수신 파일 해시를 SOURCE.sha256에 기록한다.
- check-boundaries.mjs는 수신 파일 해시를 검사하고, tokens.css가 현재 생성 결과와 같은지도 다시 생성해 비교한다.
수신 기록은 디자인 시스템 0.18.0, 61개 파일이다. SOURCE.sha256에는 생성기 스크립트 1개와 수신 파일 61개가 있어 62개 해시 행이 있는 구조다. 이 부분은 정상적인 설계다.
2.2 토큰 규모와 분류
현재 토큰은 10개 묶음, 총 161개다.
| 묶음 | 개수 |
|---|---|
| color | 86 |
| spacing | 19 |
| radius | 9 |
| shadow | 8 |
| gradient | 3 |
| duration | 12 |
| easing | 6 |
| icon | 4 |
| breakpoint | 4 |
| layout | 10 |
| 합계 | 161 |
타이포그래피는 13개 스타일로 별도 정의돼 있다.
이 숫자만으로 과도하다고 판단하면 안 된다. 상태색, 차트 팔레트, 테마, 시각 효과, 간격·레이아웃 의미값이 포함돼 있다. 지금 줄여야 할 것은 토큰 개수가 아니라 오래된 설명과 중복된 규칙이다. 실제 사용처를 확인하지 않고 semantic token을 삭제하지 않는다.
2.3 컴포넌트 시각 비교
- 디자인 컴포넌트 폴더: 54개
- 기준 preview.html: 54개
- README: 53개
- React demo: 53개
- shots.mjs는 디자인 preview와 React demo를 같은 Chromium 환경에서 렌더링하고 pixelmatch로 비교한다.
- 기본 허용 차이는 0.5%다.
- npm run check에는 이 컴포넌트 스크린샷 비교가 포함돼 있다.
이 방식은 디자인 정본과 React 어댑터가 시각적으로 달라지는 것을 잡는 데 유효하다. 새 시각 테스트 도구나 Storybook을 도입할 이유는 현재 확인되지 않았다.
3. 컴포넌트 상태 모델을 분리해야 함
현재 디자인 README의 컴포넌트 첫 줄은 예를 들어 다음과 같다.
상태: Stable, 접근성 ✓, 다크 ✓, 코드 ✗
그런데 React handoff 표에는 Stable만 표시한다. 디자인 안정도와 코드 구현 완성도가 하나의 상태처럼 보인다.
실제 예:
- DropZone: Stable, 접근성 ✓, 다크 ✓, 코드 ✗
- Tabs: Stable, 접근성 ✓, 다크 ✓, 코드 ✗
- OptionCard: Stable, 접근성 ✓, 다크 ✓, 코드 ✗
- ScoreStepper: Stable, 접근성 ✓, 다크 ✓, 코드 ✗
- Shell, AdminShell, DataTable, Dialog, BottomSheet: In Progress, 코드 ✗
- Banner, StatusBadge, Heatmap, ScoreBreakdown 등은 Experimental 초안
제안
컴포넌트 상태를 두 축으로 분리한다.
| 축 | 상태 예시 | 의미 |
|---|---|---|
| 디자인 상태 | Experimental / In Progress / Stable | 시안·명세가 확정됐는가 |
| 구현 상태 | Not started / In progress / Verified | React 구현과 상호작용 검증이 끝났는가 |
접근성과 테마는 별도 검증 필드로 유지한다.
제품 사용 가능 조건은 디자인 Stable 하나가 아니라, 디자인 Stable + React Verified + 필요한 접근성 검증 통과로 정의한다. Dark는 현재 제품에서 사용하지 않으므로 Light를 먼저 검증하고 Dark는 별도 승인 전까지 잠근다.
4. React 컴포넌트 대응표가 실제 코드와 맞지 않음
4.1 개수 불일치
ui-handoff.md는 React 대응이 26개라고 적혀 있다. 그러나 표에는 다음과 같이 이름 있는 항목이 있다.
- Stable 14개
- In Progress 16개
- Experimental 3개
- 합계 33개
- 별도로 StateGlyph, ChartColors, Motion 기초 요소 3개가 한 행에 묶여 있다.
26이라는 숫자는 현재 표와 맞지 않는다. 단순히 숫자만 33으로 바꾸기보다 전체 컴포넌트와 React export를 한 번 대조해 표를 완성해야 한다.
4.2 React export가 표에서 빠진 항목
현재 ui/index.ts는 components, wow, admin, insight, controls, entry를 모두 export한다. 그런데 handoff 대응표에 이름이 없는 React export가 확인된다.
- AskRenji
- Banner
- Composer
- Delta
- Disclosure
- Heatmap
- Legend
- Menu
- NightPanel
- PasswordField
- ReviewPanel
- SaveStatus
- ScoreBreakdown
- SkillChip
- SkillDetail
- StatusBadge
이 중 여러 항목은 디자인 README에서 Experimental 초안으로 분류돼 있다. 구현 코드와 demo가 존재하는 것과 제품 사용이 승인된 것은 다른 상태다.
제안
새 매핑 문서를 만들지 말고 기존 ui-handoff.md 표를 완성한다. 각 디자인 컴포넌트에 대해 다음을 명시한다.
- 디자인 폴더 이름
- React export 이름
- 실제 사용 클래스
- 디자인 상태
- 구현 상태
- 사용 가능한 화면과 금지된 사용
- 키보드·스크린리더 계약
- Radix 사용 여부 또는 자체 구현 여부
54개 폴더 중 Cover는 README가 없고, Responsive는 React demo가 없다. 이 둘도 명시적으로 처리한다. Responsive는 기초 요소라 일반 부품 demo가 아닌 반응형 전용 시험으로 관리할 수 있다.
5. 실제 코드와 ARIA/키보드 계약 불일치
이 부분은 시각 비교만으로 잡히지 않는다. 현재 코드의 역할 선언과 실제 키보드 동작을 대조했다.
5.1 Tabs
파일: zero/app/ui/components.tsx
현재 구현:
- role="tablist"
- 각 버튼에 role="tab", aria-selected
- 클릭 이벤트로 선택값 변경
확인한 누락:
- 좌우 화살표 키로 탭 사이 이동하는 동작이 없다.
- roving tabindex가 없다. 모든 버튼이 기본 탭 순서에 들어간다.
- 탭과 패널의 aria-controls, aria-labelledby 연결 계약이 컴포넌트에 없다.
실제 값 고르기인 pick 모드는 aria-pressed를 쓰므로 별도 그룹으로 처리하는 방향이 맞다.
제안: 실제 탭이면 WAI-ARIA APG Tabs 패턴대로 활성 탭 하나만 탭 순서에 두고 좌우 화살표, Home, End를 구현한다. 단순 필터·보기 토글이면 tablist가 아니라 group과 aria-pressed를 사용한다.
5.2 OptionCard
현재 구현:
- 부모는 role="radiogroup"
- 카드 버튼은 role="radio", aria-checked
- 클릭으로 선택
확인한 누락:
- 선택된 카드 하나만 탭 순서에 들어가는 roving tabindex가 없다.
- 좌우/상하 화살표로 선택지를 이동하고 선택하는 동작이 없다.
제안: 기존 커스텀 구현을 유지한다면 WAI-ARIA APG Radio Group 패턴을 구현한다. 또는 실제 radio input을 사용해 브라우저 기본 키보드 동작을 이용한다. 패키지 추가는 필요하지 않다.
5.3 ScoreStepper
명세:
- ScoreStepper/README.md는 role="slider"와 좌우 화살표로 1점씩 움직이는 동작을 명시한다.
- ui-handoff.md는 Radix Slider를 기재한다.
실제 React:
- 최상위는 role="group"
- 실제 조작은 1점 낮추기/높이기 버튼 두 개
- 가운데 숫자와 막대는 표시용이고 막대는 aria-hidden="true"
- slider role, aria-valuenow/min/max, 화살표 키 동작이 없다.
제안: 제품 의도가 +/− 버튼이라면 현재 구현을 유지하고 문서를 group + increment/decrement로 고친다. 막대 손잡이를 직접 움직이는 슬라이더가 의도라면 실제 slider 계약과 키보드 동작을 구현한다. 두 모델을 문서와 코드에서 혼용하지 않는다.
5.4 StatRow 필터
필터 모드는 role="tablist"와 각 항목의 role="tab"를 사용하지만 현재 코드에서 화살표 키 이동과 roving tabindex가 확인되지 않는다. Tabs와 같은 규칙을 적용해야 한다.
5.5 Dialog와 Sheet
현재 코드:
- Dialog는 일반 div에 role="alertdialog", aria-modal="true"를 지정한다.
- 제목 h2와 설명 p가 있지만 dialog에 aria-labelledby와 aria-describedby 연결이 없다.
- 포커스 이동, Tab 순환, Escape 닫기, 닫은 뒤 호출 요소로 포커스 복귀 로직이 컴포넌트 안에 없다.
- Sheet도 직접 만든 role="dialog" 마크업이다.
- PhoneSheet는 dialog prop이 주어졌을 때만 설치된 @radix-ui/react-dialog를 사용한다. prop이 없으면 직접 만든 마크업을 반환한다.
README도 Dialog와 BottomSheet의 포커스 가두기가 미완성이라고 기록한다.
제안: Modal primitive를 한 경로로 통일한다. 이미 설치된 @radix-ui/react-dialog를 활용하거나 자체 구현을 완성한다. 중요한 것은 선언된 role이 아니라 실제 동작이다.
필수 계약:
- 열릴 때 적절한 요소로 포커스 이동
- Tab과 Shift+Tab이 모달 밖으로 나가지 않음
- Escape 동작
- 닫힐 때 호출 요소로 포커스 복귀
- 접근 가능한 제목과 설명 연결
- 배경 콘텐츠 비활성화
5.6 Radix 의존성 표와 실제 패키지
ui-handoff.md는 Tabs, OptionCard, ListRow, ScoreStepper, Dialog, Toast, Combobox, DatePicker, LevelPicker 등에 Radix primitive를 기재한다.
현재 package.json에서 확인되는 Radix 패키지는 @radix-ui/react-dialog 하나다. 실제 코드 import도 controls.tsx에서 해당 패키지를 사용하는 것이 확인됐고, 나머지 컨트롤은 React 자체 구현이다.
이는 새 패키지를 추가해야 한다는 뜻이 아니다. 지금의 자체 구현 방식을 유지할 수 있다. 다만 handoff의 Radix 열을 실제 의존성처럼 읽지 않도록 현재 구현 방식(자체 구현 / Radix 실제 사용 / 향후 선택지)으로 바꾸고, 자체 구현 컨트롤에는 APG 키보드 테스트를 붙여야 한다.
6. DropZone은 디자인 Stable과 구현 완료를 구분해야 함
- DropZone/README.md: 파일 올리기 영역, 허용 형식, 최대 용량, 파일 선택, 드래그 중 상태를 정의한다.
- 상태 줄에는 Stable, 접근성 ✓, 다크 ✓, 코드 ✗가 적혀 있다.
- 현재 React DropZone은 제목·선택 안내·힌트를 렌더하는 정적 div다.
- props에 파일 선택 callback, accept, 최대 용량, disabled, drag 상태가 없다.
- 실제 file input이나 drop event도 이 컴포넌트 안에는 없다.
화면에서 별도 input을 감싸는 방식으로 처리할 수는 있지만, handoff는 화면에서 직접 input을 만들지 말라고 한다. 따라서 현재 계약만으로는 제품 파일 업로드를 끝까지 연결하기 어렵다.
제안: DropZone을 실제 파일 입력 부품으로 만들거나, DropZone은 표현 전용이라고 명확히 하고 접근 가능한 FilePicker 부품과 조합하는 방식을 명세한다. 파일 선택, 드래그앤드롭, 형식/용량 오류, 키보드로 파일 선택, 파일 행 상태를 한 계약으로 검증한다.
7. Lens와 EmptyState의 브랜드 자산 규칙
7.1 Lens
React Lens는 디자인 정본 design/scripts/sl-mark.js의 MARK 함수를 TypeScript로 옮긴 SVG 생성 구현이다. 공식 skilllens-mark.svg와 같은 기하·그라데이션을 사용한다. 이 구현을 CSS로 그린 렌즈와 동일 취급하면 안 된다.
반면 ui-handoff.md는 Lens를 sl-lens + 두 개의 i 요소로 설명한다. 현재 React 코드는 span class="sl-lens" 안에 SVG를 넣는 구조다. 설명을 현재 코드와 맞춰야 한다.
7.2 EmptyState
현재 EmptyState React 구현은 .sl-empty__lens 안에 두 개의 i 요소를 넣고 CSS 타원 두 개로 렌즈를 그린다.
그런데:
- 디자인 README의 EmptyState 규칙은 그림으로 StateGlyph 하나를 쓰도록 한다.
- 브랜드 README는 로고를 CSS로 다시 그리지 말고 공식 렌즈 자산을 사용하도록 한다.
- screen-check는 .sl-empty__lens를 금지 대상으로 검사한다.
제안: EmptyState의 CSS 렌즈를 StateGlyph 또는 승인된 SVG 기반 Lens로 교체한다. screen-check는 모든 .sl-lens를 무조건 실패시키지 말고, 내부 SVG가 승인된 MARK 구현인지 확인한다. .sl-empty__lens의 CSS 도형은 승인된 대체 결정이 없는 한 계속 실패시킨다.
추가 접근성 확인: Lens에 label을 주면 바깥 span과 안쪽 SVG가 모두 role="img"와 accessible name을 가질 수 있다. 스크린리더에 이미지 역할이 중첩되어 두 번 읽히지 않도록 한쪽만 이름을 갖게 한다.
8. 임시 화면 실험이 공용 UI 경계에 남아 있음
현재 main.tsx는 세 CSS 파일을 가져온다.
- ui/css/tokens.css
- ui/css/sl.css
- ui/css/app.css
그런데 ui-handoff.md는 스타일 파일이 tokens.css와 sl.css 둘뿐이라고 적혀 있다.
app.css는 .sl-x-* 클래스를 포함한 화면 연출 실험 파일이다. Company.tsx에서 해당 클래스를 사용한다. 주석에는 디자인 시스템 0.13에 흡수되면 지운다고 되어 있지만 현재 정본은 0.18.0이다. 파일 안에는 13px, 20px, 260ms, 120ms 등 토큰이 아닌 직접 값도 남아 있다.
또한 ui/index.ts는 wow.tsx를 공용 UI barrel에서 export하고, Company 화면이 Lookup, CountUp, useTimeline을 가져간다.
제안:
- 이 연출이 데모 전용이면 데모/화면 실험 코드로 분리하고 공용 UI export에서 제외한다.
- 제품 공통 패턴으로 승격할 계획이면 디자인 정본에 토큰·클래스·preview·README·검증을 먼저 추가한다.
- 현재처럼 공용 UI에 임시 스타일을 남긴 채 handoff에는 스타일 파일이 두 개라고 적힌 상태는 해소한다.
- 이 실험 코드를 다른 54개 화면의 기본 템플릿으로 복제하지 않는다.
9. 토큰 색상 대비 설명의 수치 불일치
색상 토큰의 현재 실제 값으로 WCAG 상대 휘도 대비를 계산했다. 값은 반올림했으며, 아래 수치는 Light 제품 화면과 Dark 잠재 테마를 구분해 해석해야 한다.
| 토큰/조합 | 토큰 설명 | 현재 값으로 계산한 대비 | 판단 |
|---|---|---|---|
| skill-blue #6557F6 / 흰색 | 4.47:1, AA 미달. 같은 설명 뒤에는 4.94:1이라고도 기재 | 4.94:1 | 오래된 4.47 설명 삭제 |
| skill-blue-strong #4F41D8 / surface, sunken, tint | Light 5.5~6.3:1 | 6.82 / 6.38 / 6.02:1 | 설명 범위 수정 |
| skill-blue-strong #9FA3FF / Dark surface, raised, tint | Dark 6.1~7.9:1 | 7.53 / 6.84 / 5.15:1 | Dark는 미검수이므로 사용 잠금 유지, 수치 설명 수정 |
| on-skill-blue-strong / strong 채움 | Light 6.3, Dark 7.9:1 | 6.82 / 7.53:1 | 설명 수치 수정 |
Light README는 이미 skill-blue가 흰 바탕에서 4.94:1이라고 설명한다. 따라서 토큰 설명의 4.47:1은 이전 값이 남은 것으로 판단한다.
추가로 focus-lime의 토큰 설명은 흰색 대비 1.2:1이지만 현재 값 #DFFF59의 계산 결과는 약 1.13:1이다. 어차피 글자·아이콘·테두리에 사용하지 않는 장식색이므로 우선순위는 낮지만 설명은 정확히 맞춘다.
제안: 색상 값을 바꾸지 말고 우선 설명을 현재 값에 맞춘다. 실제 화면 사용처를 함께 검사한다. Dark는 README에서 검수 전이라고 명시하고 Light로 고정했으므로 지금 제품 범위에서 활성화하지 않는다.
10. 반응형 기초 테스트 누락
현재 54개 디자인 컴포넌트 폴더와 54개 preview가 있다. React demo는 53개이며 Responsive가 유일하게 빠져 있다.
Responsive preview에는 폰 390, 태블릿 834, PC 1440의 세 구간 예시가 있지만, shots.mjs는 React demo가 있는 항목만 비교하므로 Responsive preview와 React 결과를 비교하지 않는다.
제안:
- Responsive foundation을 위한 전용 React demo 또는 테스트 페이지를 둔다.
- 390, 834, 1280/1440에서 같은 화면을 측정한다.
- 창 너비뿐 아니라 실제 .sl-vp 컨테이너 너비가 달라지는 상황도 검증한다.
- 폰에서 표→카드, 길잡이, 고정 CTA, 시트 전환을 테스트한다.
- 색·타입·간격이 breakpoint에 따라 임의로 바뀌지 않는지 확인한다.
11. 검증 명령의 역할을 분리해 명확히 하기
현재 npm run check는 lint, 접근성 ESLint, typecheck, build, 컴포넌트 shots를 실행한다. screen-check는 별도 URL과 화면 ID를 받아 수동 실행하는 별도 명령이다.
이는 명령 구조 자체의 결함은 아니다. 다만 팀이 npm run check 통과를 전체 화면 디자인 검증 완료로 오해하지 않도록 구분해야 한다.
현재 screen-check.mjs가 측정하는 항목:
- 화면당 주 버튼 수
- 12px 미만 글자
- 중첩 카드
- 로고/렌즈 마크
- 시작선 정렬
- 갈 곳 없는 링크
- 승인 baseline과 pixelmatch 비교
- sl- 요소의 위치·크기 지문
아직 자동 측정하지 않는 항목:
- 24×24 CSS px 포인터 대상 크기 또는 WCAG 간격 예외
- 텍스트와 배경의 실제 렌더링 대비
- Tabs/Radio/Dialog 등의 키보드 동작
- 모달 포커스 가두기와 복귀
- 스크린리더 accessible name/role/state
- Responsive foundation 전 구간
제안: 기존 도구를 확장한다. 새 테스트 프레임워크를 추가하지 않는다.
- Playwright DOM 측정에 최소 터치/포인터 대상 크기 검사를 추가한다.
- 대비는 alpha가 있는 배경을 포함해 계산할 수 있도록 한다. 계산이 불가능한 복합 배경은 자동 통과시키지 말고 수동 검토 대상으로 표시한다.
- 상호작용 컴포넌트는 키보드 테스트를 별도 fixture로 만든다.
- 화면별 screen-check는 승인 baseline과 함께 제품 화면 승인 단계에서 실행한다.
baseline 환경 정보에는 현재 browser, Playwright, OS, font hash, data, viewport가 들어간다. 날짜·시간 표시가 있는 화면은 locale/timezone에 따라 결과가 달라질 수 있으므로 browser context와 metadata에 locale=ko-KR, timezoneId=Asia/Seoul, colorScheme=light를 명시하는 것을 권장한다.
12. 외부 표준과의 관계
12.1 WAI-ARIA APG
다음 컴포넌트는 WAI-ARIA Authoring Practices Guide의 패턴을 직접 기준으로 삼는 것이 좋다.
- Tabs: https://www.w3.org/WAI/ARIA/apg/patterns/tabs/
- Radio Group: https://www.w3.org/WAI/ARIA/apg/patterns/radio/
- Modal Dialog: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
- Composite widget keyboard interface: https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/
WAI-ARIA role을 붙였다는 사실만으로 동작이 완성되는 것은 아니다. role이 요구하는 키보드와 포커스 동작까지 구현해야 한다.
12.2 WCAG 2.2
현재 README의 24×24 최소 포인터 대상 규칙은 WCAG 2.2 SC 2.5.8의 기본 크기와 일치한다. 다만 이 기준은 작은 대상에 대한 간격 예외도 허용하므로, 단순히 CSS width/height만 검사하는 것으로는 충분하지 않다.
공식 기준: https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum
12.3 Design Tokens Community Group
현재 tokens.json은 프로젝트에 맞춘 자체 JSON 구조다. W3C Design Tokens Community Group은 2025.10 형식 보고서를 공개했으며, 이는 도구 사이에서 토큰을 교환하기 위한 안정된 형식이다. 다만 W3C 정식 표준이나 Standards Track 문서는 아니다.
공식 보고서: https://www.w3.org/community/reports/design-tokens/CG-FINAL-format-20251028/
제안: 지금 내부 토큰 형식을 바꾸지 않는다. Figma/Penpot 등 외부 도구 연동 요구가 생기면 현재 JSON에서 DTCG 2025.10 형식으로 내보내는 adapter를 별도로 만든다. React 빌드의 현재 작동 경로를 갈아엎을 이유는 없다.
13. Claude가 맡을 디자인 시스템 전용 후속 작업
기존 Worker/API/E2E 인계와 중복하지 않고 아래만 다룬다.
우선순위 1: 제품 사용 전 계약 정리
- 컴포넌트 상태를 디자인 상태와 코드 검증 상태로 분리한다.
- ui-handoff.md의 26개 숫자와 React 대응표를 실제 54개 폴더, React export, demo 기준으로 재집계한다.
- Radix 열을 실제 의존성과 자체 구현 여부에 맞게 수정한다. 패키지를 무작정 추가하지 않는다.
- Tabs, OptionCard, StatRow의 키보드 동작을 APG 기준으로 구현하거나 role을 실제 동작에 맞게 바꾼다.
- ScoreStepper를 실제 group형 조절기와 slider 중 하나로 결정하고 명세·코드를 일치시킨다.
- Dialog, Sheet, PhoneSheet의 모달 구현을 하나의 검증된 경로로 정리한다.
- DropZone의 실제 파일 선택 계약을 완성한다.
- EmptyState의 CSS 렌즈를 제거하고 StateGlyph 또는 승인 SVG로 바꾼다.
우선순위 2: 시각·반응형·토큰 검증
- Responsive foundation에 React 비교 demo 또는 전용 시험을 추가한다.
- 컴포넌트 시각 비교 53개와 별개로 390/834/1440 반응형 검증을 실행한다.
- screen-check에 포인터 대상 크기와 대비 검사를 추가한다.
- 토큰의 대비 설명을 현재 실제 값과 맞춘다.
- Lens의 공식 SVG 허용 기준을 검사기에 반영하되 CSS 렌즈는 계속 차단한다.
- screen-check baseline의 locale/timezone/colorScheme을 고정한다.
우선순위 3: 경계와 문서
- app.css와 wow.tsx를 데모 전용으로 둘지 공용 디자인 시스템으로 승격할지 결정한다.
- 임시 화면 실험을 공용 UI export와 제품 화면에서 분리한다.
- design-system.json이 버전 메타데이터로 계속 쓰인다면 README의 “아티팩트 더 이상 사용하지 않음” 문구를 정확히 고친다.
- DTCG 형식 전환은 지금 하지 않고, 외부 연동 필요가 확인될 때 export adapter로 검토한다.
14. Claude에게 요청할 회신
PM에게 선택지만 던지지 말고, 기본 제안과 근거를 먼저 제시해 달라.
- 컴포넌트 Ready 정의: 디자인 Stable과 제품 사용 가능 상태를 어떻게 구분할 것인가? 각 상태의 완료 증거는 무엇인가?
- R1 필수 부품: 54개 화면의 실제 사용처를 기준으로 어떤 컴포넌트가 R1에 필수이며, 어떤 부품이 아직 디자인 Stable/코드 Verified가 아닌가?
- ARIA 구현 전략: Tabs, OptionCard, Dialog, Sheet를 현재 자체 구현으로 완성할 것인가? 기존 설치 패키지로 해결할 것인가? 새 패키지 없이 가능한 기본안을 제시해 달라.
- ScoreStepper 계약: 디자인은 슬라이더인가, +/− 조절기인가? 한 가지로 확정하고 문서·코드·테스트를 일치시켜 달라.
- DropZone 계약: 파일 선택, drag/drop, 오류, 파일 상태를 어느 컴포넌트가 소유하는가?
- Lens/EmptyState: 공식 MARK SVG와 CSS 렌즈를 검사기가 어떻게 구분해야 하는가? EmptyState는 StateGlyph로 통일하는가?
- 임시 연출: app.css와 wow.tsx는 데모 전용인가? 제품 UI에서 제거할 기준과 위치를 제안해 달라.
- 반응형 검증: Responsive foundation을 어떤 demo와 viewport/container matrix로 검증할 것인가?
15. 완료 판정
디자인 시스템 후속 작업은 아래 증거가 있을 때 완료로 본다.
- 컴포넌트 54개 전체의 디자인 상태, React 대응, 구현 상태가 서로 모순되지 않는다.
- 제품 화면에서 쓰는 부품은 디자인 Stable과 React Verified가 모두 확인된다.
- Tabs, Radio, Dialog, Sheet, ScoreStepper의 키보드/포커스 계약이 코드와 테스트에서 일치한다.
- DropZone이 실제 파일 선택 계약을 제공한다.
- EmptyState는 CSS로 브랜드 렌즈를 다시 그리지 않는다.
- 53개 컴포넌트 시각 비교와 Responsive 전용 시험이 모두 있다.
- 토큰 대비 설명이 실제 색상값과 일치한다.
- 임시 화면 실험이 공용 디자인 시스템으로 오인되지 않는다.
- 테스트 실행 결과와 실패 증거가 남아 있다.
이 문서는 정적 검토 결과다. 코드 수정, 빌드, 브라우저 실행, 실제 접근성 검증이 완료됐다고 주장하지 않는다.
이 사이트는 ideber 저장소 projects/skill-lens/ 에서 자동으로 만들어집니다. 고칠 때는 저장소를 고칩니다. 공개 주소이지만 검색엔진에는 나오지 않습니다.