Skip to main content

Consumer app

The shopper experience lives in the (main) route group and navigates via a floating blurred pill nav (BottomNav): Home, Explore, a center Preview action, Messages, and Profile.

Getting set up

Before a try-on can work, the shopper completes a setup tunnel that also captures BIPA consent and writes the body photo.

index.tsx
path chooser

(auth)/signup

onboarding.tsx
taste + consent gate 1

fit-setup.tsx
measurements + consent gate 2

body-photo.tsx
standalone capture + consent gate 3

home.tsx

ScreenWhat it does
onboarding.tsxTaste onboarding (welcome → culture → style) with the first BIPA consent gate; writes gender/aesthetic/culture via updateProfile
fit-setup.tsx5-step fit profile: gender → height (wheel) → weight (wheel, optional) → body photo → results. runAnalysis() posts to /api/analyze-body-photos, then writes user_measurements to AsyncStorage as bare keys. 120s timeout + error alert
body-photo.tsxStandalone body-photo capture/upload with direct camera/gallery pickers (guidance modals were removed to fix a picker loop)
profile.tsxView/edit the fit profile, body photo, measurement wheels, unit toggle, logout, and Delete Account

Consent is enforced three times on the frontend and again at the backend (403 if not consented). See security.

Browsing

ScreenWhat it does
home.tsxPersonalized feed — wordmark header, hero, category pills, a two-column ProductCard grid, pull-to-refresh, and an error state with retry
catalog.tsxBrowse / search / filter grid; merges backend products with local sample data; a search modal
product/[id].tsxThe product page — color/size selectors, info tabs, similar products, and the Try It On button that opens the try-on screen

The try-on render

try-on/[productId].tsx is the core screen (and its viewport is frozen). It:

  1. Fetches the body photo from GET /api/body-photo and only proceeds if the server confirms one exists — it never reuses a cached local photo, so a previous user's photo can't leak into a render.
  2. Posts to /api/try-on (the body photo is not in the request — it is fetched server-side), then either returns a cached result immediately or polls `/api/try-on/status/{jobId}` every 3 seconds up to a 180-second timeout.
  3. Shows the DrapeRenderLoader during the wait, then a BEFORE/AFTER view, a fit score, a color re-render option, and save / share / buy actions.

Errors are bucketed into friendly copy (rate-limit, timeout, abort, generic), and the poll's AbortController is stored in a useRef and cancelled on unmount.

Saving & history

ScreenWhat it does
save-closet.tsxPost-try-on save confirmation
saved.tsxSaved items / wishlist
preview.tsxGrid of the shopper's generated renders
history.tsxTry-on history, with a pending_history_writes retry queue for offline writes
look-board.tsxA grid of saved "looks" for a product or store

Commerce & extras

ScreenWhat it does
orders.tsxConsumer order history
checkout-return.tsx (top-level)Handles the Stripe checkout return, verifying the order by session_id
scan.tsxCamera QR/barcode scanner that resolves to a product or store
sell.tsxA peer-to-peer listing flow (category / condition)
refer.tsxReferral program — code, share sheet, stats
messages.tsx / message-thread.tsxInbox and thread — currently static/mock data, no backend wiring