> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat on Start + Void

> Cutover packet for the native Chat Worker: names, bindings, build, smoke checks and rollback.

`apps/chat` has native TanStack Start + Vite+ + Void source beside its Next build,
generated by the [start-bridge codemod](https://docs.tuturuuu.com/build/devops/start-bridge-codemod.md). The Next
build and `vercel.json` are untouched, so the current deployment keeps serving until
the route is flipped. `vercel-production-chat.yaml` still deploys the Next app.

## Worker

* Staging candidate: the staging Worker name (`workers_dev` and `preview_urls` off, `TUTURUUU_NOINDEX=1`). Production profile `VITE_CHAT_NATIVE_PROFILE=production` emits `tuturuuu-chat` with the same flags, `TUTURUUU_NOINDEX=0`, and no routes. The operator attaches `chat.tuturuuu.com` at cutover; config never declares a route.
* Entry: `apps/chat/cloudflare/worker.ts`; Wrangler config is emitted by `void` into `dist`. The cutover job seals that emitted config, including `configPath`, `userConfigPath`, `topLevelName`, and `definedEnvironments`.
* Host: `chat.tuturuuu.com`. Root-only: `mountHosts` is empty and `unknownHost` is `reject`, so `tuturuuu.com/chat` and any other host answer 404 before app code runs.
* Binding: `ASSETS` only (static output, `run_worker_first`). No Durable Object binding and no realtime service binding.
* Variables (names): `TUTURUUU_NOINDEX` (`0` on the production profile), optional `INTERNAL_WEB_API_ORIGIN` (default `https://tuturuuu.com`).
* Secrets (names, set on the Worker before the flip, never in the repo): `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`, `SUPABASE_SECRET_KEY`, `TUTURUUU_APP_COORDINATION_SECRET`. `TUTURUUU_APP_COORDINATION_SECRET` must be exactly Web's signer value (the `SUPABASE_SECRET_KEY` value). `apps/chat/vite.config.mts` does not inject a startup secret check, and the Worker entry has no `required-secrets` assertion, so a missing name is not a startup 500 from those gates. Auth and the Supabase server client read the four names above. Compare with the Vercel project environment list before the flip.
* Not Worker requirements: `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN`, and `ABUSE_GUARD_BACKEND`. The API proxy guard fails open when Upstash is absent. `CHAT_REALTIME_TOKEN_SECRET` and `CHAT_REALTIME_INTERNAL_URL` belong to `apps/web` and `apps/chat-realtime`, not this Worker. See the [Chat realtime runbook](https://docs.tuturuuu.com/build/devops/chat-realtime-runbook.md).
* Optional variables read by the source: `CHAT_APP_URL`, `NEXT_PUBLIC_CHAT_APP_URL`, `NEXT_PUBLIC_APP_URL`, `WEB_APP_URL`, `NEXT_PUBLIC_WEB_APP_URL`. Production falls back to `https://chat.tuturuuu.com` and `https://tuturuuu.com` when they are unset.

## Build and qualification

```bash theme={null}
bun install --frozen-lockfile --ignore-scripts
bun turbo:local run build --filter='@tuturuuu/chat^...' --concurrency=2
bun run --silent scripts/ci/generate-build-metadata.ts
VITE_CHAT_NATIVE_PROFILE=production bun run --cwd apps/chat build:cloudflare
CI=true CI_SOURCE_SHA=$(git rev-parse HEAD) VITE_CHAT_NATIVE_PROFILE=production bun run --cwd apps/chat test:runtime
```

`chat-cloudflare.yaml` job `chat-cutover-artifact` runs the same production-profile build and seals the output with `scripts/ci/chat-native-artifact.py` (`CHAT_SOURCE_SHA` mapped onto `APPS_SOURCE_SHA`). The sealed Worker name is `tuturuuu-chat`, `workers_dev` is false, and the config has no routes. Run the build on a CI or remote runner, not a developer machine.

The `native` job builds with the profile unset (the staging Worker name). `test:runtime` starts the emitted Worker in workerd
with synthetic secrets and no network egress: build identity, root host, apex rejection,
unknown paths, and the signed-out redirect through the app-owned
`cloudflare/auth-redirect.runtime.mjs` fixture (8 checks).

The app proxy admits anonymous `GET`/`HEAD /api/build-info` without an app-session
refresh, so deployment verification gets `200` instead of `401`.

## Smoke checks after the route is attached

```bash theme={null}
curl -sI https://chat.tuturuuu.com/api/build-info   # 200, JSON, no-store
curl -sI https://chat.tuturuuu.com/                 # 307 to /login for a signed-out client
curl -sI https://chat.tuturuuu.com/login            # renders, no 5xx
curl -sI https://tuturuuu.com/chat        # 404 (root-only app)
```

Every page redirects signed-out users to login, so a signed-in check needs a test
session and belongs to the release owner. No smoke request may return `5xx`.

## Rollback

1. Before the flip, record the current production Vercel deployment id for the app (the repo
   does not store it) and the DNS records and TTLs for `chat.tuturuuu.com` in the release record.
2. Roll back by detaching the Worker route or restoring the captured DNS records to the
   recorded deployment. `vercel-production-chat.yaml` still deploys the Next app.
3. Rerun the smoke checks against the previous origin.

Rolling back touches no database rows and no migrations. Route, DNS and deployment
changes belong to the release owner.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.