Skip to main content
This is the operator runbook for the migration stack:
  • apps/backend: Rust API runtime, native on port 7820, Docker sidecar, and Cloudflare Worker tuturuuu-backend.
  • apps/tanstack-web: TanStack Start frontend, local dev on port 7824, Docker sidecar, Cloudflare Worker tuturuuu-tanstack-web, and opt-in Vercel build validation.
Keep the legacy apps/web runtime available until the cutover gates pass. This page explains how to start, validate, and deploy the new stack; route ownership and cutover evidence stay in the TanStack/Rust migration contract and cutover runbook.

Required Environment

Use real values only in ignored env files, shell variables, GitHub Environment secrets, Cloudflare Worker secrets, Vercel Project Environment Variables, or VPS secret stores. Do not commit values.
VariableUsed byNotes
BACKEND_INTERNAL_TOKENbackend and frontend server runtimeShared bearer token for internal migration/status calls.
BACKEND_INTERNAL_URLapps/tanstack-web outside Cloudflare service bindingsServer-only backend origin, such as http://localhost:7820 or an HTTPS backend Worker/VPS origin.
BACKEND_PUBLIC_ORIGINapps/tanstack-web browser-safe backend origin fallbackPublic backend origin when the frontend needs a browser-safe base URL.
SUPABASE_URLbackend WorkerServer-side Supabase REST origin.
SUPABASE_SERVICE_ROLE_KEYbackend WorkerServer-side Supabase service key.
TUTURUUU_APP_COORDINATION_SECRETbackend WorkerApp coordination token verification.
CRON_SECRETbackend WorkerCron proxy parity.
DISCORD_APP_DEPLOYMENT_URLbackend WorkerDiscord app deployment proxy.
AURORA_EXTERNAL_URLbackend WorkerAurora health and ingest upstream.
AURORA_EXTERNAL_WSIDbackend WorkerAurora ingest workspace id.
TANSTACK_WEB_RUNTIMEfrontend build/runtime selectionUse node for Docker/node output, vercel for Vercel build validation, and unset for Cloudflare Workers.

Local Native Run

Native local development is two processes: Rust backend first, then TanStack Start. apps/backend/.env.example is a template; the native Rust binary reads environment variables from the process environment.
  1. From the repo root, export local-only backend values:
    export BACKEND_ENV=development
    export BACKEND_INTERNAL_TOKEN="<local-only shared token>"
    export PORT=7820
    
  2. Start the Rust backend:
    cargo run --manifest-path apps/backend/Cargo.toml --features native --bin backend
    
  3. In another shell, point TanStack Start at the backend and start the frontend:
    BACKEND_INTERNAL_TOKEN="${BACKEND_INTERNAL_TOKEN:?set BACKEND_INTERNAL_TOKEN}" \
    BACKEND_INTERNAL_URL=http://localhost:7820 \
    BACKEND_PUBLIC_ORIGIN=http://localhost:7820 \
    bun dev:tanstack-web
    
  4. Verify the backend:
    curl -fsS http://127.0.0.1:7820/healthz
    curl -fsS http://127.0.0.1:7820/readyz
    curl -fsS \
      -H "Authorization: Bearer ${BACKEND_INTERNAL_TOKEN:?set BACKEND_INTERNAL_TOKEN}" \
      http://127.0.0.1:7820/api/migration/status
    
  5. Open the frontend on port 7824. The root migration shell should report the backend as reachable when the URL and token match.
Common local failures:
  • readyz is not ready: BACKEND_INTERNAL_TOKEN is missing from the backend process.
  • TanStack shows backend unreachable: the frontend shell does not have BACKEND_INTERNAL_URL or BACKEND_INTERNAL_TOKEN, or the backend is running on a different port.
  • Rust starts but route calls fail: the route may require additional Supabase, Aurora, Discord, cron, or app coordination env values.

Docker Dual-Stack Rehearsal

Use the minimal dual-stack compose file when you want production artifacts for only the migration stack:
docker compose -f docker-compose.tanstack-dual.yml config
docker compose -f docker-compose.tanstack-dual.yml up -d --build
The default loopback ports are:
ServiceContainerHost URL
Rust backendbackend-dualhttp://127.0.0.1:7820
TanStack frontendtanstack-web-dualhttp://127.0.0.1:7824
Run the minimal Playwright E2E rehearsal:
bun test:e2e:tanstack:docker -- -- --project=chromium
Keep the stack up for manual debugging:
bun test:e2e:tanstack:docker -- --keep-up -- --project=chromium
Shut it down when finished:
docker compose -f docker-compose.tanstack-dual.yml down
Use the broader production web Docker path when the migration stack needs to run behind web-proxy, blue/green cutover, watcher recovery, Redis, cron, or Cloudflare Tunnel. That path is covered in Web Docker Deployment.

