프로젝트 개요
하이라이트
도메인 모델
커머스 스키마 전반을 포괄하는 프로덕션 수준 TypeScript 인터페이스
SSAUser, Product, ProductImage, Subscription, Shipment, Address, Profile, BeautyBoxCartItem까지 8개 인터페이스가 커머스 도메인을 정의합니다. nullable 전화번호, 선택 주소 라인, product image의 is_primary와 sort_order, 구독/배송 상태 enum처럼 실제 Supabase 기반 스키마가 노출할 구조를 반영했습니다.
상품 모델은 정렬된 이미지 배열, 다중 skin_types와 skin_concern, nullable 원가/소비자가 필드를 포함합니다. 데모 객체가 단순 placeholder가 아니라 production 코드로 옮기기 쉬운 구조가 되도록 설계했습니다.
데모 인프라
Supabase 인터페이스 스텁, 동기식 인증, 결정적 fixture 그래프
Supabase 클라이언트는 전체 SSAAuthClient와 generic SSAQueryBuilder<T> 인터페이스를 정의하지만 getSupabaseClient()는 데모에서 null을 반환합니다. 컴포넌트는 실제 네트워크 호출 없이도 올바른 인터페이스를 기준으로 컴파일됩니다.
useRequireAuth 훅은 DEMO_USER를 동기적으로 반환하고, demo-data.ts의 fixture 그래프는 DEMO_USER, DEMO_PROFILE, DEMO_ADDRESSES, DEMO_SUBSCRIPTIONS, DEMO_SHIPMENTS, DEMO_PRODUCTS의 관계 ID를 일관되게 연결합니다.
디자인 시스템
typed runtime hook으로 소비하는 CSS custom property 토큰
시각 언어는 --ssa-sage, --ssa-espresso, --ssa-cream, --ssa-forest 등 20개 이상의 CSS custom property로 SSA 컨텍스트 안에 묶었습니다. useTheme() 훅이 런타임에 값을 읽어 typed ThemeTokens로 반환하고 각 컴포넌트가 inline style에서 사용합니다.
브랜드 문자열을 보호하는 keepBrandTerms()와 keepBrandTermsDeep() 유틸도 함께 두었습니다. i18n은 서버 컴포넌트에서 locale별 dictionary를 읽고 client island에 props로 전달해 런타임 locale 해석을 줄였습니다.
상태 머신
피부 진단 결과가 장바구니 typed field로 이어지는 구매 흐름
피부 진단은 결과를 sessionStorage에 저장하고, SubscribeClient가 이를 읽어 buildBeautyBoxCartItem()에 전달합니다. 이후 BeautyBoxCartItem.skinType에 포함되어 localStorage와 checkout success URL까지 이어집니다.
플랜 선택은 price, numericPrice, showKit을 가진 BEAUTY_BOX_PLANS 설정으로 구동됩니다. normalizeBeautyBoxPlanId()는 legacy onetime variant까지 canonical plan ID로 보정해 페이지 간 상태 의존을 줄입니다.
이 케이스 스터디는 구현 의도와 기술 구조를 설명하고, 실제 화면에서는 상품 탐색, 피부 프로필, 장바구니, 박스 구성, 계정/주문/배송 상태까지 직접 확인할 수 있습니다. 운영 데이터와 서버 쓰기는 연결하지 않은 데모 모드입니다.
데모 보기