From 6a4fb2173cdeb6a7f210cc9fca95d3301b54473f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:18:14 +0900 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20Figma=20WDS=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=82=AC=EC=9A=A9=20=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=EB=A5=BC=20conventions=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conventions/wds-component-usage.md | 75 +++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 docs/conventions/wds-component-usage.md diff --git a/docs/conventions/wds-component-usage.md b/docs/conventions/wds-component-usage.md new file mode 100644 index 0000000..e42924b --- /dev/null +++ b/docs/conventions/wds-component-usage.md @@ -0,0 +1,75 @@ +# Figma Stream 파일 — WDS(원티드 디자인 시스템) 사용 현황 + +> 작성일: 2026-09-07 +> 종류: 살아있는 참고 문서 — `/component` 스킬이 매번 이 문서부터 대조하고, 새로 확정되는 매핑을 여기에 추가한다 +> 대상 파일: [🌊 Stream](https://www.figma.com/design/3QkxTuGLZkB17pZILTog9L/%F0%9F%8C%8A--Stream) (`fileKey: 3QkxTuGLZkB17pZILTog9L`) + +## 배경 + +`4. 사용자 UI` 페이지(`nodeId: 971:29755`) 안에 있는 `component`라는 이름의 섹션(`nodeId: 985:36615`)은 Stream 팀이 자체적으로 만든 화면 조각(로컬 심볼) 모음이며, WDS 컴포넌트가 아니다. 실제 WDS 컴포넌트는 각 화면 인스턴스 안에 흩어져서 쓰이고 있어, 파일 전체 메타데이터에서 인스턴스 이름을 모아 [Wanted Design System (Community)](https://www.figma.com) 라이브러리(`libraryKey: lk-01f447137a741b37c25896e9a4e109dcb719fa4e54177be9a39d24b8da507c109279c2d1d0533b9943595d7d6a5ea398977f43b5d84e163797965d810ba79b69`)의 `search_design_system` 검색 결과와 이름을 대조해 정리했다. + +## 조사 방법 및 한계 + +1. `get_libraries`로 Stream 파일에 연결된 라이브러리 확인 → WDS(Community), iOS and iPadOS 26 2개가 연결됨. +2. `get_metadata(971:29755)`로 페이지 전체 노드 트리(약 43만자)를 받아 로컬 파일로 저장. +3. 저장된 트리에서 `` 태그만 추출해 이름별로 집계(총 178개 고유 이름, 인스턴스 총 개수 기준). +4. 각 이름을 `search_design_system`(WDS 라이브러리로 스코프 제한)에 검색해 **정확히 같은 이름의 컴포넌트가 WDS에 존재하는지** 대조. + +**한계**: `get_metadata`는 인스턴스의 `componentKey`(어느 라이브러리 컴포넌트를 참조하는지 나타내는 고유 키)를 주지 않는다. 그래서 아래 표는 "이름 일치"로 확인한 것이며, 100% 확정하려면 `get_design_context`로 각 인스턴스를 열어 componentKey를 대조해야 한다(아래 "완전 확정 방법" 참고). + +## WDS 컴포넌트로 확인됨 (이름 정확히 일치, componentKey까지 확보) + +| WDS 컴포넌트 | 파일 내 인스턴스 수 | WDS componentKey | +|---|---|---| +| `Top Navigation/Resource/Contents` | 81 | `fcafe72bb0d975a6a1e6486be86be899e7d93e4a` | +| `Content Badge/Content Badge` | 48 | `2118b972d3ea08f35fb551cc755e41b5adeeb312` | +| `Control/Checkbox` | 42 | `72378cce3669fd4c065f12d01c254c303209d700` | +| `Action Area/Action Area` | 34 | `56b315679e172ceeac7ad64851cb0059ec235ae7` | +| `Control/Radio` | 28 | `8267d231338418aa74450dcfbe1576791540fb2a` | +| `Textinput/Textarea` | 24 | 메인 컴포넌트 Node ID `567:14111` — [문서](https://montage.wanted.co.kr/docs/components/selection-and-input/text-area/design) | +| `Chip/Chip` | 24 | 메인 컴포넌트 Node ID `440:4251` — [문서](https://montage.wanted.co.kr/docs/components/actions/action-chip/design) | +| `Icon/Normal/Location` | 13 | 메인 컴포넌트 Node ID `567:16585` | +| `Icon/Normal/Clock` | 13 | `7b620e5b46b1a467c6f8662fabcde63ce4e73b01` | +| `Page Indicator/Counter` | 12 | `560362b1ebe2ebe05646e66f4eb54a1531f3073d` | +| `Toast/Toast` | 10 | `5e6b6b522ae500ca6cd893ee2c2ffaf378c5c808` | +| `Button/Button` | 9 | `d28f3e22ae96d34ce26fb02977f23fb8084b7f85` | +| `Menu/Resource/Action Area/Trailing Content/Button` | 7 | `b7088257913aa98cea946cc3dc7931ebd544b872` | +| `Divider/Divider` | 7 | `cdef3da5cdbdd1e6f5d5d9efe85280c509b9e614` | +| `Icon/Normal/Circle Info` | 6 | 메인 컴포넌트 Node ID `440:4076` | +| `Icon/Normal/Arrow Right` | 6 | `26812c6481c960486eebf2282d6e12f2d4a133cd` | +| `Tab/Tab` | 4 | `454aa29664579ce983621c8b1c078f3e2e7ddbb0` | +| `Pagination/Dots` | 4 | 메인 컴포넌트 Node ID `445:9563` — [문서](https://montage.wanted.co.kr/docs/components/navigations/pagination-dots/design) | +| `Avatar` (Avatar/Avatar 계열) | 4 | `5885add30e5c5f5048057425d06ee89f263e96dd` | +| `Icon/Normal/Circle Check` | 3 | `bd9f80c38233b8d368cbcb4b8b9dcfa4c14c10b5` | +| `Menu/Menu` | 3 | `b4044d0a6a54bc6f8b10a76b97bfdf46a3978098` | +| `Icon/Normal/Plus` | 2 | `c2b078d8027a89ac207d6f5a1fe4205f9e26242c` | +| `Icon/Normal/Pencil` | 2 | `ddc90ae1926c0277477f233629cd4c186e87426f` | +| `Category/Resource/Chip/Normal/Normal` | 2 | `7a1668f2266cd57a689731ded85b52aa58c39905` | +| `Category/Resource/Chip/Normal/XSmall` | 1 | `73e0f352cd9ac759377854340136cd1f1032b6cb` | +| `Category/Resource/Chip/Alternative/Small` | 1 | `72cee86994b3c3581887be5149c41a59c4b02d93` | +| `Icon/Normal/Calendar` | 1 | `e050124e28e6217eedf243295b6087728acd9edc` | + +WDS 컴포넌트만 합산하면 파일 안에서 **약 350회 이상**의 인스턴스가 확인된다(위 표 합계 기준). `Textinput/Textarea`, `Chip/Chip`, `Icon/Normal/Location`, `Icon/Normal/Circle Info`, `Pagination/Dots` 5개는 `get_design_context`로 실제 노드를 열어 WDS 메인 컴포넌트 Node ID(및 3개는 원티드 공식 디자인 시스템 문서 링크)까지 확인해 완전히 확정했다. + +## 제외됨 — Stream 자체 로컬 컴포넌트 (WDS 아님) + +이름은 비슷해 보여도 WDS 검색 결과에 없거나, `component` 섹션(985:36615)에서 로컬 심볼로 직접 정의된 것들: + +- `Rental Item Card`, `RentalHistory-card`, `ApplicationHistory-card`, `Item-card` 계열, `Event-card`, `Q&A Card`, `Notice-card` — Stream 도메인 전용 카드 +- `Bottom Nav`, `BottomNav/Icon`, `Locker-button`, `SearchField`, `Floating Button`, `Empty State`, `Modal`, `Modal/ButtonGroup`, `Section-header`, `Top Navigation`(WDS의 `Top Navigation/Resource/Contents`와 다른 별개 로컬 프레임), `divider(new)`, `ProgressBar`, `Native / Home Indicator`, `Native / Bottom Sheet Indicator` +- `Icon/Feedback`, `Icon/Camera`, `Icon/Link`, `Icon/Answer`, `Icon/Activity`, `Icon/Arrow` 및 고데기·알약·후시딘 등 물품 아이콘 — Stream 전용 아이콘 세트 (WDS의 `Icon/Normal/*` 네이밍과 다름) +- `Status Bar - iPhone`, `Home Bar` — WDS가 아니라 별도로 연결된 **iOS and iPadOS 26 (Community)** 라이브러리 소속으로 추정 + +### 재검증: `Bottom Nav` / `Modal` / `Section-header` + +`@wanteddev/wds` 코드 패키지에는 `bottom-navigation`, `modal`, `section-header` 컴포넌트가 실제로 존재해서 이 셋이 WDS일 가능성을 재검토했으나, Figma 쪽 이름으로 다시 검색한 결과 **원래 분류(Stream 로컬)가 맞다**: + +- `Bottom Nav` — WDS에는 `Bottom Navigation/Bottom Navigation`이라는 이름으로 존재(componentKey `e0bf6586448b2b496500a76ee51838f44eb562d6`). Stream 파일의 `component` 섹션에는 이와 별개로 `Bottom Nav`라는 **로컬 컴포넌트 셋**이 직접 정의돼 있고(`Selected=Home/Event/Board/Rental` variant), 화면에서 쓰이는 인스턴스 이름도 `Bottom Navigation/Bottom Navigation`이 아니라 `Bottom Nav`다. 즉 디자이너가 WDS 컴포넌트를 안 쓰고 로컬로 새로 만든 것. +- `Modal` — WDS 라이브러리에서 "Modal"로 검색해도 이름이 일치하는 컴포넌트가 없음(가장 가까운 결과가 무관한 `Icon/Normal/Medal`). Stream 파일의 `Modal`/`Modal/ButtonGroup`은 `Circle Exclamation=on/off`, `Style=Default/Negative` 같은 Stream 전용 variant를 가진 로컬 컴포넌트 셋. +- `Section-header` — WDS 라이브러리에서 "Section Header"로 검색해도 결과 0건. Stream 파일 안의 로컬 컴포넌트. + +**주의**: 이건 "Figma 디자인 파일이 어떤 컴포넌트를 참조하고 있는가"에 대한 결론이지, "코드에서 무엇을 써야 하는가"와는 다른 질문이다. `wds`의 `Modal`/`BottomNavigation`/`SectionHeader` 코드 컴포넌트는 여전히 존재하므로, 실제 구현 시에는 (디자인이 로컬로 그려졌더라도) WDS 코드 컴포넌트를 기반으로 만드는 게 나을 수 있다 — 이건 구현 단계에서 별도로 판단할 문제. + +## 완전 확정 방법 (필요 시) + +이름 대조가 아니라 100% 확정하려면, 확인하고 싶은 인스턴스의 `nodeId`를 알아낸 뒤 `get_design_context(fileKey, nodeId)`를 호출해 응답에 포함된 componentKey를 위 표의 WDS componentKey와 직접 비교하면 된다. 또는 Figma 앱에서 인스턴스 선택 → 우측 패널 "Instance of" → 라이브러리 아이콘 클릭으로도 즉시 확인 가능하다. From 7788cf2dca199add6fe9e1c25e96f6d9174ae730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:18:14 +0900 Subject: [PATCH 2/4] =?UTF-8?q?docs:=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1=20=EC=BB=A8=EB=B2=A4=EC=85=98=20?= =?UTF-8?q?=EB=B0=8F=20/component=20=EC=8A=A4=ED=82=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/skills/component/SKILL.md | 55 +++++++++++++++++++++ docs/conventions/component-convention.md | 61 ++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 .claude/skills/component/SKILL.md create mode 100644 docs/conventions/component-convention.md diff --git a/.claude/skills/component/SKILL.md b/.claude/skills/component/SKILL.md new file mode 100644 index 0000000..4afd22c --- /dev/null +++ b/.claude/skills/component/SKILL.md @@ -0,0 +1,55 @@ +--- +name: component +description: Figma Stream 파일의 노드를 코드 컴포넌트로 옮긴다. WDS(원티드 디자인 시스템) 컴포넌트로 확인되면 @wanteddev/wds를 import해서 재사용하고, Stream 고유 UI만 새로 만든다. /component 로 호출한다. +--- + +# /component — Figma → 코드 컴포넌트 변환 워크플로우 + +Stream Figma 파일의 노드를 받아서, WDS로 확인된 부분은 `@wanteddev/wds`를 import해 재사용하고 Stream 고유 UI만 새로 컴포넌트로 만드는 방식으로 코드를 생성한다. 모든 컴포넌트가 같은 구조를 따르게 하는 게 목적이다. + +> **발동 조건**: `/component`로 호출했을 때. 뒤에 Figma URL(node-id 포함) 또는 node-id가 없으면 임의로 노드를 고르지 말고 사용자에게 요청한다. +> **`figma:figma-design-to-code` 스킬과의 관계**: 이 스킬을 대체하지 않는다. 그 스킬의 "기존 컴포넌트·토큰 재사용" 단계를 WDS 우선 규칙으로 구체화한 래퍼다. `get_design_context`를 호출하기 전 `figma-design-to-code` 스킬(또는 `skill://figma/figma-design-to-code/SKILL.md`)도 함께 로드한다. + +## 상수 + +``` +Stream fileKey: 3QkxTuGLZkB17pZILTog9L +WDS libraryKey: lk-01f447137a741b37c25896e9a4e109dcb719fa4e54177be9a39d24b8da507c109279c2d1d0533b9943595d7d6a5ea398977f43b5d84e163797965d810ba79b69 +``` + +Figma URL이 주어지면 거기서 fileKey/nodeId를 추출한다. node-id만 주어지고 fileKey가 없으면 위 Stream fileKey를 기본값으로 쓴다(이 스킬은 Stream 파일 전용). + +## Step 1 — 대상 노드 확인 + +`get_metadata(fileKey, nodeId)` 또는 `get_screenshot`으로 무엇을 컴포넌트화할지 확인한다. 노드가 화면 전체처럼 너무 크면, 실제로 컴포넌트화할 하위 노드를 좁혀달라고 사용자에게 요청한다 — 임의로 쪼개지 않는다. + +## Step 2 — WDS 대조 + +1. `docs/conventions/wds-component-usage.md`를 먼저 읽는다. 이미 확정된 매핑이 있으면 재조사 없이 바로 쓴다. +2. 대상 노드 안의 인스턴스 중 문서에 없는 이름이 있으면: + 1. `search_design_system`을 WDS libraryKey로 스코프 제한해서 정확한 이름으로 검색한다. + 2. 결과가 애매하면(이름만 비슷하거나 여러 개 매칭) `get_design_context`로 실제 인스턴스 노드를 열어, 응답의 "Component descriptions" 섹션에 나오는 메인 컴포넌트 Node ID·공식 문서 링크(`montage.wanted.co.kr`)로 확정한다. + 3. 새로 확정된 매핑은 `docs/conventions/wds-component-usage.md`의 표에 바로 추가한다 — 이 스킬을 쓸수록 문서가 쌓여서 다음 실행이 더 빨라진다. +3. 매칭도 안 되고 이름도 비슷한 게 없으면 Stream 고유 UI로 취급한다(Step 3-3). + +## Step 3 — 코드 생성 + +1. `get_design_context(fileKey, nodeId)`로 레퍼런스 코드를 받는다. +2. Step 2에서 WDS로 확정된 서브트리는 raw JSX 대신 실제 WDS export로 치환한다. + - export 이름은 반드시 `node_modules/@wanteddev/wds/dist/components/`에서 실존 여부를 확인한 후 쓴다 — 이름을 추측하지 않는다. + - 아이콘은 `@wanteddev/wds-icon`에서 가져온다. + - WDS 컴포넌트 내부를 오버라이드하지 않는다. 레이아웃 조정은 감싸는 wrapper에서 한다. +3. WDS로 확정되지 않은 나머지(Stream 고유 UI)는 `docs/conventions/component-convention.md`를 따라 새 컴포넌트로 작성한다 (파일 구조, variant→Props 유니온 타입 매핑, Figma 노드 추적 주석 등). +4. 이미지·아이콘 asset은 `download_assets`로 받아 `src/assets/`에 커밋한다 — Figma asset URL은 7일 후 만료되므로 그대로 참조하지 않는다. + +## Step 4 — 배치 & 검증 + +1. `docs/conventions/coding-style.md`·`component-convention.md`의 파일 위치 규칙(feature 전용 vs `components/ui/` 공용)에 따라 저장 위치를 정한다. 재사용 범위가 애매하면 사용자에게 확인한다. +2. `pnpm check`(Biome)로 lint/format을 통과시킨다. +3. `component-convention.md`의 "완료 기준 체크리스트"로 스스로 검증한다. + +## Step 5 — 결과 안내 + +- 생성·수정한 파일 경로 +- WDS로 대체한 컴포넌트 목록 / 새로 만든 Stream 고유 컴포넌트 목록 +- `wds-component-usage.md`에 새로 추가한 매핑이 있으면 그 사실을 짚어준다 diff --git a/docs/conventions/component-convention.md b/docs/conventions/component-convention.md new file mode 100644 index 0000000..7ff3bf1 --- /dev/null +++ b/docs/conventions/component-convention.md @@ -0,0 +1,61 @@ +# Component Convention + +> Figma 디자인을 코드 컴포넌트로 옮길 때 따르는 구조 규칙. +> `docs/conventions/coding-style.md`(네이밍·폴더·TS 규칙)를 보완하는 문서이며, `/component` 스킬이 만드는 모든 컴포넌트는 이 규칙을 따른다. + +## 0. 원칙 + +Figma에 있는 요소라고 전부 새로 코드를 짜지 않는다. + +- **WDS(원티드 디자인 시스템) 컴포넌트로 확인된 건 반드시 `@wanteddev/wds`/`@wanteddev/wds-icon`을 import해서 쓴다.** 직접 마크업을 새로 짜지 않는다. 판별 기준은 `docs/conventions/wds-component-usage.md`. +- **Stream 고유 UI만 새 컴포넌트로 만든다** — WDS에 없는, Stream 서비스에서만 쓰는 화면 조각(카드, 리스트 아이템 등). + +## 1. 파일 위치 + +`coding-style.md`의 기능 기반(feature-based) 구조를 따른다. + +- 지금 다루는 화면/기능 전용이면 `features/<기능>/components/.tsx` +- 이미 다른 화면에서도 쓰이는 게 Figma 상에서 확인되면 `components/ui/.tsx` +- **애매하면 먼저 `features/` 아래에 둔다.** 두 번째 화면에서 실제로 재사용될 때 `components/ui/`로 옮긴다 — 성급하게 공용 폴더부터 만들지 않는다(coding-style.md의 "빈 폴더 미리 만들지 않는다"와 같은 이유). + +## 2. 파일 구조 + +- **컴포넌트 하나 = 파일 하나** (`ComponentName.tsx`). 폴더로 쪼개지 않는다 — 실제로 서브컴포넌트가 분리될 필요가 생기면 그때 판단한다. +- Figma의 variant(예: `trailingControl: Button | Stepper`)는 **Props의 유니온 타입 하나로 매핑**한다. variant 조합마다 별도 컴포넌트를 만들지 않는다. +- Props는 `interface`로 선언한다(coding-style.md TypeScript 규칙). + +```tsx +interface RentalItemCardProps { + itemName: string + quantity: number + trailingControl?: 'button' | 'stepper' +} +``` + +## 3. WDS 컴포넌트 사용 + +- 매칭된 서브트리는 `get_design_context`가 준 raw JSX 대신 **실제 WDS export로 치환**한다. +- export 이름은 반드시 `node_modules/@wanteddev/wds/dist/components/`에서 확인 후 쓴다 — 이름을 추측하지 않는다. + - 예: Figma `Button/Button` → `import { Button } from '@wanteddev/wds'` + - 예: Figma `Chip/Chip` → `import { Chip } from '@wanteddev/wds'` +- 아이콘은 `@wanteddev/wds-icon`에서 가져온다. +- **WDS 컴포넌트 내부를 임의로 오버라이드하지 않는다.** 간격·배치 같은 레이아웃 조정은 감싸는 wrapper에서 한다. + +## 4. Stream 고유 UI (신규 컴포넌트) + +- `get_design_context`의 raw JSX/Tailwind는 **레퍼런스일 뿐, 그대로 커밋하지 않는다.** 프로젝트 Tailwind 클래스(추후 `@theme` 토큰이 채워지면 그것)로 다시 짠다. +- Stream 자체 이미지·아이콘(일러스트, 물품 아이콘 등)은 `download_assets`로 받아 `src/assets/`에 커밋한다. Figma asset URL은 **7일 후 만료**되므로 절대 코드에 그대로 참조하지 않는다. +- `data-node-id` 같은 Figma 추적용 속성은 컴포넌트 마크업에 남기지 않는다. 대신 파일 최상단에 원본 Figma 노드를 알 수 있는 주석 한 줄만 남긴다 — 나중에 디자인이 바뀌었을 때 다시 대조할 수 있도록: + +```tsx +// Figma: Rental Item Card (nodeId 1041:61407) +``` + +## 5. 완료 기준 체크리스트 + +- [ ] WDS로 확인된 요소는 전부 import로 대체했다 (raw JSX 없음) +- [ ] Stream 고유 요소만 새 컴포넌트로 작성했다 +- [ ] Props가 Figma variant를 유니온 타입으로 반영한다 +- [ ] 이미지/아이콘 asset을 다운로드해 커밋했다 (만료되는 Figma URL 미참조) +- [ ] 파일 위치가 재사용 범위(feature 전용 vs 공용)에 맞는다 +- [ ] `pnpm check`(Biome) 통과 From f0065d85ad7bc498d1108c1b4205bec40e90bdad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 12:51:22 +0900 Subject: [PATCH 3/4] =?UTF-8?q?docs:=20WDS=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=ED=8C=90=EB=8B=A8=20=EC=9E=AC=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=89=EC=83=81=20=ED=86=A0=ED=81=B0=20=EA=B7=9C?= =?UTF-8?q?=EC=B9=99=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chip/Bottom Nav/버튼 구현 과정에서 드러난 사례를 반영해 wds-component-usage.md와 component-convention.md에 재검증 규칙과 색상 토큰 사용 규칙을 추가한다 --- .claude/skills/component/SKILL.md | 2 +- docs/conventions/component-convention.md | 8 ++++- docs/conventions/wds-component-usage.md | 42 ++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.claude/skills/component/SKILL.md b/.claude/skills/component/SKILL.md index 4afd22c..535655d 100644 --- a/.claude/skills/component/SKILL.md +++ b/.claude/skills/component/SKILL.md @@ -25,7 +25,7 @@ Figma URL이 주어지면 거기서 fileKey/nodeId를 추출한다. node-id만 ## Step 2 — WDS 대조 -1. `docs/conventions/wds-component-usage.md`를 먼저 읽는다. 이미 확정된 매핑이 있으면 재조사 없이 바로 쓴다. +1. `docs/conventions/wds-component-usage.md`를 먼저 읽는다. 이미 확정된 매핑이 있으면 재조사 없이 바로 쓴다 — **단, 대상 노드의 실제 스크린샷/스타일이 문서에 기록된 것과 눈에 띄게 다르면(색상·활성 상태 표현 등) 같은 이름이라도 재확인한다.** 파일 전체에서 한 번 확정된 컴포넌트라도 다른 화면에서는 Stream이 로컬로 새로 만든 동명의 요소일 수 있다(사례: `docs/conventions/wds-component-usage.md`의 "빌릴게 필터 Chip은 WDS Chip/Chip이 아니었다" 참고). 2. 대상 노드 안의 인스턴스 중 문서에 없는 이름이 있으면: 1. `search_design_system`을 WDS libraryKey로 스코프 제한해서 정확한 이름으로 검색한다. 2. 결과가 애매하면(이름만 비슷하거나 여러 개 매칭) `get_design_context`로 실제 인스턴스 노드를 열어, 응답의 "Component descriptions" 섹션에 나오는 메인 컴포넌트 Node ID·공식 문서 링크(`montage.wanted.co.kr`)로 확정한다. diff --git a/docs/conventions/component-convention.md b/docs/conventions/component-convention.md index 7ff3bf1..b9eedfe 100644 --- a/docs/conventions/component-convention.md +++ b/docs/conventions/component-convention.md @@ -43,7 +43,13 @@ interface RentalItemCardProps { ## 4. Stream 고유 UI (신규 컴포넌트) -- `get_design_context`의 raw JSX/Tailwind는 **레퍼런스일 뿐, 그대로 커밋하지 않는다.** 프로젝트 Tailwind 클래스(추후 `@theme` 토큰이 채워지면 그것)로 다시 짠다. +- `get_design_context`의 raw JSX/Tailwind는 **레퍼런스일 뿐, 그대로 커밋하지 않는다.** 프로젝트 Tailwind 클래스로 다시 짜되, 색상은 아래 "색상 토큰" 규칙을 따른다. + +### 색상 토큰 + +- 색은 `text-[#171719]`처럼 hex를 직접 박지 않는다. `src/index.css`의 `@theme` 블록에 있는 시맨틱 토큰(`text-label-normal`, `bg-background-alternative`, `border-line-solid-neutral`, `text-primary`, `bg-primary-subtle` 등)을 쓴다. 이 토큰들은 `@wanteddev/wds/global.css`가 심어둔 `--semantic-*`/`--atomic-*` CSS 변수를 그대로 별칭 연결한 것이라 다크 테마 전환도 자동으로 따라간다. +- 필요한 색이 아직 토큰으로 없으면, hex를 추측해서 쓰지 말고 `get_variable_defs(fileKey, nodeId)`로 해당 노드의 실제 Figma 변수명·값을 확인한 뒤 `index.css`의 `@theme`에 새 토큰을 추가한다. `Line/Normal/Neutral`(반투명 `#70737c29`)과 `Line/Solid/Neutral`(불투명 `#eaebec`)처럼 이름이 비슷해도 값이 다른 토큰이 있으니 이름만 보고 넘겨짚지 않는다. +- 컴포넌트 인스턴스가 없는 화면 배경/외곽선처럼 Figma 값이 실제로는 안 보이는 경우(예: Bottom Nav 상단 border가 바로 위 배경과 같은 색이라 안 보였던 사례)도 있다 — 이럴 땐 왜 다른 토큰으로 바꿨는지 주석으로 남긴다. - Stream 자체 이미지·아이콘(일러스트, 물품 아이콘 등)은 `download_assets`로 받아 `src/assets/`에 커밋한다. Figma asset URL은 **7일 후 만료**되므로 절대 코드에 그대로 참조하지 않는다. - `data-node-id` 같은 Figma 추적용 속성은 컴포넌트 마크업에 남기지 않는다. 대신 파일 최상단에 원본 Figma 노드를 알 수 있는 주석 한 줄만 남긴다 — 나중에 디자인이 바뀌었을 때 다시 대조할 수 있도록: diff --git a/docs/conventions/wds-component-usage.md b/docs/conventions/wds-component-usage.md index e42924b..fd28c06 100644 --- a/docs/conventions/wds-component-usage.md +++ b/docs/conventions/wds-component-usage.md @@ -51,6 +51,48 @@ WDS 컴포넌트만 합산하면 파일 안에서 **약 350회 이상**의 인스턴스가 확인된다(위 표 합계 기준). `Textinput/Textarea`, `Chip/Chip`, `Icon/Normal/Location`, `Icon/Normal/Circle Info`, `Pagination/Dots` 5개는 `get_design_context`로 실제 노드를 열어 WDS 메인 컴포넌트 Node ID(및 3개는 원티드 공식 디자인 시스템 문서 링크)까지 확인해 완전히 확정했다. +## 이후 세션에서 개별 화면 작업 중 추가 확인된 매핑 + +파일 전체 스캔이 아니라 `/component`로 특정 화면(빌릴게, `1243:73331`)을 구현하면서 `get_design_context`로 열어본 김에 확정한 것들. 인스턴스 수는 파일 전체 기준이 아니라 "이 화면에서 확인됨"이다. + +| WDS 컴포넌트 | 확인 경로 | WDS 메인 컴포넌트 Node ID / 문서 | +|---|---|---| +| `Segmented Control/Segmented Control` | 빌릴게 화면 Top Navigation 안 "대여/반납" 토글 | `500:11592` — [문서](https://montage.wanted.co.kr/docs/components/selection-and-input/segmented-control/design) | +| `Icon/Normal/Search` | 빌릴게 화면 Top Navigation 트레일링 아이콘 | `445:5904` | +| `Icon/Normal/Bell` | 빌릴게 화면 Top Navigation 트레일링 아이콘 | `445:13236` | +| `Icon/Normal/Home` | Bottom Nav "홈" 탭(Normal 상태) | `980:35475` | +| `Icon/Normal/Ticket` | Bottom Nav "행사" 탭(Normal 상태) | `980:35529` | +| `Icon/Normal/List` | Bottom Nav "게시판" 탭(Normal 상태) | `980:35703` | + +코드에서는 `@wanteddev/wds-icon`의 `IconSearch`/`IconBell`/`IconHome`/`IconTicket`/`IconList`로 대응된다(각각 default export를 `index.d.ts`에서 named export로 재노출). `Segmented Control`은 `@wanteddev/wds`의 `SegmentedControl`/`SegmentedControlItem`으로 대응된다. + +### 반례 — 빌릴게 필터 Chip은 WDS `Chip/Chip`이 아니었다 + +위 "WDS 컴포넌트로 확인됨" 표에 `Chip/Chip`이 파일 전체 기준 24개 인스턴스로 확정돼 있다고 해서, **다른 화면의 비슷하게 생긴 칩도 자동으로 WDS라고 가정하면 안 된다.** 빌릴게 화면의 카테고리 필터(전체/전자기기/생활잡화/상비약/위생용품)를 처음 구현할 때 이 표만 보고 재조사 없이 WDS `Chip`을 그대로 썼는데, 실제 Figma 스타일(활성 = 연한 파랑 배경 + 파랑 outline, 비활성 = 회색 outline)이 WDS Chip의 기본 활성 스타일(검정 배경)과 달랐다 — Stream이 로컬로 새로 만든 칩이었다. **스타일이 눈에 띄게 다르면, 이름이 같아 보여도 그 인스턴스는 따로 `get_design_context`로 열어 확인한다.** 코드는 `src/features/rental/components/RentalCategoryFilter.tsx` 참고 (plain ` +``` + +hex를 하드코딩하지 않고 `index.css`의 색상 토큰을 그대로 참조했고, `Button` 자체(접근성 속성, `disabled`/`loading` 상태 처리 등)는 그대로 재사용한다. `src/features/rental/components/RentalItemCard.tsx` 참고. + ## 제외됨 — Stream 자체 로컬 컴포넌트 (WDS 아님) 이름은 비슷해 보여도 WDS 검색 결과에 없거나, `component` 섹션(985:36615)에서 로컬 심볼로 직접 정의된 것들: From b60bda2e3546977ec338d90c925a8e0c1f3d6d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 12:51:31 +0900 Subject: [PATCH 4/4] =?UTF-8?q?docs:=20Figma=20=EA=B5=90=EC=B0=A8=EA=B2=80?= =?UTF-8?q?=EC=A6=9D(/figma-check)=20=EC=8A=A4=ED=82=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 구현된 코드가 Figma 디자인과 1:1로 일치하는지 색상 토큰·WDS 컴포넌트 판단· 박스모델·컴포넌트 기본값·스크린샷까지 대조해 리포트하는 검증 전용 스킬 --- .claude/skills/figma-check/SKILL.md | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .claude/skills/figma-check/SKILL.md diff --git a/.claude/skills/figma-check/SKILL.md b/.claude/skills/figma-check/SKILL.md new file mode 100644 index 0000000..4afeaf8 --- /dev/null +++ b/.claude/skills/figma-check/SKILL.md @@ -0,0 +1,76 @@ +--- +name: figma-check +description: 이미 구현된 코드가 Figma 디자인과 1:1로 일치하는지 교차검증한다. 색상 토큰, WDS 컴포넌트 사용 판단, 레이아웃/패딩, 실제 렌더링 스크린샷까지 대조해서 불일치를 번호 매겨 리포트한다. /figma-check [코드 파일 경로]로 호출한다. +--- + +# /figma-check — Figma ↔ 구현 교차검증 워크플로우 + +`/component`로 만든 코드가 시간이 지나거나 다른 세션에서 수정되면서 Figma 원본과 어긋나지 않았는지 확인한다. **이 스킬은 검증만 한다 — 발견한 불일치를 자동으로 고치지 않는다.** 수정은 사용자가 결과를 보고 별도로 요청할 때 진행한다. + +> **발동 조건**: `/figma-check`로 호출했을 때. 뒤에 Figma URL(node-id 포함) 또는 node-id가 없으면 임의로 노드를 고르지 말고 사용자에게 요청한다. +> **`/component`와의 관계**: `/component`가 "Figma → 코드"를 만드는 스킬이라면, 이 스킬은 그 결과물이 여전히 Figma와 맞는지 "코드 ↔ Figma"를 되짚어 확인하는 스킬이다. 둘 다 같은 컨벤션 문서(`docs/conventions/component-convention.md`, `wds-component-usage.md`)를 기준으로 삼는다. + +## 상수 + +``` +Stream fileKey: 3QkxTuGLZkB17pZILTog9L +WDS libraryKey: lk-01f447137a741b37c25896e9a4e109dcb719fa4e54177be9a39d24b8da507c109279c2d1d0533b9943595d7d6a5ea398977f43b5d84e163797965d810ba79b69 +``` + +Figma URL이 주어지면 거기서 fileKey/nodeId를 추출한다. node-id만 주어지고 fileKey가 없으면 위 Stream fileKey를 기본값으로 쓴다. + +## Step 1 — 대상 코드 파일 확정 + +- 사용자가 코드 경로를 같이 줬으면 그걸 쓴다. +- 안 줬으면 `component-convention.md`가 요구하는 `// Figma: ... (nodeId )` 파일 최상단 주석을 근거로 찾는다: + +```bash +grep -rln "nodeId <해당 id>\|nodeId \`<해당 id>\`" src/ --include="*.tsx" +``` + +- 매칭이 여러 개거나 하나도 없으면 임의로 고르지 말고 사용자에게 확인한다. 검증 대상이 화면 전체(여러 컴포넌트로 조립됨)면, `get_metadata`로 하위 노드 구조를 먼저 파악해 관련 컴포넌트 파일들을 전부 나열한다. + +## Step 2 — Figma 레퍼런스 수집 + +대상 노드에 대해 아래 세 가지를 받는다 (`figma:figma-design-to-code` 스킬도 함께 로드). + +1. `get_design_context(fileKey, nodeId)` — 레퍼런스 JSX/스타일과 "Component descriptions" 섹션(WDS 메인 컴포넌트 Node ID·문서 링크 확정용) +2. `get_screenshot(fileKey, nodeId)` — 비교용 스크린샷. 로컬에 저장해둔다 +3. `get_variable_defs(fileKey, nodeId)` — 이 노드에서 실제 쓰이는 Figma 변수명과 값(색상·타이포) + +## Step 3 — 실제 렌더링 캡처 + +1. dev 서버가 안 떠 있으면 `pnpm dev`로 띄운다(포트 충돌 시 기존 프로세스 정리 후 재시작). +2. `run` 스킬(또는 `chromium-cli`, 없으면 `npx playwright`)로 대상 화면/컴포넌트를 렌더링해서 스크린샷을 찍는다. 특정 variant(예: 선택 상태, 스테퍼 모드)를 봐야 하면 클릭 등으로 상태를 재현한 뒤 캡처한다. +3. 확인이 끝나면 띄운 dev 서버는 정리한다(사용자가 계속 쓰라고 하지 않는 한). + +## Step 4 — 교차검증 체크리스트 + +아래 다섯 가지를 순서대로 확인한다. 항목마다 통과/불일치를 기록해둔다. + +1. **비주얼 비교**: Step 2의 Figma 스크린샷과 Step 3의 실제 렌더링을 나란히 놓고 본다. 레이아웃, 정렬, 간격, 색감, 잘림 여부를 확인한다. +2. **색상 토큰**: 대상 코드에 `text-[#...]`, `bg-[#...]`, `border-[#...]` 같은 하드코딩 hex가 남아있으면 전부 지적한다. `docs/conventions/component-convention.md`의 "색상 토큰" 규칙대로 `src/index.css`의 `@theme` 토큰을 써야 한다. 이미 토큰이 있는데 못 찾고 hex를 새로 박은 경우도 있을 수 있으니, hex 값을 Step 2의 `get_variable_defs` 결과와 대조해서 맞는 토큰이 있는지 확인한다. 이름이 비슷해도 값이 다른 토큰들(예: `Line/Normal/Neutral` 반투명 vs `Line/Solid/Neutral` 불투명)을 혼동하지 않았는지 특히 주의한다. +3. **WDS 판단 재검증**: 코드가 `@wanteddev/wds`/`@wanteddev/wds-icon`을 import하는 자리마다 `docs/conventions/wds-component-usage.md`에 그 판단 근거가 있는지 확인한다. 없으면 Step 2의 Component descriptions로 확정하고 문서에 추가한다. 반대 방향도 확인한다 — Stream 로컬로 새로 만든 부분이 사실 WDS 컴포넌트인 경우, 또는 이름은 같지만 실제로는 다른 스타일(활성 상태 표현 등)이라 Stream 로컬이 맞는 경우. +4. **박스모델 실측**: 브라우저에서 대표 요소 하나를 골라 `getComputedStyle`로 padding/border-width/margin이 의도한 값과 맞는지 찍어본다. 특히 `0px`으로 죽어있으면 CSS 우선순위 문제(예: 레이어 밖 전역 reset이 Tailwind 유틸리티를 이기는 문제 — `docs/plans/rental-list-screen.md` 참고)를 의심한다. +5. **컴포넌트 기본값 재확인**: WDS 컴포넌트를 쓸 때 명시하지 않은 prop의 기본값이 Figma 디자인과 다른 걸 렌더링하고 있지 않은지 확인한다(예: `TopNavigation`의 기본 `variant="normal"`이 타이틀을 가운데 정렬시켜서 Figma의 좌측 정렬과 어긋났던 사례, `background` 기본값이 iOS 반투명 스타일이라 배경색이 미묘하게 달라 보였던 사례). 의심되면 해당 컴포넌트의 `node_modules/@wanteddev/wds/dist/components//style.js`를 직접 열어 실제 동작을 확인한다. + +## Step 5 — 결과 안내 + +`pr-check` 스킬과 같은 형식으로, 발견한 불일치를 중요도 순으로 번호 매겨 나열한다. + +``` +## Figma 교차검증 결과 — {대상} (nodeId {id}) + +1. 🔴 [파일:라인] 무엇이 다른지 + - Figma: {기대값} + - 코드: {실제값} + - 수정 방안: {한두 문장} + +2. 🟡 [파일:라인] ... +``` + +- 🔴 High: 화면에 실제로 다르게 보이는 것(레이아웃 깨짐, 색 틀림, WDS 컴포넌트 오판으로 동작이 다름) +- 🟡 Medium: 지금 당장 안 보이지만 잠재적으로 문제(하드코딩 hex가 토큰과 값은 같지만 토큰을 안 써서 나중에 디자인 바뀌면 안 따라가는 경우 등) +- 🟢 Low: 사소한 스타일 차이, 주석/문서 누락 +- 전부 통과했으면 "N개 항목 모두 Figma와 일치" 로 짧게 알린다. +- 새로 확정된 WDS 매핑이나 색상 토큰이 있으면 `docs/conventions/wds-component-usage.md` / `component-convention.md`에 반영했는지 짚어준다.