---
description: Figma URL과 출력 경로를 받아 Code Connect로 DS 컴포넌트를 식별하고 Storybook MCP(`storybook-mcp`) 사용법 기준으로 page.tsx + page.module.scss를 생성한다.
---

주어진 Figma URL의 디자인을 React + `sales-frontend-design-system` 환경에 맞는 코드로 변환하고, 지정한 출력 경로에 `page.tsx`와 `page.module.scss`를 생성한다.
page 컴포넌트는 상단에 `'use client';`를 추가한다.

## 입력

- **Figma URL**: `$ARGUMENTS`의 첫 번째 인자
- **출력 경로**: `$ARGUMENTS`의 두 번째 인자 (예: `apps/docs/app/external/my-page`)

## 산출물 제한

- 출력 경로 디렉터리 생성은 허용한다.
- 생성 또는 수정 가능한 파일은 출력 경로의 `page.tsx`와 `page.module.scss` 두 개뿐이다.
- 모든 임시 컴포넌트, 상수, mock 데이터, 헬퍼 함수는 `page.tsx` 안에 작성한다.
- 별도 컴포넌트 파일, story 파일, 테스트 파일, asset 파일은 만들지 않는다.
- 디자인 시스템 컴포넌트는 `sales-frontend-design-system`에서 import한다.
- 시스템 아이콘은 `sales-frontend-assets`에서 import한다.

## 핵심 원칙

1. **Code Connect는 컴포넌트 식별과 Figma 값 추출용 힌트다.** `<CodeConnectSnippet>`에서 디자인 시스템 컴포넌트 후보, import 후보, 매핑된 Figma property 값, 텍스트, 상태, 아이콘 후보를 파악한다.
2. **실제 사용법과 구현 패턴은 Storybook MCP(`storybook-mcp`)가 기준이다.** 디자인 시스템 컴포넌트를 사용한다면 Storybook MCP(`storybook-mcp`)에서 props, variant, children 구조, Compound 조립, event/ref 패턴을 확인한 뒤 구현한다.
3. **값은 Figma/Code Connect, 사용법은 Storybook MCP를 따른다.** 텍스트, 선택 상태, disabled/error/readOnly, size, variant 등 실제 디자인 값은 Figma MCP와 Code Connect에서 가져오고, JSX 작성 방식은 Storybook MCP(`storybook-mcp`)의 문서와 Story 예시를 따른다.
4. **같은 컴포넌트는 한 번만 조회한다.** 동일 디자인 시스템 컴포넌트를 여러 번 사용할 경우 Storybook MCP(`storybook-mcp`) 조회 결과를 캐시해 재사용한다.
5. **추측으로 props를 만들지 않는다.** Storybook MCP(`storybook-mcp`) 문서/Story 또는 Code Connect 매핑에서 확인되지 않은 prop, variant, size, appearance 값은 사용하지 않는다.
6. **디자인의 모든 시각 요소를 포함한다.** Code Connect snippet이 일부만 표현하면 Storybook MCP(`storybook-mcp`)와 Figma 노드 정보를 사용해 누락 요소를 보완한다.
7. **레이아웃과 비컴포넌트 영역은 module.scss로 구현한다.** Figma의 auto-layout, spacing, color, typography, radius, shadow 정보를 디자인 토큰으로 변환한다.

## 실행 흐름

1. **Figma 분석**

   - Figma MCP의 `get_metadata`와 `get_design_context`로 노드 구조, 텍스트, 컴포넌트 인스턴스, variant/state, style/token 정보를 파악한다.
   - 가능하면 Figma MCP의 `get_screenshot`으로 원본 스크린샷을 확보해 최종 검증 기준으로 사용한다.
   - 응답 안의 `<CodeConnectSnippet>` 영역과 그 밖의 wrapper/layout 영역을 구분한다.
   - 각 `<CodeConnectSnippet>`에서 사용할 디자인 시스템 컴포넌트 후보, import 후보, 매핑된 Figma 값, 누락된 시각 요소를 추출한다.

