---
description: Figma 참조를 분석해 /gen-html local-server Storybook용 __generated__.stories.tsx와 __generated__.module.scss를 생성한다.
---

# Gen HTML Storybook 생성 규칙

## 참조 조건

- `/gen-html` 또는 `/gen-html-multiple` 이 Figma 참조를 local-server Storybook 산출물로 변환해야 할 때 이 문서를 읽는다.
- Code Connect로 디자인 시스템 컴포넌트 후보와 Figma 값을 식별하고, Storybook MCP(`storybook-mcp`) 기준으로 실제 사용법을 확정해야 할 때 이 문서를 읽는다.
- 응답 본문에서 자동 저장할 파일 내용을 반환해야 할 때 이 문서를 읽는다.

## 입력

- 작업 입력값에는 컴포넌트명, 출력 디렉터리, Storybook title prefix, Figma 참조 목록, local-server 의존성 목록이 제공된다.
- Figma 참조가 여러 개인 경우 각 참조를 별도 산출물로 나누지 않고, 동일 컴포넌트의 상태, validation, interaction 후보로 통합한다.
- Figma MCP의 `nodeId` 인자에는 URL 전체가 아니라 작업 입력값의 Figma 조회 힌트에 적힌 node id만 사용한다.

## 산출물 계약

- 생성 대상 파일은 출력 디렉터리 내부의 `__generated__.stories.tsx` 와 `__generated__.module.scss` 두 개뿐이다.
- 별도 컴포넌트 파일, 테스트 파일, asset 파일, fixture 파일, 앱 라우터 엔트리 파일은 생성하지 않는다.
- 모든 임시 컴포넌트, 상수, mock 데이터, helper 함수는 `__generated__.stories.tsx` 안에 작성한다.
- Storybook + Vite local-server에서 독립 실행 가능한 story 파일을 기준으로 작성한다.
- `next/image`, `next/link`, `next/navigation`, `next/router` 를 import 하지 않는다.
- `@/`, `~`, `src/` 같은 앱 전용 path alias import 를 사용하지 않는다.
- 로컬 워크스페이스 내부 상대경로 import 에 의존하지 않는다.
- local-server 기본/추가 dependency로 해석 가능한 패키지 import 만 사용한다.

## Storybook export 계약

- story 파일은 named export를 정확히 3개 제공한다.
  - `ComponentPreview`
  - `AccessibilityChecklist`
  - `WebStandardsChecklist`
- Story meta의 `title` 은 정적 문자열 literal이어야 하며, 작업 입력값의 Storybook title prefix로 시작한다.
- `ComponentPreview` 는 실제 Figma 변환 결과를 렌더링한다.
- `AccessibilityChecklist` 와 `WebStandardsChecklist` 는 이름만 선언하지 말고, 실제 체크리스트 UI와 항목 데이터를 가진 story로 작성한다.
- checklist 항목은 `통과` 또는 `보완 필요` 상태를 함께 보여준다.

```tsx
const CHECKLIST_ITEMS: ChecklistItemData[] = [{ label: '체크한 항목내용', isPass: true }];

/** @description 웹표준 또는 접근성 체크리스트 컴포넌트 */
const ChecklistView = () => {
  return (
    <div className={cx('checklist')}>
      <h3 className={cx('checklist-title')}>점검 항목</h3>
      {CHECKLIST_ITEMS.map((item) => (
        <div key={item.label} className={cx('checklist-item')}>
          <span className={cx('checklist-label')}>{item.label}</span>
          <span className={cx(item.isPass ? 'status-pass' : 'status-need')}>{item.isPass ? '통과' : '보완 필요'}</span>
        </div>
      ))}
    </div>
  );
};
```

## 구현 우선순위

1. Figma MCP와 Code Connect에서 디자인 값, 텍스트, 상태, 아이콘, 디자인 시스템 컴포넌트 후보를 식별한다.
2. Code Connect로 식별한 디자인 시스템 컴포넌트는 Storybook MCP(`storybook-mcp`)에서 실제 props, variant, children 구조, Compound 조립, event/ref 패턴을 확인한 뒤 구현한다.
3. Storybook MCP(`storybook-mcp`)에서 확인되지 않은 prop, variant, size, appearance 값은 사용하지 않는다.
4. 동일 디자인 시스템 컴포넌트를 여러 번 사용할 경우 Storybook MCP(`storybook-mcp`) 조회 결과를 캐시해 재사용한다.
5. 디자인 시스템 컴포넌트로 표현하기 어려운 영역만 HTML + module.scss로 직접 구현한다.

## Figma 분석 흐름

- Figma MCP의 `get_metadata`와 `get_design_context`로 노드 구조, 텍스트, 컴포넌트 인스턴스, variant/state, style/token 정보를 파악한다.
- 가능하면 Figma MCP의 `get_screenshot`으로 원본 스크린샷을 확보해 최종 검증 기준으로 사용한다.
- `<CodeConnectSnippet>`은 최종 구현 코드가 아니라 디자인 시스템 컴포넌트 후보와 Figma 값 추출용 힌트로 사용한다.
- `<CodeConnectSnippet>` 밖의 wrapper/layout 영역은 Figma metadata와 screenshot을 기준으로 보완한다.
- Storybook MCP(`storybook-mcp`) 조회 로그에는 최소한 `컴포넌트명`, `조회 이유`, `참조한 Story/문서 title`, `확인한 props/패턴`을 남긴다.

