Environment Setup

Running the merch app locally

Prerequisites

  • Node.js 22 LTS
  • PostgreSQL running with DATABASE_URL set
  • AWS credentials for S3 access
  • Stripe test keys
  • SendGrid API key (for email)

Quick Start

The merch UI is served by zooly-app under /merch, and merch admin under /admin/merch (the former apps/zooly-merch/ and apps/zooly-merch-admin/ Vite wrappers have been removed):

# Merch UI, merch admin, and backend API
cd apps/zooly-app && npm run dev     # Port 3004

Visit http://localhost:3004/merch/teststore/lexnour to see the test campaign.

Merch admin (campaign builder) is http://localhost:3004/admin/merch. For the Benchmark tab, open http://localhost:3004/admin/merch/benchmark (admin login required). See Image Generation Benchmark.

Seed Data

The merch app requires campaign/product data in the database. Run the seed script:

DATABASE_URL="postgresql://postgres:admin@localhost:5432/zoolylocal" \
  npx tsx packages/db/src/seed/merch-seed.ts

This creates 3 test campaigns:

CampaignURLProducts
Lexnour/teststore/lexnourT-Shirt ($69), Hoodie ($109)
LAS VEGAS ACES/Las%20Vegas%20Aces/las-vegas-acesTeam Tee ($45), Pro Hoodie ($85), Championship Plaque ($59)
Plaque/plaque/plaqueT-Shirt ($69), Hoodie ($109), Plaque ($39)

Environment Variables

Backend (zooly-app)

Set in apps/zooly-app/.env.local:

VariablePurpose
ALLOWED_DOMAINS_CORSComma-separated allowed CORS origins for other frontends. The merch UI and merch admin are same-origin with the API
STRIPE_SECRET_KEYStripe server key (sk_test_...)
STRIPE_PUBLISHABLE_KEYStripe publishable key (pk_test_...)
SENDGRID_API_KEYSendGrid email delivery
NEXT_PUBLIC_UI_HOSTMerch experience host for email links, without a path (email code appends /merch/...; use http://localhost:3004 locally)
SUPPORT_EMAIL_ADDRESSESComma-separated; first used as "from" address
MERCH_MOCKUP_MODEcomposite (default) or ai-tryon
FAL_KEYfal.ai API key for opt-in BRIA RMBG 2.0 background removal, the Krea 3 image model, and legacy generation paths
AWS_ACCESS_KEY_IDS3 access
AWS_SECRET_ACCESS_KEYS3 access
AWS_REGIONS3 region
AWS_BUCKET_NAMES3 bucket
DATABASE_URLPostgreSQL connection

Deployment

Production: merch.zooly.ai reverse proxies to app.zooly.ai/merch.

Manual Verification Walkthrough

  1. Campaign list: http://localhost:3004/merch shows 3 campaign cards
  2. Landing: http://localhost:3004/merch/teststore/lexnour shows hero, CTAs, legal footer
  3. Camera: Click "Take a Selfie" for camera capture flow
  4. Upload: Click "Upload Photo" for file upload flow
  5. Product select: Grid of products after photo review
  6. Size: 3-column size grid with auto-navigate
  7. Create (/create): Logarithmic progress + email capture + carousel during generation; then art selection (if multiple candidates) and cart view on the same URL; reselfie via overlay; BUY from art adds to cart on-page, BUY from cart continues to shipping
  8. Shipping: Address form with country dropdowns
  9. Payment: Stripe PaymentElement (test card: 4242 4242 4242 4242)
  10. Confirm: PAID badge, save/share, SHOP AGAIN

Troubleshooting

IssueFix
CORS errorsMerch UI and merch admin are same-origin with the API. Add an origin to ALLOWED_DOMAINS_CORS only for a different frontend that calls zooly-app
Images not loadingS3 assets from seed don't exist locally; expected behavior
Stripe errorsEnsure STRIPE_SECRET_KEY and STRIPE_PUBLISHABLE_KEY are set
Emails not sendingCheck SENDGRID_API_KEY, SUPPORT_EMAIL_ADDRESSES, NEXT_PUBLIC_UI_HOST
Camera not workingHTTPS required for getUserMedia in most browsers; use localhost or ngrok