2. **노드별 변환 결정**

   - 각 Figma 노드를 아래 **컴포넌트 결정 우선순위**에 따라 변환한다.
   - Code Connect에서 식별된 디자인 시스템 컴포넌트는 구현 전 Storybook MCP(`storybook-mcp`)로 실제 사용법을 확인한다.
   - 동일 디자인 시스템 컴포넌트를 여러 번 사용할 경우 Storybook MCP(`storybook-mcp`) 조회는 한 번만 하고, 확인한 props/패턴을 재사용한다.
   - Storybook MCP(`storybook-mcp`)를 호출할 때마다 조회 로그를 남긴다. 로그에는 최소한 `컴포넌트명`, `조회 이유`, `참조한 Story/문서 title`, `확인한 props/패턴`을 포함한다.

3. **코드 생성**

   - React 컴포넌트, 필요한 import, 화면 데이터, 이벤트 placeholder를 작성한다.
   - Style은 `.module.scss`에 작성하고 wrapper/layout, 직접 구현한 요소의 스타일, 토큰 기반 spacing/color/typography를 작성한다.
   - `<CodeConnectSnippet>` 밖의 Tailwind class가 제공되면 그대로 쓰지 말고 이 문서의 토큰 규칙에 맞춰 SCSS module로 변환한다.
   - Tailwind class가 없으면 Figma metadata의 layout/style 값을 기준으로 SCSS module을 작성한다.

4. **검증 및 보정**
   - PLACEHOLDER 문자열이 남아 있지 않은지 확인한다.
   - 사용한 디자인 시스템 prop과 variant가 Code Connect 또는 Storybook MCP(`storybook-mcp`)에서 확인된 값인지 확인한다.
   - 원본 screenshot과 JSX/SCSS 결과를 비교해 레이아웃, 간격, 색상, 타이포, 누락 요소를 점검한다.
   - 불일치가 있으면 최대 2회까지 보정한다.
   - 가능하면 프로젝트의 lint/typecheck 명령을 실행한다. 명령을 알 수 없거나 실행이 불가능하면 최종 응답에 미실행 사유를 남긴다.

## 컴포넌트 결정 우선순위

### 1순위: Code Connect로 컴포넌트 식별

Figma MCP 응답의 `<CodeConnectSnippet>`은 최종 구현 코드가 아니라 디자인 시스템 컴포넌트를 식별하고 Figma 값을 추출하기 위한 힌트로 사용한다.

- 사용할 디자인 시스템 컴포넌트 후보와 import 후보를 파악한다.
- Figma property에서 매핑된 variant, size, state, 텍스트, 아이콘 후보를 파악한다.
- Code Connect snippet을 그대로 최종 코드로 확정하지 않는다.

### 2순위: Storybook MCP(`storybook-mcp`)로 사용법 확정

Code Connect로 식별한 디자인 시스템 컴포넌트는 Storybook MCP(`storybook-mcp`)에서 실제 사용법을 확인한 뒤 구현한다.

- 조회 범위는 `Design System/...` 또는 `Components/...` title prefix Stories로 제한한다.
- 다른 패키지, 페이지 데모, `Utils/...`, `Hooks/...`, `API/...` Stories는 props 매핑 근거로 사용하지 않는다.
- 같은 컴포넌트는 한 번만 조회하고 결과를 재사용한다.
- JSX 구조와 prop 사용법은 Storybook MCP(`storybook-mcp`)를 따른다.
- 텍스트, 상태, variant, size, item 개수, 아이콘 등 실제 값은 Figma MCP와 Code Connect에서 가져온다.
- Storybook MCP(`storybook-mcp`)에서 확인되지 않은 prop이나 variant 값은 사용하지 않는다.

### 3순위: HTML + module.scss 직접 구현

