Skip to content

feat(cody): ⑤ Item Detail 화면 (CandidateSKU full + affiliate redirect) #631

Description

@thxforall

목적

④ Recommended 화면에서 룩 세트의 특정 아이템을 탭했을 때, 그 아이템의 상세 정보와 구매 링크를 표시하는 화면 구현. 코디 재현 엔진의 마지막 단계(P6)로, 유저가 대체 상품을 검토 후 제휴 쇼핑몰로 이동해 구매하는 지점.

범위

  • 경로: packages/web/app/cody/item/[skuHash]/page.tsx (동적 라우트, skuHash = CandidateSKU.sku_signature_hash)
  • 컴포넌트: packages/web/lib/components/cody/* (렌더링 로직)
  • 데이터: F1이 생성한 단일 adapter lib/api/adapters/cody-match.ts 에서 CandidateSKU 타입 import
  • 화면 스펙: wireframes §2 ⑤ (lo-fi)

제외 범위:

  • VTON 모달/상태 연계 (VTON은 Phase 3, 본 화면과 무관)
  • 품절·사이즈 없음·대체 상품 자동 swap (F5 책임, 여기 진입 시점엔 이미 완료)
  • affiliate 미커버 필터링 (F5 책임)

화면 스펙

레이아웃 (모바일 우선)

┌────────────────────────────┐
│ ← Recommended        ♡ 저장 │  ← ♡ 저장 = gated (비로그인 시 signup modal)
│                            │
│ ┌──────────┐               │
│ │  아이템    │  오버사이즈    │
│ │  이미지    │  울 블레이저    │
│ │  (OG verify)  브랜드 OOO    │
│ └──────────┘  가격 89,000원   │
│               유사도 88%      │
│               ●●●●○ (badge) │
│                            │
│  ── 대체 이유 ──             │
│  "원본 실루엣·뉴트럴 톤 유지,  │
│   소재·브랜드는 대체"         │
│  (CandidateSKU.reason)      │
│                            │
│  [ 무신사에서 구매하기 ↗ ]    │  ← affiliate redirect
│  [ ♡ 룩 보드에 저장 ]  gated  │
└────────────────────────────┘

필드 매핑 (CandidateSKU full schema per cody-match-stage2 §2.2)

UI 요소 출처 필드 타입 필수
아이템 이미지 primary_image_url string ✓ (OG-verified 또는 fallback)
핏 설명 cody_analysis.items[].fit (분석에서 유래, 여기서 표시) string -
카테고리+브랜드 category, brand enum/string
제품명 product string
가격 price_krw integer
유사도 배지 confidence (0.0–1.0 → 0–100% 표시) float
대체 이유 reason string
이미지 신뢰도 badge image_verification (og_verified / og_missing / hyperbrowser_fallback) enum ✓ (UI 시각적 구분)
구매 링크 product_url 또는 catalog_items.affiliate_url (phase 3+) string
쇼핑몰 이름 source_domain string ✓ (무신사 / 29CM / W컨셉 등)
지역 scope retailer_scope (kr / global) enum ✓ (global은 OG missing 위험, 시각적 표시)

미사용 필드 (이 화면에서는 쓰지 않음)

  • sku_signature_hash: URL 파라미터로만 사용 (조회 key)
  • relaxation_level: admin verify UI용, consumer 화면엔 미노출

Acceptance Criteria

  • 라우트 및 파라미터: app/cody/item/[skuHash] 동적 라우트 생성. URL 파라미터 skuHashCandidateSKU.sku_signature_hash로 인식하여 ④에서 진입할 때 정확히 매핑.

  • CandidateSKU 타입 import: lib/api/adapters/cody-match.ts에서만 타입 import. 별도 adapter 파일(codyItemAdapter.ts, useCodyMatch.ts 등) 생성 금지. F1이 생성한 단일 adapter 유일 진입.

  • 아이템 상세 정보 렌더링: primary_image_url(OG-verified), category, brand, product, price_krw, confidence(유사도%), reason(대체 이유) 모두 화면에 노출. image_verification 배지로 시각적 신뢰도 표시(og_verified 초록, og_missing 회색, hyperbrowser_fallback 노랑 등).

  • 구매하기 CTA: 쇼핑몰명(source_domain)이 버튼 텍스트에 포함 예) "[무신사]에서 구매하기". 클릭 시 affiliate redirect 패턴(SCR-VIEW-03 참조) 적용. catalog_items.affiliate_url 존재 시 우선 사용, null 시 product_url fallback. 이 fallback 로직은 F7 reconcile gap에 명시할 것 (affiliate_url은 LinkPrice Phase 3+이므로 현재 null).

  • 저장 액션 — 미가입 실패 처리 (F6 owned): 하트 버튼 클릭 시 비로그인 유저에겐 가입 모달 표시(gated). "룩 보드에 저장" 기능은 구현하지 않음 (이는 (+)Saved 화면의 별도 작업); 여기서는 가입 유도만 (세부 저장 로직은 F9의 보드 저장 기능과 연계될 때 완성).

  • 링크 끊김 실패 처리 (F6 owned): product_url 또는 affiliate_url fetch 시 4xx/5xx 발생하면, 에러 상태 표시 + "대체 상품 둘러보기" 버튼 제공 (← 버튼 클릭 시 ④로 복귀, per_role 리스트의 다음 후보 아이템 표시). 동선: 연결 오류 → 유저가 수동으로 다른 후보 선택 또는 조건 재설정.

  • ← 버튼/헤더: ④ Recommended로 복귀. 이전 화면의 추천 세트/조건 상태 유지 (browser history or query state).

  • VTON 분리 확인: app/cody/item/* 컴포넌트는 lib/components/vton, lib/stores/vtonStore, /api/v1/vton import 금지. 본 화면은 독립적으로 작동.

  • 비로그인 가능: 조회/구매 redirect는 로그인 불필요. 저장만 gated. mvp-scope §4 로그인 정책 준수.

핵심 파일 경로

용도 경로
페이지 packages/web/app/cody/item/[skuHash]/page.tsx
컴포넌트 packages/web/lib/components/cody/ItemDetail.tsx (또는 여러 컴포넌트로 분할)
타입·entry packages/web/lib/api/adapters/cody-match.ts (F1이 생성, import만)
flow store packages/web/lib/stores/codyStore.ts (F1이 생성)

mock·real 경계

Contract 출처: cody-match-stage2 §2.2 (CodyMatchResult.per_role[role][]) + §7.1 (catalog_items 스키마)

Stage 2 adapter 계약

  • Input: ④에서 선택한 아이템의 sku_signature_hash (URL 파라미터)
  • Output: F1이 생성한 codyStore 또는 /api/* endpoint에서 per_role 맵 조회, 해당 SKU의 CandidateSKU object 추출
  • Mock strategy: F1이 fixture 생성 시 full CandidateSKU 필드(sku_signature_hash, brand, product, color, category, price_krw, primary_image_url, product_url, source_domain, retailer_scope, confidence, reason, relaxation_level, image_verification) 모두 포함. 테스트 fix엔 real schema 100% mirror.

affiliate_url sourcing — F7 reconcile gap

  • 현재 (Phase 1): catalog_items.affiliate_url is nullable, LinkPrice 미통합 (Phase 3+). 따라서 redirect는 product_url로 진행.
  • 구현: product_url OR (catalog_items.affiliate_url if exists) 우선순위. mock에서는 affiliate_url null 가정, real에선 값 있을 때 우선 사용.
  • F7 체크리스트 항목: affiliate_url mock→real 재조정 확인 (구현 아님, 검증만).

의존성

  • F5 (Recommended 화면): ⑤로 진입하는 상단 앞 버튼의 출처. per_role 맵과 추천 세트 상태 공유 (codyStore via F1).
  • F1 (단일 adapter): lib/api/adapters/cody-match.ts 타입 import 전용. 새 adapter 파일 절대 금지.
  • auth (gated save): 저장 모달은 기존 signup 플로우 재사용.
  • catalog_items DB (§7.1): primary_image_url, affiliate_url, OG metadata (og_title, og_description, image_verification) 조회 의존. 백엔드는 이미 구축(catalog-acquisition scope).

제약·주의

  • 경로 규칙 (절대): app/cody/item/[skuHash]/ 외 경로 절대 금지 (금지: /recreate, /app/(request), /app/cody/screens, /app/cody/detail 등).

  • adapter 단일성: F1이 생성하는 cody-match.ts 1개만. F6는 import만. codyItemAdapter.ts, useCodyMatch, CodyEngineAdapter 등 신규 adapter 파일 생성 금지.

  • 타입 mirror — 누락 금지: CandidateSKU full 필드(sku_signature_hash, brand, product, color, category, price_krw, primary_image_url, product_url, source_domain, retailer_scope, confidence, reason, relaxation_level, image_verification) 를 fixture·mock·schema에 100% 포함. 발명 또는 누락 시 F7 reconcile 실패.

  • 실패 상태 소유 (F6만):

    • 링크 끊김 (product_url/affiliate_url 접근 불가) → 대체 후보 안내
    • 미가입 + 저장 시도 → signup modal (gated)
    • 품절·사이즈·affiliate 미커버 (F5 책임, F6에서 처리 안 함)
  • confidence 용법: CandidateSKU.confidence (0–1 float → 0–100% 유사도 배지). AnalysisQuality (②의 분석 품질 배지)와 무관. 혼동 금지.

  • retailer_scope 명시: 상품이 global (kr 아님)이면 이미지 신뢰도 낮음 표시 (og_missing 가능성 높음). UI에서 차이 있음.

  • VTON 분리: import 금지. app/cody/* smoke test는 vton state/modal 미의존 확인.

  • 비로그인 정책: 조회/구매는 로그인 불필요 (mvp-scope §4). 저장만 gated.

  • persona (owner=raf, 6/11 확정): AC엔 제외. §6 narrative(지수)는 wireframes §5 참조. Primary 페르소나 확정 후 강조점 조정 가능.

참조

  • wireframes.md §2 ⑤ — lo-fi 화면 스펙 (레이아웃, 필드, 상태)
  • wireframes.md §4 — 실패 상태 카탈로그 (링크 끊김·미가입 저장 재확인)
  • wireframes.md §5 — 대표 narrative(지수) — P6 구매 → 저장 플로우
  • mvp-scope.md §2 — 화면 목록 및 API 의존 (affiliate redirect)
  • mvp-scope.md §3 — 데이터 스키마 (cody_analysis, 다만 여기선 CandidateSKU 위주)
  • mvp-scope.md §4 — 로그인 정책 (분석·추천·조회 비로그인, 저장만 gated)
  • mvp-scope.md §5 명시적 제외 — VTON(Phase 3), 자체 checkout 없음 (100% affiliate)
  • cody-match-stage2.md §2.1 — ShopperPreference schema (F6 non-input, context only)
  • cody-match-stage2.md §2.2 — CandidateSKU full schema, per_role dict, confidence 정의
  • cody-match-stage2.md §7.1 — catalog_items 테이블 (affiliate_url, primary_image_url, image_verification, source_domain)
  • CONTEXT.md Cody glossary — CandidateSKU, AnalysisQuality, ClientOnlyFit, ShopperPreference 정의 (confidence 혼동 주의)
  • user-scenarios.md §2 P6 — 구매 링크 + 저장 / 공유 단계
  • user-scenarios.md §4 — 실패 루프: 링크 끊김 대처, 미가입 저장 모달
  • user-scenarios.md §6 narrative — 지수의 블레이저 탭 → 무신사 구매(affiliate) 동선

Metadata

Metadata

Assignees

No one assigned

    Labels

    codyCody Recreation Engine MVPenhancementNew feature or requestfrontend프론트엔드

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions