목적
F1 단일 adapter(lib/api/adapters/cody-match.ts)의 mock → real 교체 절차를 문서화하고, 구현 전에 schema/mapping 불일치를 검증하는 체크리스트 . 본 이슈는 구현이 아니라 F1 확정·F2-F6 진행 중 발견된 gap을 정리 하고, ② analyze 확장(6/15)·④⑤ CodyMatchService S2(6/30) trigger 시 협의 없이 진행하지 않을 교체 규칙 을 명시한다.
범위
대상: packages/web/lib/api/adapters/cody-match.ts (F1이 유일하게 생성하는 단일 adapter)
검증: mock fixture ↔ cody-match-stage2 §2·§7.1 schema 일치성, 타입 mirror 누락, 매핑 규칙 간극
trigger:
②분석 화면(F3): analyze endpoint 호출 시 CodyAnalysis + AnalysisQuality 반환 계약 재확인
④⑤추천 화면(F5·F6): CodyMatchService S2 → ④Recommended 레이어 호출 시 ShopperPreference → preference_variant 매핑 검증
생성물: gap 문서 1개(체크리스트 형태) + 별도 구현 없음
화면 & 의존 지점
② Analysis (F3) ─ analyze endpoint 호출
├─ Input: raw image
└─ Output: CodyAnalysis {style, items, style_formula}
+ AnalysisQuality (FE mock state — backend 없음)
④ Recommended (F5) ─ CodyMatchService.match() 호출 (6/30)
├─ Input: CodyAnalysis + ShopperPreference
└─ Output: CodyMatchResult {per_role:[CandidateSKU]}
⑤ Item Detail (F6) ─ catalog_items.affiliate_url 조회 (join)
└─ Output: CandidateSKU + affiliate_url (catalog_items 출처)
Acceptance Criteria
1. TS 타입 mirror — cody-match-stage2 §2.2 전 필드 누락 검증
CandidateSKU fixture가 다음 전부 포함:
sku_signature_hash (PK)
brand, product, color, category ('top'|'bottom'|'footwear'|'outerwear'|'accessory')
price_krw, primary_image_url, product_url, source_domain
retailer_scope ('kr'|'global')
confidence (0.0-1.0, per-SKU 매칭 점수)
reason (토큰 매칭 설명)
relaxation_level ('S1'|'S2'|'S3'|'S4')
image_verification ('og_verified'|'og_missing'|'hyperbrowser_fallback')
affiliate_url은 CandidateSKU에 없음 — catalog_items(§7.1) 소속. ⑤에서 join으로 hydrate 확인
CodyMatchResult fixture:
raw_post_id, preference_variant, matched_at
per_role: Record<string, CandidateSKU[]> (role key는 카테고리 dedup)
coverage: Record<string, number> (per-role 후보 개수)
relaxation_summary: Record<string, string> (S3/S4 사유)
cost_usd, cache_hit
2. CodyAnalysis 타입 — mock vs stage2 §2.1 계약
3. ShopperPreference 매핑 — 4가지 gap 검증
3a. Budget UI bucket → preference_variant tier 매핑
3b. Fit (클라이언트 전용) — ShopperPreference에서 제외 확인
3c. core_combination / substitute_axis — 선택적 확장 AC
3d. 쇼핑몰 체크 → retailer_scope + preferred_retailers 매핑
4. 단일 adapter 격리 — F1 import seam 검증
5. mock fixture — full §2.2 형태 & spike→production deltas
6. 실패상태 소유권 — 각 화면이 자기 gap 소유 확인
7. VTON 분리 — zero import 검증
8. 경로 표준 — CANONICAL SPEC 路 정확성
9. Contract 출처 명시 & 의존성 맵
10. 페르소나 & 제약사항
핵심 파일
파일
역할
상태
packages/web/lib/api/adapters/cody-match.ts
단일 adapter (타입+entry fn)
F1이 생성
packages/web/lib/api/adapters/cody-match-mock.ts
mock fixture
F1이 생성
packages/web/lib/stores/codyStore.ts
flow store (ShopperPreference state)
F2 생성
packages/web/app/cody/page.tsx
① Upload
F2 생성
packages/web/app/cody/analysis/page.tsx
② Analysis
F3 생성
packages/web/app/cody/conditions/page.tsx
③ Conditions
F4 생성
packages/web/app/cody/recommended/page.tsx
④ Recommended
F5 생성
packages/web/app/cody/item/[skuHash]/page.tsx
⑤ Item Detail
F6 생성
mock·real 경계 (contract 출처)
Mock fixture 기준 (codyStore mock)
// cody-match-mock.ts — F1이 생성, 전체 계약 반영
type CodyAnalysis = {
style : { mood , season , color_palette , silhouette } ;
items : [ { category , color , fit , role , importance } ] ; // §2.1 소비
style_formula : {
must_keep : string [ ] ; // mvp-scope §3
replaceable : string [ ] ; // mvp-scope §3
core_combination : string ?; // stage2 §2.1 (optional, F3 확장)
substitute_axis : string ?[ ] ; // stage2 §2.1 (optional, F3 확장)
} ;
} ;
// ② analyze endpoint → CodyAnalysis + AnalysisQuality (FE mock only)
type AnalysisQuality = {
confidence : number ; // 분석 품질 배지(0.2-1.0)
// backend cody_analysis에 없음 — FE mock state
} ;
type ShopperPreference = {
budget_krw : number ; // 0 = unbounded
retailer_scope : 'kr' | 'global' | 'both' ;
country : string ;
gender : 'male' | 'female' | 'unisex' ;
excluded_brands : string [ ] ;
preferred_retailers : string [ ] ; // soft hint
// fit은 없음 — ClientOnlyFitPreference로 별도 관리
} ;
type CandidateSKU = {
sku_signature_hash : string ;
brand : string ;
product : string ;
color : string | null ;
category : 'top' | 'bottom' | 'footwear' | 'outerwear' | 'accessory' ;
price_krw : number ;
primary_image_url : string ;
product_url : string ;
source_domain : string ;
retailer_scope : 'kr' | 'global' ;
confidence : number ; // 0.0-1.0, 매칭 점수
reason : string ;
relaxation_level : 'S1' | 'S2' | 'S3' | 'S4' ;
image_verification : 'og_verified' | 'og_missing' | 'hyperbrowser_fallback' ;
// affiliate_url은 없음 — catalog_items(§7.1)에서 join
} ;
type CodyMatchResult = {
raw_post_id : UUID ;
preference_variant : string ; // "budget-500k"|"authentic"|"custom:..."
matched_at : Date ;
per_role : Record < string , CandidateSKU [ ] > ;
coverage : Record < string , number > ;
relaxation_summary : Record < string , string > ;
cost_usd : number ;
cache_hit : boolean ;
} ;
Real gateway (trigger: 6/15 ②분석 확장, 6/30 ④⑤ S2 go-live)
②분석: analyze endpoint 응답 = CodyAnalysis + AnalysisQuality (backend → FE, quality는 FE mock 유지)
trigger: cody-engine API 문서 확인 시점
gap: core_combination / substitute_axis 실제 생성 여부 (F3 구현 단계 협의)
④⑤추천: CodyMatchService.match(preference_variant) 호출
trigger: ai-server CodyMatchService gRPC 준비 (cody-match-stage2 §9.1 scheduler)
boundary: ShopperPreference 매핑(3a-3d) 결정 후 → real entry point
affiliate_url: catalog_items 테이블 join (§7.1) — ④④에서 다음 tier 카드 조회 시 포함
의존성
F1: cody-match.ts (단일 adapter) — F7의 검증 대상
F2: codyStore (ShopperPreference 상태) — adapter input 제공
F3: ② analyze endpoint 확장(core_combination/substitute_axis, AnalysisQuality)
F5: ④ CodyMatchService S2 호출 (preference_variant 매핑)
F6: ⑤ affiliate_url hydrate (catalog_items join)
F8: 통합 실패상태 검증 (F2-F6의 gap들)
제약·주의
구현 금지
F7은 구현 이슈가 아니다. 모든 AC는 "~를 검증한다", "~가 있다", "~를 확인한다" 스타일 (existence check, not creation).
adapter 파일 생성/수정 불가 (F1 담당)
화면 컴포넌트 수정 불가 (F2-F6 담당)
Adapter seam 규칙
cody-match.ts: types + entry function 한 파일에만
F3/F5/F6: 이 파일에서만 import (useCodyMatch hook, CodyEngineAdapter 등 금지)
버킷 gap 미처리
20만 UI bucket의 매핑이 미정:
custom preference(budget_krw=200_000 + hash) 선택 vs snap-to-tier 선택
결정 전까지 checkbox 미사용 권장 (모호성 회피)
이 체크의 통과 기준: "매핑 규칙 문서화" (결정값 자체는 불필요)
Persona owner = raf / 6/11
본 F7의 구현 AC에는 persona 미포함
단, wireframes ③의 Primary(Aspirational) 기준만으로 진행 (확정 후 조정)
VTON 무관
cody 코드 어디서도 vton store/component/API import 금지 (smoke test로 검증)
참조
cody-match-stage2.md (§2.1 ShopperPreference, §2.2 CanyMatchResult, §4.5 spike→prod, §6.2 ranking, §7 schema)
mvp-scope.md (§3 CodyAnalysis schema, §2 5화면, §4 비기능)
wireframes.md (③Conditions 조건들, ④Recommended 룩 세트 구조, ⑤Item Detail 아이템)
CONTEXT.md (Cody 용어 정의: Composition Variant ≠ Preference Variant, ShopperPreference ≠ fit, AnalysisQuality FE-only)
codyStore.ts (ShopperPreference state 형태) — F2 구현 시 F7 매핑과 맞춤 재확인
확인 항목 (deploy 직전)
목적
F1 단일 adapter(
lib/api/adapters/cody-match.ts)의 mock → real 교체 절차를 문서화하고, 구현 전에 schema/mapping 불일치를 검증하는 체크리스트. 본 이슈는 구현이 아니라 F1 확정·F2-F6 진행 중 발견된 gap을 정리 하고, ② analyze 확장(6/15)·④⑤ CodyMatchService S2(6/30) trigger 시 협의 없이 진행하지 않을 교체 규칙을 명시한다.범위
packages/web/lib/api/adapters/cody-match.ts(F1이 유일하게 생성하는 단일 adapter)화면 & 의존 지점
Acceptance Criteria
1. TS 타입 mirror — cody-match-stage2 §2.2 전 필드 누락 검증
CandidateSKUfixture가 다음 전부 포함:sku_signature_hash(PK)brand,product,color,category('top'|'bottom'|'footwear'|'outerwear'|'accessory')price_krw,primary_image_url,product_url,source_domainretailer_scope('kr'|'global')confidence(0.0-1.0, per-SKU 매칭 점수)reason(토큰 매칭 설명)relaxation_level('S1'|'S2'|'S3'|'S4')image_verification('og_verified'|'og_missing'|'hyperbrowser_fallback')CodyMatchResultfixture:raw_post_id,preference_variant,matched_atper_role: Record<string, CandidateSKU[]>(role key는 카테고리 dedup)coverage: Record<string, number>(per-role 후보 개수)relaxation_summary: Record<string, string>(S3/S4 사유)cost_usd,cache_hit2. CodyAnalysis 타입 — mock vs stage2 §2.1 계약
style_formula가 다음 포함:must_keep: string[](core identity tokens)replaceable: string[](swappable axes)core_combination: string(optional 확장, mvp-scope §3엔 없으나 §2.1 소비)substitute_axis: string[](optional 확장, stage2만 정의)3. ShopperPreference 매핑 — 4가지 gap 검증
3a. Budget UI bucket → preference_variant tier 매핑
retailer_scope='both'수반 — gap 3d 참조)budget_krw=200_000+custom:<hash>(§7.2 allows custom)3b. Fit (클라이언트 전용) — ShopperPreference에서 제외 확인
ShopperPreferencefit 필드 없음 (§2.1 명시)ClientOnlyFitPreference타입fitPreference: 'over'|'slim'|'any'별도 상태3c. core_combination / substitute_axis — 선택적 확장 AC
core_combinationoptional (null 허용, ② 분석 v1에서 미생성)substitute_axisoptional (null 허용, ② 분석 확장 시 생성)3d. 쇼핑몰 체크 → retailer_scope + preferred_retailers 매핑
retailer_scope: 'kr'|'global'|'both'preferred_retailers: string[](soft hint, slugs per §4.3: musinsa/29cm/wconcept)retailer_scope='kr',preferred_retailers=['musinsa']retailer_scope='kr',preferred_retailers=['musinsa','29cm']retailer_scope='kr',preferred_retailers=['musinsa','29cm','wconcept']retailer_scope='kr'(default, preferred_retailers=[])retailer_scope='both'플립4. 단일 adapter 격리 — F1 import seam 검증
packages/web/lib/api/adapters/cody-match.ts만 존재packages/web/lib/components/cody/*화면들이 이 파일에서만 importcodyAnalysisAdapter.tsrecommended/adapter.tsuseCodyMatch.tsCodyEngineAdaptercodyStore.ts내 직접 adapter 로직 (store는 타입만, seam은 adapter)5. mock fixture — full §2.2 형태 & spike→production deltas
CodyMatchResult예제가 complete per_role set 포함:6. 실패상태 소유권 — 각 화면이 자기 gap 소유 확인
7. VTON 분리 — zero import 검증
packages/web/app/cody/*코드 grep:import.*vton/VtonModal/vtonStoreimport.*api/v1/vton8. 경로 표준 — CANONICAL SPEC 路 정확성
app/cody/,lib/components/cody/*)lib/api/adapters/cody-match.ts+cody-match-mock.ts/recreate,app/request,app/(request),app/(consumer),app/cody/screens,app/cody/detail9. Contract 출처 명시 & 의존성 맵
10. 페르소나 & 제약사항
핵심 파일
packages/web/lib/api/adapters/cody-match.tspackages/web/lib/api/adapters/cody-match-mock.tspackages/web/lib/stores/codyStore.tspackages/web/app/cody/page.tsxpackages/web/app/cody/analysis/page.tsxpackages/web/app/cody/conditions/page.tsxpackages/web/app/cody/recommended/page.tsxpackages/web/app/cody/item/[skuHash]/page.tsxmock·real 경계 (contract 출처)
Mock fixture 기준 (codyStore mock)
Real gateway (trigger: 6/15 ②분석 확장, 6/30 ④⑤ S2 go-live)
②분석: analyze endpoint 응답 = CodyAnalysis + AnalysisQuality (backend → FE, quality는 FE mock 유지)
④⑤추천: CodyMatchService.match(preference_variant) 호출
의존성
cody-match.ts(단일 adapter) — F7의 검증 대상제약·주의
구현 금지
Adapter seam 규칙
cody-match.ts: types + entry function 한 파일에만버킷 gap 미처리
budget_krw=200_000+ hash) 선택 vs snap-to-tier 선택Persona owner = raf / 6/11
VTON 무관
참조
확인 항목 (deploy 직전)