Code Connect로 디자인 시스템 컴포넌트를 식별할 수 없거나, Storybook MCP(`storybook-mcp`)에서도 적합한 디자인 시스템 컴포넌트를 확인할 수 없으면 직접 구현한다.

## 특수 패턴 처리

### PLACEHOLDER 아이콘

- `dsp-icons-icons-sub-ui-PLACEHOLDER` 같은 문자열이 남아 있으면 실패로 간주한다.
- Figma 노드의 instance swap 이름, `data-name`, 아이콘 노드명을 확인해 실제 아이콘으로 교체한다.
- 시스템 아이콘은 `sales-frontend-assets`의 React SVG 컴포넌트를 사용한다.
- 그래픽/일러스트 아이콘은 CSS class 기반 아이콘으로 표현한다.

### Label vs Fieldset

- 단일 입력에 붙은 label은 Code Connect 또는 Storybook MCP(`storybook-mcp`)에서 확인한 `Label` 계열 컴포넌트를 사용한다.
- checkbox group, radio group, chip group처럼 멀티 입력 그룹에 붙은 label은 `Fieldset.Root` + `Fieldset.Legend` + `Fieldset.Items` 패턴을 우선 검토한다.
- `Label`과 `Fieldset`의 실제 import/props/children 구조는 Storybook MCP(`storybook-mcp`)로 확인한 뒤 작성한다.

### JSX 작성 규칙

- 이벤트 핸들러가 필요하지만 실제 동작 요구가 없으면 `() => {}` 또는 명확한 local placeholder 함수를 사용한다.
- CSS Module className은 `classnames/bind` 패턴으로 적용한다. 문자열 className 직접 전달은 금지한다.

## SCSS 작성 규칙

```scss
@use 'sales-frontend-design-system/design-system-context' as *;
```

- `.module.scss` 상단에는 위 `@use`를 선언한다.
- 추가 `@use`는 이 문서에 없는 토큰/믹스인이 꼭 필요할 때만 사용한다.
- Figma auto-layout은 `display: flex`, `flex-direction`, `align-items`, `justify-content`, `gap`으로 변환한다.
- 반응형 정보가 Figma에 있거나 화면 특성상 필요한 경우 `@include media(tablet|pc|pc-wide)`를 사용한다.
- 디자인 시스템 컴포넌트 내부 스타일을 무리하게 override하지 않는다. 필요한 경우 wrapper spacing만 조정한다.

## 디자인 토큰 매핑

### 색상 — `colors(토큰명)`

| Figma 변수           | SCSS 함수                   |
| -------------------- | --------------------------- |
| `Surface/primary`    | `colors(surface-primary)`   |
| `Surface/secondary`  | `colors(surface-secondary)` |
| `Surface/neutral`    | `colors(surface-neutral)`   |
| `Surface/neutral_1`  | `colors(surface-neutral_1)` |
| `Surface/neutral_2`  | `colors(surface-neutral_2)` |
| `Surface/neutral_3`  | `colors(surface-neutral_3)` |
| `Surface/neutral_4`  | `colors(surface-neutral_4)` |
| `Text/primary`       | `colors(text-primary)`      |
| `Text/secondary`     | `colors(text-secondary)`    |
| `Text/body`          | `colors(text-body)`         |
| `Text/body_0`        | `colors(text-body_0)`       |
| `Text/body_1`        | `colors(text-body_1)`       |
| `Text/body_2`        | `colors(text-body_2)`       |
| `Text/body_3`        | `colors(text-body_3)`       |
| `Text/neutral_1`     | `colors(text-neutral_1)`    |
| `Text/neutral_2`     | `colors(text-neutral_2)`    |
| `Border/primary_1`   | `colors(border-primary_1)`  |
| `Border/primary_2`   | `colors(border-primary_2)`  |
| `Border/neutral_1`   | `colors(border-neutral_1)`  |
| `Border/neutral_2`   | `colors(border-neutral_2)`  |
| `Border/neutral_3`   | `colors(border-neutral_3)`  |
| `Border/neutral_4`   | `colors(border-neutral_4)`  |
| `Border/neutral_5`   | `colors(border-neutral_5)`  |
| `Border/neutral_6`   | `colors(border-neutral_6)`  |
| `Background/white`   | `colors(background-100)`    |
| `Background/neutral` | `colors(background-200)`    |
| `Background/dimmed`  | `colors(background-dimmed)` |