Cloudflare Workers Deployment

Cloudflare Workers is the edge preview path for both runtimes. The frontend Worker uses the BACKEND service binding to call the backend Worker first, with HTTP env fallback only for local and emergency non-binding runs. This follows the current TanStack Start Cloudflare guidance for @cloudflare/vite-plugin plus wrangler.
  1. Authenticate and validate config:
    bun wrangler whoami
    bun check:cloudflare
    
  2. Install Rust Worker prerequisites if the machine has not built Workers before:
    rustup target add wasm32-unknown-unknown
    cargo install worker-build --locked
    
  3. Bootstrap backend Worker secrets in Cloudflare:
    bun wrangler secret put BACKEND_INTERNAL_TOKEN --config apps/backend/wrangler.jsonc
    bun wrangler secret put TUTURUUU_APP_COORDINATION_SECRET --config apps/backend/wrangler.jsonc
    bun wrangler secret put SUPABASE_URL --config apps/backend/wrangler.jsonc
    bun wrangler secret put SUPABASE_SERVICE_ROLE_KEY --config apps/backend/wrangler.jsonc
    bun wrangler secret put CRON_SECRET --config apps/backend/wrangler.jsonc
    bun wrangler secret put DISCORD_APP_DEPLOYMENT_URL --config apps/backend/wrangler.jsonc
    bun wrangler secret put AURORA_EXTERNAL_URL --config apps/backend/wrangler.jsonc
    bun wrangler secret put AURORA_EXTERNAL_WSID --config apps/backend/wrangler.jsonc
    
  4. Deploy the backend Worker first:
    bun wrangler deploy --config apps/backend/wrangler.jsonc
    
  5. Bootstrap TanStack Worker secrets:
    bun wrangler secret put BACKEND_PUBLIC_ORIGIN --config apps/tanstack-web/wrangler.jsonc
    bun wrangler secret put BACKEND_INTERNAL_TOKEN --config apps/tanstack-web/wrangler.jsonc
    
  6. Generate Worker types and deploy the TanStack Worker:
    bun --cwd apps/tanstack-web run cf-typegen
    bun --cwd apps/tanstack-web run deploy:cloudflare
    
  7. Smoke both Worker origins:
    BACKEND_INTERNAL_TOKEN="${BACKEND_INTERNAL_TOKEN:?set BACKEND_INTERNAL_TOKEN}" \
    BACKEND_WORKER_ORIGIN=https://<backend-worker-origin> \
    TANSTACK_WEB_WORKER_ORIGIN=https://<tanstack-worker-origin> \
    bun smoke:cloudflare
    
For secret rotation on an already serving Worker, prefer the versions flow:
bun wrangler versions secret put BACKEND_INTERNAL_TOKEN --config apps/backend/wrangler.jsonc
bun wrangler versions deploy --config apps/backend/wrangler.jsonc
Rollback is Worker-version or route/DNS based:
bun wrangler deployments list --config apps/backend/wrangler.jsonc
bun wrangler rollback <VERSION_ID> --config apps/backend/wrangler.jsonc
bun wrangler deployments list --config apps/tanstack-web/wrangler.jsonc
bun wrangler rollback <VERSION_ID> --config apps/tanstack-web/wrangler.jsonc
External references: TanStack Start hosting, Cloudflare TanStack Start, Wrangler configuration, and Cloudflare Worker secrets.

Vercel Frontend Build Validation

Vercel is used to validate that apps/tanstack-web can produce Vercel-compatible TanStack Start output. This repository does not deploy or publish the TanStack frontend to Vercel. The Rust backend must still be reachable over HTTPS during the build, usually through the Cloudflare backend Worker or a self-hosted backend origin. Vercel mode uses the app-local TANSTACK_WEB_RUNTIME=vercel branch and Nitro, matching the current Vercel TanStack Start guidance. Configure the Vercel project:
SettingValue
Project rootapps/tanstack-web
Build commandbun run build:vercel
Framework presetOther, unless Vercel auto-detects the TanStack/Nitro output correctly
Git integrationDisabled by apps/tanstack-web/vercel.json; GitHub Actions runs vercel build only
Required Vercel Project Environment Variables:
VariableValue source
TANSTACK_WEB_RUNTIMEvercel
BACKEND_PUBLIC_ORIGINHTTPS backend origin
BACKEND_INTERNAL_URLSame HTTPS backend origin unless a separate private origin exists
BACKEND_INTERNAL_TOKENSame token configured on the backend
NEXT_PUBLIC_SUPABASE_URLSupabase project URL, if the rendered routes need Supabase client config
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYSupabase publishable key, if routes need browser Supabase config
Manual CLI sequence from the repo root:
bash scripts/ci/run-with-backoff.sh bun install
bash scripts/ci/run-with-backoff.sh bun install --global vercel@latest

