From 2e780f2dcd562dd172c45b1f7fbdbff3b25ebb58 Mon Sep 17 00:00:00 2001 From: gahusb Date: Tue, 28 Apr 2026 03:44:10 +0900 Subject: [PATCH] refactor(packs): TIER_LABEL SSOT + Phase 2 migration note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 코드 리뷰 후속 (I1+M2): - TIER_LABEL: PackTier → 한국어 표시명 single source of truth - PACK_ASSETS[*].name 백틱 템플릿으로 TIER_LABEL 참조 - extractPackTier if-ladder → LABEL_TO_TIER lookup (자동 derive) - 마케팅 카피(입문/프로/마스터) 변경 시 한 곳만 수정으로 mypage·music 동기화 추가 코멘트 (M1, I3): - U+00B7 middle-dot 명시 - Phase 2 PackFile 형태 마이그레이션 가이드 (files: string[] → { label, url? }[]) Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/pack-assets.ts | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/lib/pack-assets.ts b/lib/pack-assets.ts index fe6967b..ffdb726 100644 --- a/lib/pack-assets.ts +++ b/lib/pack-assets.ts @@ -5,9 +5,23 @@ export interface PackAsset { export type PackTier = 'starter' | 'pro' | 'master'; +/** + * Tier 키 → 한국어 표시명 SSOT. + * `app/services/music/page.tsx`의 TIERS와 일치 유지 필요 (현재 입문/프로/마스터). + */ +export const TIER_LABEL: Record = { + starter: '입문', + pro: '프로', + master: '마스터', +}; + +const LABEL_TO_TIER: Record = Object.fromEntries( + Object.entries(TIER_LABEL).map(([tier, label]) => [label, tier as PackTier]) +); + export const PACK_ASSETS: Record = { starter: { - name: 'AI 음악 마스터 팩 (입문)', + name: `AI 음악 마스터 팩 (${TIER_LABEL.starter})`, files: [ 'Suno 프롬프트 북 PDF (40p)', '구조 템플릿 PDF', @@ -15,7 +29,7 @@ export const PACK_ASSETS: Record = { ], }, pro: { - name: 'AI 음악 마스터 팩 (프로)', + name: `AI 음악 마스터 팩 (${TIER_LABEL.pro})`, files: [ '입문 자료 전체', 'MV 워크플로우 가이드 (Runway · Luma · Pika)', @@ -25,7 +39,7 @@ export const PACK_ASSETS: Record = { ], }, master: { - name: 'AI 음악 마스터 팩 (마스터)', + name: `AI 음악 마스터 팩 (${TIER_LABEL.master})`, files: [ '프로 자료 전체', '샘플 프로젝트 장르별 3종', @@ -38,16 +52,22 @@ export const PACK_ASSETS: Record = { /** * orders.service ("구매 신청: AI 음악 마스터 팩 · 프로") → tier key. * 매칭 안 되면 null 반환 (Music 팩 외 의뢰). + * + * NOTE: service 문자열은 U+00B7 MIDDLE DOT (·) 사용. 이 함수는 "마지막 ·" 뒤의 + * 단어를 tier 라벨로 인식. 예: "구매 신청: AI 음악 마스터 팩 · 프로" → "프로" → 'pro'. + * Phase 2에서 marketing 카피가 tier 뒤에 추가 ·를 두면 이 로직 재검토 필요. */ export function extractPackTier(service: string): PackTier | null { if (!service.startsWith('구매 신청:')) return null; - // service 예시: "구매 신청: AI 음악 마스터 팩 · 프로" - // 마지막 "·" 뒤가 tier 이름 const dotIdx = service.lastIndexOf('·'); if (dotIdx === -1) return null; const tierName = service.slice(dotIdx + 1).trim(); - if (tierName === '입문') return 'starter'; - if (tierName === '프로') return 'pro'; - if (tierName === '마스터') return 'master'; - return null; + return LABEL_TO_TIER[tierName] ?? null; } + +/** + * Phase 2 migration note: `files: string[]` 는 placeholder. Phase 2에서 NAS + * 파일 URL 도입 시 `files: { label: string; url?: string; sizeBytes?: number }[]` + * 형태로 확장 필요. mypage page.tsx 의 `{file}` → `{file.label}` + * 동시 변경. + */