### 패딩 — `padding(토큰명)`

| Figma 변수          | SCSS 함수            |
| ------------------- | -------------------- |
| `Padding/zero`      | `padding(zero)`      |
| `Padding/xxxxSmall` | `padding(xxxxsmall)` |
| `Padding/xxxSmall`  | `padding(xxxsmall)`  |
| `Padding/xxSmall`   | `padding(xxsmall)`   |
| `Padding/xSmall`    | `padding(xsmall)`    |
| `Padding/small`     | `padding(small)`     |
| `Padding/medium`    | `padding(medium)`    |
| `Padding/large`     | `padding(large)`     |
| `Padding/xLarge`    | `padding(xlarge)`    |
| `Padding/xxLarge`   | `padding(xxlarge)`   |
| `Padding/xxxLarge`  | `padding(xxxlarge)`  |
| `Padding/xxxxLarge` | `padding(xxxxlarge)` |

### 마진 — `margin(토큰명)`

| Figma 변수                     | SCSS 함수                       |
| ------------------------------ | ------------------------------- |
| `Margin/zero`                  | `margin(zero)`                  |
| `Margin/inputfield-vertical`   | `margin(inputfield-vertical)`   |
| `Margin/inputfield-horizontal` | `margin(inputfield-horizontal)` |
| `Margin/button-large`          | `margin(button-large)`          |
| `Margin/button-medium`         | `margin(button-medium)`         |
| `Margin/button-small`          | `margin(button-small)`          |
| `Margin/card`                  | `margin(card)`                  |
| `Margin/divider-xlarge`        | `margin(divider-xlarge)`        |
| `Margin/divider-large`         | `margin(divider-large)`         |
| `Margin/divider-medium`        | `margin(divider-medium)`        |
| `Margin/divider-small`         | `margin(divider-small)`         |
| `Margin/divider-xsmall`        | `margin(divider-xsmall)`        |
| `Margin/title-xlarge`          | `margin(title-xlarge)`          |
| `Margin/title-large`           | `margin(title-large)`           |
| `Margin/title-medium`          | `margin(title-medium)`          |
| `Margin/title-small`           | `margin(title-small)`           |
| `Margin/title-xsmall`          | `margin(title-xsmall)`          |
| `Margin/textarea-large`        | `margin(textarea-large)`        |
| `Margin/textarea-medium`       | `margin(textarea-medium)`       |
| `Margin/textarea-small`        | `margin(textarea-small)`        |
| `Margin/textarea-xsmall`       | `margin(textarea-xsmall)`       |
| `Margin/textarea-xxsmall`      | `margin(textarea-xxsmall)`      |
| `Margin/card/around_large`     | `margin(card-around-large)`     |
| `Margin/card/around_small`     | `margin(card-around-small)`     |
| `Margin/modal`                 | `margin(modal)`                 |

### 보더 라디우스 — `radius-basic(토큰명)`

| Figma 변수      | SCSS 함수              |
| --------------- | ---------------------- |
| `Corner/small`  | `radius-basic(small)`  |
| `Corner/medium` | `radius-basic(medium)` |
| `Corner/large`  | `radius-basic(large)`  |
| `Corner/xlarge` | `radius-basic(xlarge)` |
| `Corner/full`   | `radius-basic(full)`   |

### 그림자 — `shadow(토큰명)`

| Figma 변수      | SCSS 함수        |
| --------------- | ---------------- |
| `Shadow/small`  | `shadow(small)`  |
| `Shadow/medium` | `shadow(medium)` |
| `Shadow/large`  | `shadow(large)`  |

