widgetbook-wiring
구현한 화면을 Widgetbook과 화면 비교 테스트에 등록할 때 사용합니다. 상태별 미리보기, Figma 연결과 스냅샷을 구성해 화면을 확인하고 변경 전후를 비교할 수 있게 합니다.
한마디로#
상태별 미리보기, Figma 연결과 스냅샷을 구성해 화면을 확인하고 변경 전후를 비교할 수 있게 합니다.
무엇을·언제#
- 무엇을: use_case 생성 → 상태 Knob 배선 → Figma 결합(designLink) → 골든 스냅샷 생성 → Figma 대조용 캡처 → 경계 확인.
- 언제:
/cc-blueprint:buildStep 4 (자동), 또는 기존 화면 소급 등재 시 단독 호출. - 좋은 점: 이 단계를 건너뛴 화면은 한 제품의 실측에서 100개 중 82개가 "Knob 이 장식"이었습니다 — 배선 순서를 고정해 그 사고를 구조적으로 막습니다.
규약 SoT (재정의 금지)#
| 판단 | SoT |
|---|---|
use_case 소유 위치·1 Page = 1 use_case·Knob 규약·this.bloc 주입 |
cc-flutter:widgetbook-conventions |
@UseCase(name:)·designLink·레지스트리 결합 |
cc-flutter:figma-widgetbook-alignment |
| 골든 테스트 작성·승인 절차 | cc-flutter:golden-test-guide |
| Figma 대조용 캡처의 모양 · 비교 규칙 | cc-pixel-loop:visual-verify (§1 정규화 · §3 렌더) |
이 스킬이 고정하는 것은 순서·완료 조건·경계뿐이다.
배선 절차#
1. use_case 생성 — feature 패키지 소유(조립 앱은 sink), 섹션당 1건.
@UseCase(name:) = Figma 섹션 이름과 문자 동일 · path 는 `[Surface]/Feature` 표기.
2. 상태 Knob — 시나리오 enum 을 dropdown 단일 Knob 으로(`cc-flutter:widgetbook-conventions` §3-1).
값마다 시안의 상태 이름(Default · Loading · Empty · Error · 그 섹션이 그린 추가 상태 — 대응표
`cc-flutter:figma-widgetbook-alignment` §2-1)을 들고, 그 상태를 그리는 `bloc()` 이 mock 시나리오
(build 의 mock/ 데이터)를 쓴다. Knob 의 한국어 라벨은 키가 아니다 — 문자열 목록으로 만들지 않는다.
⛔ 함정 검사: Page 가 BlocSignalProvider(create:) 로 BLoC 을 자체 생성하면 주입 mock 이
가려져 Knob 이 무력화된다 — Page 의 this.bloc 선택 주입 여부를 먼저 확인하고,
아니면 build 산출물 결함으로 되돌린다 (여기서 우회 배선하지 않는다).
3. designLink — use_case 에 Figma 프레임 node URL 을 단다 (섹션 프레임, 파일 루트 아님).
레지스트리 행의 코드 칸을 `—(미구현)` → use_case 참조로 갱신한다.
4. 골든 스냅샷 — 상태 4종 × 대표 뷰포트(Mobile 필수 · Web 은 시안에 Web 프레임이 있는 화면. Tablet 프레임은 시안에 없다(figma-workflow §5 R2) — Widgetbook Viewport 애드온으로만 확인)
골든 테스트 생성 → 1회 승인(update-goldens) → `flutter test` green 확인.
4b. Figma 대조용 캡처 — 골든과 **다른 테스트**다. 장치는 visual-verify plan.json 의 `devices` 그대로
(상태 프레임의 논리 크기 · 배율 · 상태 바 · 홈 인디케이터 — 같은 프레임끼리 장치 하나), textScaler 1.0,
라이트 · 다크 테마, 움직임 정지(disableAnimations). 시나리오는 2번의 enum 그대로 —
`figmaFrames.scenario(s.captureScenario, build: (_) => XxxPage(bloc: s.bloc()))`. enum 의 `captureScenario` 는
프레임 상태의 소문자(default · loading · empty · error)라 비교의 `captureScenario` 와 같다. 캡처 테스트는
그 enum 을 import 할 수 있는 패키지(use_case 의 fixture 를 가진 패키지)의 test/ 에 둔다.
앱 루트와 같은 CoUIApp 인자(브랜드 · 서페이스 스타일 · 밀도)로 감싸고, 시안의 서체를 로드한다(loadGoldenFonts — 앱이 번들하지 않은 서체는 상자로 그려진다).
co_golden 이면 capture 모드로 찍는다 — **기준 이미지를 승인하지 않는다**(기준은 Figma 다).
co_golden 이 없는 저장소는 testWidgets + toImage 캡처(visual-verify §3).
`CO_GOLDEN_MODE=capture flutter test` 뒤 `figma_compare.py ingest` 가 plan 의 label 마다 PNG 를 찾는지 확인한다(없음 0).
5. 경계 확인 — 아래 표의 이웃 검증 계층으로 넘어갈 일을 여기서 하지 않는다.
검증 경계 — 어디까지가 이 배선인가#
| 검증 | 담당 | 이 스킬과의 관계 |
|---|---|---|
| 정적 스냅샷 회귀 (골든) | 이 스킬 (4단계) | 기준 = 코드가 승인한 이미지 — 시안과 같다는 증거가 아니다 |
| Figma 대조용 캡처 | 이 스킬 (4b단계) | 여기까지가 배선 — 캡처를 만들 뿐 비교하지 않는다 |
| Figma ↔ 렌더 대조 (완료 기준) | cc-pixel-loop:visual-verify (/cc-pixel-loop:verify) |
4b 의 캡처를 입력으로 쓴다 — 기준 = 시안. 골든과 별개 축 |
| Figma↔Widgetbook 집합 대조 (L0/L1/L2) | /cc-blueprint:sync | 배선 결과를 소비 |
| 고치며 수렴 (Figma↔렌더) | /cc-pixel-loop:loop | 같은 비교를 반복마다 — 실행 중인 앱으로도 |
| 위젯 트리 단위 자동화 회귀 | cc-marionette | 실행 중 앱 검증 |
| 앱 내부 상태 검증 | cc-mcp-toolkit | BLoC/DB 관측 |
완료 조건#
□ 섹션마다 use_case 1건 · @UseCase(name:) == 섹션명 · designLink == 프레임 node URL
□ 상태 Knob 4종이 화면을 실제로 바꾼다 (Page 자체 BLoC 생성 없음 확인)
□ 골든: 상태 4종 × 대표 뷰포트 스냅샷 존재 + flutter test green
□ 대조용 캡처: 상태 프레임 × 라이트 · 다크마다 PNG 가 나온다 (프레임 크기 · 배율 · textScaler 1.0 · 서체 로드) —
비교의 통과는 이 스킬의 완료 조건이 아니라 /cc-blueprint:build Step 5 의 것
□ 레지스트리 코드 칸 갱신 (—(미구현) 해소)