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)
- Connect the repository; point the project root at
web/. - Install command
pnpm install, build commandpnpm --filter web build. - Set the environment variables from
docs/env/web.env.example(including per-appAPP_<SLUG>_*) for Preview and Production separately. - 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 # deployKey points:
compatibility_date >= 2025-09-01andnodejs_compatare required.- Use a managed database reachable over TCP (Neon, Supabase, PlanetScale), ideally through Hyperdrive.
- Local secrets go in
web/.dev.vars; production secrets viawrangler secret put. - Don't set
REDIS_URLorSENTRY_DSNon Workers; setAI_RECONCILE_INTERVAL_MS=0and 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 / Creem:
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.