```scss
.card {
  box-shadow: shadow(medium);
}
```

### 호버 — `@include hover { ... }`

터치 디바이스에서 sticky hover를 방지하는 믹스인. 데스크톱에서는 `:hover`, 터치 디바이스에서는 `:active`로 자동 분기된다.

```scss
.card {
  @include hover {
    background-color: colors(surface-neutral_1);
  }
}
```

### 반응형 — `@include media(디바이스) { ... }`

| 디바이스  | 브레이크포인트      | 설명         |
| --------- | ------------------- | ------------ |
| `tablet`  | `min-width: 768px`  | 태블릿 이상  |
| `pc`      | `min-width: 1281px` | PC 이상      |
| `pc-wide` | `min-width: 1441px` | PC Wide 이상 |

```scss
.container {
  padding: padding(small);

  @include media(tablet) {
    padding: padding(medium);
  }

  @include media(pc) {
    padding: padding(large);
  }
}
```

### 타이포그래피 — `@include apply-typography(토큰명)`

| Figma 변수                | SCSS 믹스인                      |
| ------------------------- | -------------------------------- |
| `Typography/title1`       | `apply-typography(title1)`       |
| `Typography/title2`       | `apply-typography(title2)`       |
| `Typography/title3`       | `apply-typography(title3)`       |
| `Typography/title4`       | `apply-typography(title4)`       |
| `Typography/title5`       | `apply-typography(title5)`       |
| `Typography/subtitle1`    | `apply-typography(subtitle1)`    |
| `Typography/subtitle2`    | `apply-typography(subtitle2)`    |
| `Typography/subtitle3`    | `apply-typography(subtitle3)`    |
| `Typography/body1`        | `apply-typography(body1)`        |
| `Typography/body2`        | `apply-typography(body2)`        |
| `Typography/body3`        | `apply-typography(body3)`        |
| `Typography/body4`        | `apply-typography(body4)`        |
| `Typography/caption`      | `apply-typography(caption)`      |
| `Typography/link_large`   | `apply-typography(link_large)`   |
| `Typography/link_medium`  | `apply-typography(link_medium)`  |
| `Typography/link_small`   | `apply-typography(link_small)`   |
| `Typography/input_large`  | `apply-typography(input_large)`  |
| `Typography/input_medium` | `apply-typography(input_medium)` |
| `Typography/input_small`  | `apply-typography(input_small)`  |

## 아이콘 변환 규칙

피그마에서 아이콘 노드의 `data-name` 또는 instance swap 이름이 `sub-ui/*`, `main-ui/*`, `graphics/*`, `images/*`, `illust/*` 형태이면 아래 규칙으로 변환한다.

- 시스템 아이콘 (`sub-ui/*`, `main-ui/*`)은 `sales-frontend-assets`에서 SVG React 컴포넌트를 import한다.
- 그래픽/일러스트 (`graphics/*`, `images/*`, `illust/*`)는 아이콘 CSS class를 사용한다.
- 정확한 export 이름이 확실하지 않으면 repository 또는 Storybook MCP(`storybook-mcp`) 예시에서 확인한 뒤 사용한다.

```tsx
import { IconSubUiArrowRightWhite } from 'sales-frontend-assets';

<Button
  variant="primary"
  size="medium"
  appearance="filled"
  icon={<IconSubUiArrowRightWhite width={20} height={20} />}
  iconDir="right"
>
  다음
</Button>;

<span className={cx('dsp-icons', 'dsp-icons-graphics-avatar-man-60')} />;
```

## 최종 응답 형식

작업 완료 후 다음을 간단히 보고한다.

- 생성한 파일 경로
- 사용한 주요 DS 컴포넌트
- Storybook MCP(`storybook-mcp`) 조회 로그. 조회하지 않았다면 `조회 없음`으로 명시
- 실행한 검증 명령과 결과, 또는 미실행 사유
- 원본과 남은 차이가 있으면 구체적인 차이
