Environment Setup

Running the Face-app locally and seeding boards

Prerequisites

  • The monorepo installed (npm install at the root).
  • A local Postgres reachable via DATABASE_URL in .env.local (see DB Setup).
  • The zooly-app backend running locally (port :3004) for the API.

Ports

ServicePortNotes
face-app (Vite dev):3009Moved off :3008 to avoid colliding with the merch admin dev default
zooly-app (backend API):3004Public + admin routes

Client env vars

The face-app reads these (Vite inlines them at build time):

VariableExample (local)Example (staging)
VITE_APP_URLhttp://localhost:3004https://dev.zooly.ai
VITE_AUTH_URLhttp://localhost:3004https://auth.zooly.ai

See apps/face-app/example.env.

Always include the https:// scheme in production/preview values. Without it, client fetches resolve relative to the current origin and return the SPA HTML fallback instead of JSON (a common cause of "404 / Board not found" symptoms in deployed environments).

CORS

Add the face-app origins to ALLOWED_DOMAINS_CORS in zooly-app (apps/zooly-app/.env.local): the dev origin (http://localhost:3009) and https://face.zooly.ai (plus https://dev-face.zooly.ai for staging). The routes reuse the shared CORS helper apps/zooly-app/app/api/merch/cors.ts.

Migrate + seed

Migrations are hand-written and applied locally only against .env.local:

# from packages/db
npm run db:migrate

Seed the boards (idempotent — world-cup default board + 48 BoardTeams, nba board + 2 BoardTeams; resolves the default campaign by slug and sets each BoardTeam's campaignId pointer):

# from packages/db (uses apps/zooly-app/.env.local)
npm run db:seed:leaderboard

The seed script is packages/db/src/seed/seedTeamLeaderboard.ts. Override the shared campaign slug with FACE_DEFAULT_CAMPAIGN_SLUG (defaults to mock). If that campaign is not present in the target DB, teams seed with campaignId = null (no store link) and a warning is logged.

Seeding a remote/staging DB writes data to a remote database — only do this with explicit approval. To target a specific DB, run the seed with a different env file, e.g. npx tsx --env-file=../../.env.dev src/seed/seedTeamLeaderboard.ts. Never db push; never run migrations on a remote DB without approval.

Hero assets

Hero face-paint images live in S3 under img/face-app/ (Brazil, Germany, USA, Japan), uploaded via scripts/upload-files-to-s3.ts.

Run

# backend
npm run dev   # in apps/zooly-app  (port 3004)

# face-app
npm run dev   # in apps/face-app   (port 3009)

Then open http://localhost:3009/ — it redirects to /world-cup.

Deployment

The face-app deploys as a Vercel project (zoolyai/face-app-dev for staging). apps/face-app/vercel.json provides the SPA rewrite so board slugs and /admin/* deep links resolve to the SPA. Backend API + DB are shared with zooly-app (zoolyai/zooly-app-dev for staging).