$npx -y skills add kwakseongjae/oh-my-design --skill omd-migrate단일 brand의 references/<id>/DESIGN.md를 Apple-tier 깊이로 풀 마이그레이션. 9 quality gate 전부 통과 — §4 canonical schema + ≥2 surface live inspect + Tier 2 cross-check + .verification.md conflict matrix + 검증된 §10-15 philosophy + footer + tests + visual smoke. 'X 마이그레이션', 'X apple 깊이로', 'X 풀 검증',
| 1 | # omd:migrate — Single-brand Apple-tier deep migration |
| 2 | |
| 3 | `spec/migration-checklist.md`의 9 quality gate를 한 brand에 대해 모두 충족시킨다. **현재 67 brand 중 1개(apple)만 통과 상태.** 이 스킬은 나머지 66개를 하나씩 끌어올리는 도구. |
| 4 | |
| 5 | 다음 패턴 트리거: |
| 6 | - `omd:migrate stripe` |
| 7 | - `stripe 마이그레이션` |
| 8 | - `stripe apple 깊이로 풀 검증` |
| 9 | - `stripe 풀 마이그레이션` |
| 10 | |
| 11 | 자연어 OK. 슬래시 없어도 됨. |
| 12 | |
| 13 | --- |
| 14 | |
| 15 | ## Pre-flight (자동) |
| 16 | |
| 17 | 브랜드 인자 받고: |
| 18 | |
| 19 | 1. `web/references/<id>/DESIGN.md` 존재 확인 (없으면 에러: "use omd:add-reference for new ref") |
| 20 | 2. 현재 9 gate 상태 평가: |
| 21 | ``` |
| 22 | G1 schema: [✓/✗] (grep variant blocks per category) |
| 23 | G2 ≥4 cats: [✓/✗] (count category headers) |
| 24 | G3 surfaces: [count] live inspect already done |
| 25 | G4 Tier 2: [✓/✗] refero/getdesign attempt logged |
| 26 | G5 verif.md: [✓/✗] file exists |
| 27 | G6 philo: [count verified vs illustrative] |
| 28 | G7 footer: [✓/✗] **Verified:** present |
| 29 | G8 tests: last npm test result |
| 30 | G9 smoke: not auto-checkable; ask user to verify after |
| 31 | ``` |
| 32 | 3. 사용자에게 현재 상태 + 작업할 gate 보고. `--skip-gate` flag로 일부 스킵 가능. |
| 33 | |
| 34 | --- |
| 35 | |
| 36 | ## Phase G1+G2 — §4 canonical schema audit |
| 37 | |
| 38 | 목표: `**Variant Name**` + bullet `Field: value` 형식으로 모든 컴포넌트 카테고리 정리. |
| 39 | |
| 40 | 1. `grep -c '^### \|^\*\*[A-Z]' web/references/<id>/DESIGN.md` 으로 §4 구조 파싱 |
| 41 | 2. 각 카테고리(Buttons / Inputs / Cards / Badges / Tabs / Toggles / Toasts / Dialogs / Avatars / Lists / Navigation)에 대해: |
| 42 | - 카테고리가 prose paragraph면 → schema로 변환 (사용자 컨펌 후) |
| 43 | - 카테고리에 variant block 1개뿐이면 → 라이브 inspect 데이터를 기반으로 추가 |
| 44 | 3. **최소 4 카테고리** 충족 확인 (브랜드 surface에 실제로 그 카테고리가 있을 때만) |
| 45 | 4. 각 variant block은 다음 fields 모두: |
| 46 | ``` |
| 47 | **<Variant Name>** |
| 48 | - Background: <value> |
| 49 | - Text: <value> |
| 50 | - Border: <value | none> |
| 51 | - Radius: <value> |
| 52 | - Padding: <value> |
| 53 | - Font: <size> / <weight> / <family> |
| 54 | - Use: <one-line context> |
| 55 | ``` |
| 56 | |
| 57 | #### 🚨 §4 작성 강제 규칙 (이거 어기면 builder Components 섹션이 통째로 안 나옴) |
| 58 | |
| 59 | **1줄 = 1필드.** 절대 슬래시(`/`)·콤마로 여러 필드를 한 줄에 결합하지 말 것. 파서(`extract-components`)는 `^- Field: value$` 패턴만 인식한다. |
| 60 | |
| 61 | ❌ **금지** — 슬래시 multi-field (KRDS 초기 작성에서 36 variants 중 35개가 안 보였던 케이스): |
| 62 | ``` |
| 63 | - Background: `#256EF4` / Text: `#FFFFFF` / Border: 1px solid `#256EF4` |
| 64 | ``` |
| 65 | |
| 66 | ✅ **필수** — 1필드 1불릿: |
| 67 | ``` |
| 68 | - Background: `#256EF4` |
| 69 | - Text: `#FFFFFF` |
| 70 | - Border: 1px solid `#256EF4` |
| 71 | ``` |
| 72 | |
| 73 | **예외**: `- Font: <size> / <weight> / <family>` 는 한 필드(`font`)의 정해진 sub-syntax. Background·Text·Border 등 별도 필드를 합치는 것과 다르다. |
| 74 | |
| 75 | **State variants** (Hover/Pressed/Focus/Disabled/Required/Error): 동일 variant 블록 내 별도 `- Hover:` / `- Pressed:` 불릿. 별도 `**Variant**` 블록 만들지 않는다. |
| 76 | |
| 77 | **Size scale** (xsmall/small/medium/large/xlarge): 1개 `**Variant**`에 default 사이즈만 불릿. 나머지 사이즈는 그 블록 뒤 markdown 테이블로. variant 5개로 쪼개지 않는다. |
| 78 | |
| 79 | **자가 검증 (G1+G2 통과 조건)**: |
| 80 | ```bash |
| 81 | S4=$(awk '/^## 4\./,/^## 5\./' web/references/<id>/DESIGN.md) |
| 82 | slash=$(echo "$S4" | grep -E "^- " | grep -cE " / [A-Za-z][a-z]+:") |
| 83 | [ "$slash" -gt 0 ] && echo "❌ FAIL: $slash 슬래시 multi-field 잔존" && exit 1 |
| 84 | echo "✓ canonical schema clean" |
| 85 | ``` |
| 86 | |
| 87 | 이 검사 실패 시 G1+G2 ✗ → 수정 → 재검증. footer-only fix로 우회 금지. |
| 88 | |
| 89 | **Figma 케이스 예시** (현재 G1+G2 ✗): |
| 90 | - Cards/Navigation/Distinctive가 prose → schema 변환 필요 |
| 91 | - Black Pill variant data가 Icon variant와 conflate → 분리 필요 |
| 92 | |
| 93 | --- |
| 94 | |
| 95 | ## Phase G3 — Tier 1 live inspect (≥2 surfaces) |
| 96 | |
| 97 | playwright로 brand의 **다른 컨텍스트 surface 2개 이상** navigate + evaluate: |
| 98 | |
| 99 | | Brand type | Surfaces 권장 | |
| 100 | |---|---| |
| 101 | | 마케팅 + 제품 분리 (Apple, Toss, Spotify) | marketing home + product/checkout | |
| 102 | | 컨슈머 (Airbnb, Coinbase) | home + listing/asset detail | |
| 103 | | 개발자 도구 (Stripe, Vercel, Linear) | home + docs/dashboard | |
| 104 | | 동아시아 (Kakao, Karrot) | KR locale + secondary surface | |
| 105 | | Auto luxury (BMW, Ferrari) | home + configurator (cookie banner 너머까지) | |
| 106 | |
| 107 | 각 surface에 대해: |
| 108 | 1. `mcp__playwright__browser_navigate(<url>)` |
| 109 | 2. `mcp__playwright__browser_evaluate` — `getComputedStyle` 추출 패턴 (스킬 SKILL.md 또는 omd-add-reference 참고) |
| 110 | 3. raw observations를 `web/references/<id>/.verification.md`에 append |
| 111 | |
| 112 | --- |
| 113 | |
| 114 | ## Phase G4 — Tier 2 cross-check |
| 115 | |
| 116 | **둘 다 시도** (✓는 결과가 0건이어도 시도했다는 증거): |
| 117 | |
| 118 | 1. `WebFetch https://getdesign.md/<id>` — getdesign 데이터 (대부분 directory only이지만 로그) |
| 119 | 2. **playwright** `https://styles.refero.design/?q=<brand>` (WebFetch는 SSR shell만 반환하므로 playwright 필수): |
| 120 | - search → 결과 카드 collect (`a[href^="/style/"]`) |
| 121 | - 각 결과 카드에 대해 `WebFetch /style/<uuid>` 으로 detail 추출 |
| 122 | - 한 brand에 multiple style 페이지 있으면 (Apple 4개, Airbnb 2개) 전부 수집 |
| 123 | |
| 124 | `.verification.md`에 Tier 2 raw observations append. |
| 125 | |
| 126 | --- |
| 127 | |
| 128 | ## Phase G5 — Conflict matrix → `.verification.md` |
| 129 | |
| 130 | `web/references/<id>/.verification.md` 형식 (Apple 참고): |
| 131 | |
| 132 | ```markdown |
| 133 | # <Brand> — Verification Notes (YYYY-MM-DD) |
| 134 | |
| 135 | ## Tier 1 — live DOM (playwright getComputedStyle) |
| 136 | ### Surfaces inspected |
| 137 | - <url 1> |
| 138 | - <url 2> |
| 139 | |
| 140 | ### Raw observations |
| 141 | **<Component class> — <Variant>** |
| 142 | - bg: <value> |
| 143 | - color: <v |