Production - deployment
Production setup for the OpenQuok web, backend, optional CLI auth server, and optional orchestrator workers.
Connect your agent today
Draft from chat, review in your calendar, and publish only what you approve.
The production version (openquok.com) is set up for:
1) Vercel for the backend (Express.js) (/backend)
2) Vercel for web (SvelteKit) (/web)
3) (Optional) the CLI auth server (/agent/server — OAuth device flow) Supabase remains the database and auth provider for the API.
It is noted that Orchestrator workers (BullMQ) are not run on Vercel. We deploy separate always-on processes (for example on Railway) that share the same Redis and Supabase credentials as the API. See Configuration - Worker and Orchestrator workflows.
Self-host
To run API, web, Redis, and BullMQ workers on your own host from this monorepo, follow Docker Compose (self-host). After docker compose … up --build, open the UI at http://localhost:4007 (API at http://localhost:3000). That path still needs an operator-provided Supabase project; see System requirements.
What you need
- Supabase project (URL, anon key, service role key)
- Vercel projects for
backend/,web/, and optionallyagent/server/(CLI device-flow auth helper — see Configuration - Agent) - Recommended: managed Redis for production OAuth flows, BullMQ orchestration, and shared rate-limit counters when RATE_LIMIT_REDIS_ENABLED is on (production default).
Warning
- Optional: one or more worker hosts for BullMQ flows (see Railway (orchestrator workers))
Secrets and configuration
- Never commit real secrets. Use backend/.env.development.example and backend/.env.production.local locally. Use the Vercel dashboard in production.
Tip
- Mirror the same variable names as in backend/config/GlobalConfig.ts (via
getEnv/getEnvBoolean/getEnvNumber). - Public site origin: set the same canonical HTTPS origin on the backend as FRONTEND_DOMAIN_URL and on the web build as VITE_FRONTEND_DOMAIN_URL (no trailing slash after the host, for example https://www.openquok.com).
Note
www or apex) and use it — OAuth redirect URIs are built only from FRONTEND_DOMAIN_URL, and providers such as Meta require an **exact** string match in their dashboards.- CORS: include apex and
wwwin ALLOWED_FRONTEND_ORIGINS when both hostnames serve traffic, even though OAuth uses a single canonical origin above.
Note
- Local HTTPS dev differs: the web app can use an empty VITE_API_BASE_URL and same-origin
/apithrough the dev server. See Vite (SvelteKit). - Media publishing (Threads, etc.): for posts with media stored as object keys, set STORAGE_R2_PUBLIC_BASE_URL so workers can build public HTTPS URLs for Meta to fetch. See R2 or local storage.
- Rate limiting (backend API only): set NOT_SECURED to false on the Vercel backend so production defaults apply.
- Maintenance cutover: for Supabase region migration or other ops windows, set MAINTENANCE_MODE on the backend, web (server env), and workers together. See Maintenance mode and Supabase backup.
Warning
If you change FRONTEND_DOMAIN_URL or VITE_FRONTEND_DOMAIN_URL, redeploy or restart both the API and the web app, then update third-party allow-lists (Meta Instagram or Threads redirect URIs, Stripe return URLs, etc.) so every registered URL uses the same scheme and host as FRONTEND_DOMAIN_URL.
Supabase production migrations
Run schema changes when a release adds tables or RLS under backend/supabase/db/. Re-aggregate locally first:
pnpm backend:db:aggregate-migrations-all From backend/ (linked to your production project):
cd backend
pnpm db:production:migration-list There are two ways to apply migrations. One is CLI push — runs the aggregated file under backend/supabase/migrations/:
pnpm db:production:push-db:dry-run
pnpm db:production:push-db Another one is copy & paste SQL from the module folder (e.g. backend/supabase/db/acquisition/) into the Supabase Dashboard → SQL Editor.
After the SQL succeeds, mark the matching aggregated migration as applied so migration list stays in sync with the remote (use the date segment from the filename, e.g. 20260919 from 20260919_core_structure.sql):
npx supabase@latest migration repair --linked --status applied 20260919
pnpm db:production:migration-list After a region restore, prefer pnpm prod-backup:relink from the repo root. It links to the target project and repairs the current aggregate date only when remote history is behind. Do not run db push during cutover — restore already applied the schema.
Warning
Do not revert old migration rows. If production already has an earlier aggregated migration recorded, only add the new version as applied. Do not run repair --status reverted on migrations that are already live unless you are deliberately rolling back schema.
Optional — refresh backend table types from the linked project:
pnpm db:production:typegen See also Database & migrations for local workflow, aggregation, and pg_cron notes.
Deploy with Vercel
Use the detailed CLI and project settings on Vercel. From the repository root:
pnpm vercel:env:sync:web:prod
pnpm vercel:env:sync:backend:prod
pnpm vercel:env:sync:agent-server:prod pnpm vercel:deploy:backend:prod
pnpm vercel:deploy:web:prod
pnpm vercel:deploy:agent-server:prod After deploy, configure OAuth redirect URIs, webhooks, and any third-party dashboards to use your production API URL.
Check API startup logs for rate limiters using store: redis when RATE_LIMIT_REDIS_ENABLED is enabled. If public pages return 503 (SSR maps API 429), see the runbook in Rate limiting.
Deploy orchestrator workers (Railway)
Workers are required when you configure BullMQ transports . Use Configuration → Worker → Railway (workers) for the full CLI flow and service management details.
Warning
railway service to select the correct Railway service.From the repository root, set up / deploy one persistent service per worker:
# One-time: create services + set production env vars
pnpm railway:setup:integration-refresh
pnpm railway:setup:notification-email
pnpm railway:setup:scheduled-social-post # Update env (safe to re-run)
pnpm railway:env:sync:integration-refresh:prod
pnpm railway:env:sync:notification-email:prod
pnpm railway:env:sync:scheduled-social-post:prod # Deploy each worker (Railway CLI must be linked to the target service)
pnpm railway:deploy:integration-refresh
pnpm railway:deploy:notification-email
pnpm railway:deploy:scheduled-social-post Optional: publish npm packages (SDK + CLI)
Skip this section when the release only changes the dashboard, API, or workers — npm users are unaffected.
When a release changes the public API (sdk/) or the CLI (agent/), publish after the API is live on production and after you commit the shipped code to main. Bump versions in the same release commits so git, tags, and npm stay aligned.
1. Pre-flight (feature commit)
Commit everything that Vercel already deployed (or will deploy):
git add -A
git commit -m "feat: …"
git push origin main 2. Bump versions and tag (CI publish — recommended)
Match version in each package to the tag you will push. CI (.github/workflows/release.yml) publishes on tag push via npm trusted publishing.
SDK (@openquok/node-sdk) — bump sdk/package.json, then:
git add sdk/
git commit -m "chore(sdk): release 0.0.12"
git push origin main
git tag sdk-v0.0.12
git push origin sdk-v0.0.12 CLI (@openquok/auto-cli) — bump agent/package.json, then:
git add agent/
git commit -m "chore(cli): release 0.0.15"
git push origin main
git tag cli-v0.0.15
git push origin cli-v0.0.15 Preview release notes before tagging (from repo root):
pnpm release:notes sdk-v0.0.12
pnpm release:notes cli-v0.0.15 Full checklists: sdk/PUBLISHING.md and agent/PUBLISHING.md.
3. Manual publish (alternative)
If you are not using tag-driven CI, bump version in sdk/package.json and/or agent/package.json, commit and push to main, then from the monorepo root:
pnpm publish:sdk:build
pnpm publish:sdk:manual
pnpm publish:cli:build
pnpm publish:cli:manual Requires npm login locally. Prefer tags + CI when trusted publishing is configured.
Not agent/server
agent/server (Vercel device-flow auth) is not the npm CLI. Deploy it with pnpm vercel:deploy:agent-server:prod only when agent/server/ changes — not as part of @openquok/auto-cli publish.