Deploying
One Worker serves the built SPA and every /api route, including the voice WebSocket. It ships in two flavours, chosen by Wrangler environment.
| Flavour | Command | Worker name | Store |
|---|---|---|---|
| D1 (default) | npm run deploy | ai-pob-claimpilotchat | the DB binding to D1 claimpilot-chat |
| Neon | npm run deploy:neon | ai-pob-claimpilotchat-neon | Neon over DATABASE_URL |
The Cloudflare account is pinned in api/wrangler.jsonc, so local commands and Workers Builds always target the same one. Named Wrangler environments inherit nothing, so the neon environment restates its assets, vars and gateway ids.
First deploy of an environment
-
Set the secrets. Secrets are per environment: a secret put on the default environment is not visible to
--env neon.cd apinpx wrangler secret put GEMINI_API_KEYnpx wrangler secret put CF_AIG_TOKEN # if the AI Gateway is authenticatednpx wrangler secret put EMBED_KEY # optional budget guardnpx wrangler secret put DATABASE_URL --env neon # Neon flavour only -
Create the schema.
npm run db:migrate:remote # D1npm run db:migrate:neon # Neon -
Check the pinned settings in
api/wrangler.jsonc: models, voice,DATABASE_PROVIDER, the AI Gateway ids andALLOWED_ORIGINS. Awrangler deploysets only what is in this file, so nothing set by hand in the dashboard survives. -
Deploy.
npm run deploy # or npm run deploy:neonThis builds the SPA and the embed bundle, then runs
wrangler deploy. -
Load claims with the generator (
--target d1-remoteor--target neon) orcopy-claims, for example:npm run copy-claims -- --from d1-local --to d1-remote -
Check it. See After a deploy.
The AI Gateway ids are pinned in wrangler.jsonc, so a deploy turns the gateway on. If the gateway is authenticated and CF_AIG_TOKEN is not set for that environment, every model call fails with AiGatewayError 2009 Unauthorized. Set the secret before deploying.
Routine deploys
npm run test:all && npm run deploy
New migrations are applied before the deploy that needs them (db:migrate:remote or db:migrate:neon). Migrations are additive by convention, so the running version keeps working while they apply.
Each build stamps version.json. Open tabs poll it every minute and show A new version is available with a refresh button once the new deployment lands.
Auto-deploy from GitHub (Workers Builds)
Connect the repository in the Cloudflare dashboard with:
| Setting | Value |
|---|---|
| Root directory | / |
| Build command | npm run build |
| Deploy command | npm run deploy -w api (or npm run deploy:neon -w api) |
| Worker name | must match name in wrangler.jsonc |
Secrets and the remote schema and data are set up once, outside the build, as above.
After a deploy
| Check | How |
|---|---|
| The Worker is up and configured | GET /api/health reports database, the model, configured: true, and the gateway id |
| Claims load | Open the site; the root URL opens a random claim |
| Chat works end to end | Ask a question; an activity chip appears, then an answer with lookups |
| Voice works | Thirty seconds on the microphone. Voice depends on the Worker opening an outbound WebSocket to Gemini Live, the one thing that behaves differently from local development |
| Embedding works for each host | Their page loads the element and answers; their origin is in ALLOWED_ORIGINS |
Custom domains
Add a routes entry to wrangler.jsonc for the environment. Add the new origin to ALLOWED_ORIGINS only if pages on other origins will embed the assistant from it; same-origin pages need nothing.
Rolling back
Use Deployments in the Cloudflare dashboard, or npx wrangler rollback from api/. A rollback does not undo a migration, which is another reason to keep migrations additive.