Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .claude/skills/component/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: component
description: Figma Stream 파일의 노드를 코드 컴포넌트로 옮긴다. WDS(원티드 디자인 시스템) 컴포넌트로 확인되면 @wanteddev/wds를 import해서 재사용하고, Stream 고유 UI만 새로 만든다. /component <figma URL 또는 node-id>로 호출한다.
---

# /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`를 먼저 읽는다. 이미 확정된 매핑이 있으면 재조사 없이 바로 쓴다 — **단, 대상 노드의 실제 스크린샷/스타일이 문서에 기록된 것과 눈에 띄게 다르면(색상·활성 상태 표현 등) 같은 이름이라도 재확인한다.** 파일 전체에서 한 번 확정된 컴포넌트라도 다른 화면에서는 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`)로 확정한다.
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`에 새로 추가한 매핑이 있으면 그 사실을 짚어준다
76 changes: 76 additions & 0 deletions .claude/skills/figma-check/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
name: figma-check
description: 이미 구현된 코드가 Figma 디자인과 1:1로 일치하는지 교차검증한다. 색상 토큰, WDS 컴포넌트 사용 판단, 레이아웃/패딩, 실제 렌더링 스크린샷까지 대조해서 불일치를 번호 매겨 리포트한다. /figma-check <figma URL 또는 node-id> [코드 파일 경로]로 호출한다.
---

# /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 <id>)` 파일 최상단 주석을 근거로 찾는다:

```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/<name>/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`에 반영했는지 짚어준다.
67 changes: 67 additions & 0 deletions docs/conventions/component-convention.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# 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/<ComponentName>.tsx`
- 이미 다른 화면에서도 쓰이는 게 Figma 상에서 확인되면 `components/ui/<ComponentName>.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 클래스로 다시 짜되, 색상은 아래 "색상 토큰" 규칙을 따른다.

### 색상 토큰

- 색은 `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 노드를 알 수 있는 주석 한 줄만 남긴다 — 나중에 디자인이 바뀌었을 때 다시 대조할 수 있도록:

```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) 통과
Loading