Case study · Catalog Digital · 2025–2026
Building Catalog's AI stylist: virtual try-on that fails safely
Catalog is an AI fashion app where shoppers see outfits on their own photo. Working with Catalog Digital's founders, I built the try-on pipeline and a catalog that stocks itself. The hard part wasn't the AI call. It was making every step safe to retry, cheap to run, and honest when something goes wrong.
Step 1: check the selfie
Claude Haiku vision reads each selfie and returns JSON: is the face clear, is there exactly one person, is it a real photo, and, as a soft signal only, is it full body, with a friendly reason for the shopper. The app rejects a photo that fails any of the first three. If the check itself errors, the upload goes through, so an outage never blocks a shopper.
Step 2: render the outfit
Seedance 2.0 on Fal renders a 9:16, 720p clip from one face and up to nine product packshots. Every image is first copied into the project's own storage, with its file type checked from the bytes and a 15 MB cap. Packshots go in as images only when they contain no person. Otherwise the product is described in the prompt, and an identity lock keeps the face coming from the selfie only.
Step 3: a fallback that can't loop
Results come back by webhook, not polling. When the provider rejects a Seedance render on content policy or moderation, the job goes back to pending and re-runs once on Google's Gemini model. The fallback only triggers from Seedance renders, and it clears the request id, so the same callback can never fire it twice.
Making it observable
- Each job lives in one row: pending, generating, then done or failed.
- The render function and the webhook both ignore repeat calls.
- Every step is written to an event log and shown on an admin timeline.
- A job stuck for 20 minutes shows as failed instead of spinning forever.
A catalog that stocks itself
- Shopper searches are grouped and ranked, with extra weight on searches that returned nothing.
- Claude Haiku sorts the search terms into real ones and junk.
- Claude Sonnet expands longer, scenario-style searches into product queries.
- Google Shopping results come in, duplicates are skipped by URL, and new products start inactive.
- Claude tags each product with occasions.
- A product goes live only once it has an image and occasion tags.
Cost has guardrails too: a monthly search budget, an off switch, at most three search targets per run, and a cost log for every AI call.
The Shopify portal
Brands connect their store with Shopify login, protected by a signed state token. Products sync over GraphQL, 50 per page and up to 1,000 per call, and re-running a sync is safe. The portal onboarded four brands.
Tests
CI runs type checks, Vitest unit tests and Playwright smoke tests, including tests for which render model a job routes to.
retries are a feature, not an accident
Stack
- Supabase Edge Functions
- Deno
- TypeScript
- Claude Haiku
- Claude Sonnet
- Seedance 2.0
- Gemini
- Fal
- Shopify GraphQL
- Remix
- Flutter
Need an AI feature that has to be right?
I'm available now for full-time remote roles and select AI builds, with 9am–1pm ET overlap. Email maikap.samir@gmail.com or see my work. Code walkthrough on request.