Skip to main content
Retained inactive reference. Docker setup and Rust are paused and not in use. The apps/tanstack-web monolith and the Docker cron runner are retired. Per-app TanStack Start remains the active target (see the native Start migration runbook). Do not execute the retained build, test, migration, deployment, or dependency-update procedures until explicitly resumed. Docker-backed E2E jobs are also paused. Use the active runtime map for current operations.
This runbook is the discoverable docs copy of the root cutover runbook for the TanStack Start plus Rust backend migration. It focuses on operational checks and does not replace the route ownership contract at platform/architecture/tanstack-rust-migration. For how to start the native services, run the dual-stack Docker stack, deploy the Workers, validate the Vercel TanStack frontend build, or expose a VPS through Cloudflare Tunnel, use TanStack/Rust Local And Deployment.

Purpose

Use this runbook when proving the new production target is ready:
  • apps/tanstack-web serves the frontend.
  • apps/backend serves Rust-owned backend routes.
  • the dual stack runs from production Docker artifacts.
  • compare mode proves the legacy and new frontend paths can pass the same smoke suite before traffic moves.

Local Dual-Stack Commands

Validate the compose file without starting anything:
Run the minimal dual-stack TanStack/Rust E2E suite:
The command starts docker-compose.tanstack-dual.yml, waits for backend-dual and tanstack-web-dual to become healthy, runs Playwright in apps/tanstack-web, and tears the stack down unless --keep-up is passed to the runner. Run the focused compare smoke used by CI:
Run a broader compare rehearsal by omitting the spec filter, but expect a much longer full-stack run:

Services And Ports

docker-compose.tanstack-dual.yml exposes only loopback ports by default: The frontend healthcheck must prove the root page renders and can reach the backend. Keep real secret values in ignored env files or CI secrets; docs and workflow files should reference environment variable names only.

CI Coverage

The E2E workflow includes a migration matrix:
  • tanstack-dual-stack runs the minimal dual-stack compose runner against apps/tanstack-web/e2e.
  • compare-smoke runs scripts/run-web-e2e-docker.js --frontend compare against a focused public no-auth spec.
Both jobs upload Playwright and tmp/e2e artifacts for failure triage.

Evidence For Gates

The final cutover gate consumes fresh evidence reports:
Use diagnostic mode while legacy routes remain:
For terminal cutover, do not pass any --skip-* evidence flags.

Final Checklist

  • bun migration:tanstack:cutover-check passes with zero legacy-next artifacts.
  • dual-stack Docker E2E passes against docker-compose.tanstack-dual.yml.
  • compare-mode Docker E2E passes for both Next and TanStack frontends.
  • benchmark compare evidence is fresh and within thresholds.
  • Cloudflare smoke probes pass for backend and TanStack origins.
  • bun migration:tanstack:gates exits 0 with all evidence present.
  • final bun validate passes or has only documented unrelated blockers.
Keep apps/web available as rollback fallback until the cutover window is complete and the post-cutover smoke has stayed green.

Satellite additions during migration

The main manifest inventories the live Web API and dashboard. New satellite surfaces must also remain visible: register their exact source-based route IDs in apps/tanstack-web/migration/satellite-route-overrides.json. The manifest command also generates satellite-route-backlog.json; bun migration:tanstack:check verifies both inventories. The satellite registry currently covers hosted Learn playground pages, Infrastructure account benefits and the native Meet editor shell. Adding an app derives its inventory from the registered source path; removing a registered route requires an explicit accepted-removal decision. Preserve shared Internal API contracts and authorization when migrating each surface. This backlog does not change live routing or authorize a Rust cutover.

Meet production cutover

Meet’s production publication is admitted in tuturuuu.ci.ts (productionPublicationPolicy.meet, surfaces frontend and realtime-do). Unlike Calendar, Meet does not change origin: the native Start + Void build publishes as a new version of the same tuturuuu-meet Worker that served the legacy OpenNext build, on the same meet.tuturuuu.com custom domain. The MeetLiveDurableObject migration (meet-live-v1) is identical in both configurations, so no Durable Object migration runs. Release owner steps:
  1. Promote a green main SHA to production. The planner selects meet-cloudflare.yaml; its deploy job records the current tuturuuu-meet and tuturuuu-meet-realtime versions and deployments in the meet-rollback-<sha>-<run> artifact before any write.
  2. Private smoke before promotion (required): the deploy job’s wrangler deploy is the public flip, so first upload the qualified artifact with wrangler versions upload (no traffic) and route only operator requests to it with the Cloudflare-Workers-Version-Overrides header on meet.tuturuuu.com. Promote only after the real-call QA passes (join, SFU media, lobby rename, consent, an authenticated API call and a server action). Record the legacy tuturuuu-meet and tuturuuu-meet-realtime version IDs first.
  3. Keep MEET_AI_ENABLED_WORKSPACE_IDS set as a secret on tuturuuu-meet (Meet AI is default-allow without it; the deploy job fails closed) and watch errors for 30 minutes after the flip, rolling back at the first regression.
  4. Rollback is one step: wrangler versions deploy <legacy-version-id>@100% --name tuturuuu-meet (and the same for tuturuuu-meet-realtime if its version changed), using the IDs from the rollback artifact. Rehearse once before announcing.
  5. Verify https://meet.tuturuuu.com/api/build-info reports the promoted SHA.
To hold Meet again, set productionPublicationPolicy.meet back to { state: 'held', reason: ... }; the planner and the deploy job’s production-policy gate then skip every Meet production write.