## import 규칙

- 디자인 시스템 컴포넌트는 `sales-frontend-design-system` 에서 import한다.
- 시스템 아이콘은 `sales-frontend-assets` 에서 import한다.
- Code Connect snippet의 import가 local-server에서 해석 가능한 배포 패키지라면 그대로 사용한다.
- Code Connect snippet의 import가 앱 내부 alias나 미배포 상대경로라면 Storybook MCP(`storybook-mcp`) 문서의 배포 패키지 import로 보정한다.
- CSS Module className은 `classnames/bind` 패턴으로 적용한다.
- 문자열 className 직접 전달은 사용하지 않는다.

## 특수 패턴 처리

### PLACEHOLDER 아이콘

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

```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')} />;
```

### 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`)로 확인한 뒤 작성한다.

## SCSS 작성 규칙

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

- `__generated__.module.scss` 상단에는 위 `@use`를 선언한다.
- 추가 `@use`는 이 문서에 없는 토큰/믹스인이 꼭 필요할 때만 사용한다.
- Figma auto-layout은 `display: flex`, `flex-direction`, `align-items`, `justify-content`, `gap`으로 변환한다.
- `<CodeConnectSnippet>` 밖의 Tailwind class가 제공되면 그대로 쓰지 말고 SCSS module로 변환한다.
- 반응형 정보가 Figma에 있거나 화면 특성상 필요한 경우 `@include media(tablet|pc|pc-wide)`를 사용한다.
- 디자인 시스템 컴포넌트 내부 스타일을 무리하게 override하지 않는다. 필요한 경우 wrapper spacing만 조정한다.
- SCSS에서 `padding(xlarge)`, `margin(card)`, `radius-basic(medium)` 같은 토큰 함수나 CSS 변수 기반 값을 Sass 산술식으로 직접 계산하지 않는다. 배수 계산이 필요하면 `calc(#{padding(medium)} * 12)` 형태의 CSS calc로 옮긴다.

## 디자인 토큰 매핑

### 색상

- Figma `Surface/*` 변수는 `colors(surface-*)` 계열로 변환한다.
- Figma `Text/*` 변수는 `colors(text-*)` 계열로 변환한다.
- Figma `Border/*` 변수는 `colors(border-*)` 계열로 변환한다.
- Figma `Background/white`, `Background/neutral`, `Background/dimmed` 는 각각 `colors(background-100)`, `colors(background-200)`, `colors(background-dimmed)` 로 변환한다.

### 간격, 라디우스, 그림자

- Figma `Padding/*` 변수는 `padding(*)` 함수로 변환한다.
- Figma `Margin/*` 변수는 `margin(*)` 함수로 변환한다.
- Figma `Corner/*` 변수는 `radius-basic(*)` 함수로 변환한다.
- Figma `Shadow/*` 변수는 `shadow(*)` 함수로 변환한다.

### 타이포그래피

- Figma `Typography/title1` ~ `Typography/title5` 는 `@include apply-typography(title1)` ~ `title5` 로 변환한다.
- Figma `Typography/subtitle1` ~ `Typography/subtitle3` 는 `@include apply-typography(subtitle1)` ~ `subtitle3` 로 변환한다.
- Figma `Typography/body1` ~ `Typography/body4` 는 `@include apply-typography(body1)` ~ `body4` 로 변환한다.
- Figma `Typography/caption`, `link_large`, `link_medium`, `link_small`, `input_large`, `input_medium`, `input_small` 도 같은 이름의 `apply-typography(*)` 토큰으로 변환한다.

## 검증

- PLACEHOLDER 문자열이 남아 있지 않은지 확인한다.
- 사용한 디자인 시스템 prop과 variant가 Code Connect 또는 Storybook MCP(`storybook-mcp`)에서 확인된 값인지 확인한다.
- 원본 screenshot과 JSX/SCSS 결과를 비교해 레이아웃, 간격, 색상, 타이포, 누락 요소를 점검한다.
- 상태성 UI 차이인지 실제 생성 누락인지 구분하고, 필요한 경우 마지막 보정 1회를 수행한다.
- 가능하면 프로젝트의 lint/typecheck 명령을 실행한다. 명령을 알 수 없거나 실행이 불가능하면 최종 응답에 미실행 사유를 남긴다.

## 최종 응답

- 최종 응답은 `gen-html-form.md` 형식을 따른다.
- `### 파일 내용 자동 저장` 섹션에는 아래 두 파일의 전체 본문을 fenced code block으로 포함한다.
- 이 섹션에는 파일 헤더와 code block 외의 설명 문장이나 추가 bullet을 넣지 않는다.

````md
### 파일 내용 자동 저장

- __generated__.stories.tsx:

```tsx
// story 파일 전체 내용
```

- __generated__.module.scss:

```scss
// scss 파일 전체 내용
```
````
