Sign in

Deployment

Ship the web app to Vercel, your own Docker host, or Cloudflare Workers; build mobile with EAS.

The web app deploys to three targets out of the box. Pick one — no code changes required to switch later.

Vercel (default)

  1. Connect the repository; point the project root at web/.
  2. Install command pnpm install, build command pnpm --filter web build.
  3. Set the environment variables from docs/env/web.env.example (including per-app APP_<SLUG>_*) for Preview and Production separately.
  4. Run database migrations from CI before switching traffic (pnpm --filter web db:migrate).

Docker (self-hosted)

A production multi-stage web/Dockerfile is included (deps → build → runner, Next standalone output, non-root user). Build from the monorepo root:

docker build -f web/Dockerfile -t zmlkit-web .
docker run --env-file web/.env.production -p 3000:3000 zmlkit-web
  • Build needs no real secrets — placeholder env is baked in; everything real is injected at runtime.
  • Put a reverse proxy (Caddy/Nginx/Traefik) in front for TLS.

Cloudflare Workers (OpenNext)

The template runs on Workers via the OpenNext adapter — the runtime-sensitive pieces (password hashing, image processing, middleware) are already Workers-safe:

cd web
cp wrangler.toml.example wrangler.toml   # gitignored; fill in your account
pnpm cf:build      # bundle
pnpm cf:preview    # local workerd preview (best on Linux/WSL)
pnpm cf:deploy     # deploy

Key points:

  • compatibility_date >= 2025-09-01 and nodejs_compat are required.
  • Use a managed database reachable over TCP (Neon, Supabase, PlanetScale), ideally through Hyperdrive.
  • Local secrets go in web/.dev.vars; production secrets via wrangler secret put.
  • Don't set REDIS_URL or SENTRY_DSN on Workers; set AI_RECONCILE_INTERVAL_MS=0 and drive async AI finalization with provider webhooks + a cron hitting /api/ai/cron.

Webhooks

After deploying, register the payment/AI webhooks per app in each provider dashboard:

  • Stripe / Waffo Pancake: https://<domain>/api/billing/webhooks/{provider}/{appSlug}
  • Kie (async AI): https://<domain>/api/ai/webhooks/kie/{appSlug}

The signing secrets go in the matching APP_<SLUG>_*_WEBHOOK_SECRET env vars.

Mobile (EAS)

The Expo app builds with EAS profiles (mobile/eas.json): development (dev client), preview, production. Set EXPO_PUBLIC_API_BASE_URL to your deployed web URL. OTA updates ship via EAS Update; native rebuilds are only needed when native dependencies change.