VERCEL_ORG_ID="${VERCEL_ORG_ID:?set VERCEL_ORG_ID}" \
VERCEL_PROJECT_ID="${VERCEL_TANSTACK_WEB_PROJECT_ID:?set VERCEL_TANSTACK_WEB_PROJECT_ID}" \
vercel pull --yes --environment=preview --token="${VERCEL_TOKEN:?set VERCEL_TOKEN}"

TANSTACK_WEB_RUNTIME=vercel \
bun turbo:local run build '--filter=@tuturuuu/tanstack-web^...'

bun run --silent scripts/ci/generate-build-metadata.ts

TANSTACK_WEB_RUNTIME=vercel \
VERCEL_ORG_ID="${VERCEL_ORG_ID:?set VERCEL_ORG_ID}" \
VERCEL_PROJECT_ID="${VERCEL_TANSTACK_WEB_PROJECT_ID:?set VERCEL_TANSTACK_WEB_PROJECT_ID}" \
vercel build --token="${VERCEL_TOKEN:?set VERCEL_TOKEN}"
Production uses the same sequence with vercel pull --environment=production and vercel build --prod. It intentionally does not run vercel deploy. GitHub Actions owns the normal path:
  • .github/workflows/vercel-preview-tanstack-web.yaml
  • .github/workflows/vercel-production-tanstack-web.yaml
The workflows use VERCEL_TANSTACK_WEB_PROJECT_ID, VERCEL_ORG_ID, and VERCEL_TOKEN inside the build jobs only. Preview builds require workflow_dispatch from protected main plus a trusted actor. Production builds run from the production branch. They record build markers after vercel build passes and do not create Vercel deployments. External references: Vercel TanStack Start, vercel pull, vercel build.

VPS Or Self-Hosting With Cloudflare Tunnel

Self-hosting uses the existing production Docker stack. Use this when the full platform proxy, blue/green deployment history, watcher recovery, and Cloudflare Tunnel container should own traffic.
  1. Prepare the server:
    git clone https://github.com/tutur3u/platform.git tuturuuu
    cd tuturuuu
    bun install
    
  2. Put production env values in root .env.local or an explicit deployment env file. Set the frontend selector and backend token:
    DOCKER_WEB_FRONTEND=tanstack
    BACKEND_INTERNAL_TOKEN=<shared backend token>
    
  3. If using Cloudflare Tunnel, create a remotely managed tunnel in Cloudflare Zero Trust, add a public hostname for the desired domain, and route it to:
    http://localhost:7803
    
    Store the tunnel token as CF_TUNNEL_TOKEN, CLOUDFLARED_TOKEN, or DOCKER_CLOUDFLARED_TOKEN in the server env file. The Docker helper maps CF_TUNNEL_TOKEN to the Compose CLOUDFLARED_TOKEN.
  4. Start the TanStack production stack without a tunnel:
    DOCKER_WEB_FRONTEND=tanstack bun serve:web:docker:bg
    
    Start it with the bundled Cloudflare Tunnel sidecar:
    DOCKER_WEB_FRONTEND=tanstack bun serve:web:docker:bg -- --with-cloudflared
    
    A non-empty CF_TUNNEL_TOKEN in root .env.local also auto-enables the tunnel sidecar unless the Docker helper is explicitly opted out.
  5. Verify through the local proxy:
    curl -fsS http://127.0.0.1:7803/__platform/drain-status
    
  6. Verify through the public hostname after Tunnel reports healthy:
    curl -fsS https://<public-hostname>/
    
  7. Stop the stack:
    DOCKER_WEB_FRONTEND=tanstack bun serve:web:docker:bg:down
    
Rollback options:
  • Blue/green: use the existing cached rollback path documented in Web Docker Deployment.
  • Git: check out the previous known-good commit and rerun DOCKER_WEB_FRONTEND=tanstack bun serve:web:docker:bg.
  • Tunnel: remove or change the Cloudflare public hostname route while the local stack is repaired.
External references: Cloudflare Tunnel setup and Cloudflare remote tunnel creation.

Verification Checklist

Run these before handing off a local or deployment-config change:
python3 -m json.tool apps/docs/docs.json apps/tanstack-web/vercel.json
node --test scripts/check-cloudflare-workers.test.js scripts/ci/check-workflow-config.test.js scripts/ci/release-workflows.test.js
bun check:cloudflare
bun type-check:tanstack-web
git diff --check
bun check
Do not run deploy commands, production Supabase pushes, or long build commands from an implementation session unless the user explicitly requested live deployment or build execution.