apps/tanstack-web is the replacement frontend for the legacy Next.js
apps/web runtime. It uses TanStack Start, TanStack Router, TanStack Query,
Vite, React 19, Tailwind 4, and the existing Tuturuuu shared packages.
apps/backend is the dedicated Rust API runtime. Do not create another backend
service for this migration; extend apps/backend route groups and keep API
contracts documented in apps/backend/api/openapi.yaml. The backend runs as a
native container now and keeps a Cloudflare Workers Rust entrypoint ready in
apps/backend/wrangler.jsonc for edge preview deployment.
For exact local run commands and deployment steps across native local, Docker,
Cloudflare Workers, Vercel, and VPS/Cloudflare Tunnel paths, use
TanStack/Rust Local And Deployment.
Runtime Shape
| Runtime | Local URL | Fallback port | Owner |
|---|---|---|---|
| Legacy web | https://tuturuuu.localhost | 7803 | apps/web |
| TanStack web | https://tanstack.tuturuuu.localhost | 7824 | apps/tanstack-web |
| Rust backend | http://localhost:7820 | 7820 | apps/backend |
bun dev:tanstack-web for local TanStack work. Docker dev also exposes the
tanstack-web service on port 7824 and injects BACKEND_PUBLIC_ORIGIN,
BACKEND_INTERNAL_URL, and BACKEND_INTERNAL_TOKEN for Rust backend calls.
Cloudflare preview uses the BACKEND service binding first and keeps
BACKEND_INTERNAL_URL as an HTTP fallback for local, Docker, and emergency
non-binding runs.
Rendering And Cache Policy
Every migrated TanStack route must declare its rendering/cache class before it is marked terminal inroute-overrides.json:
| Class | Use for | Required implementation |
|---|---|---|
| Static prerender | Public routes whose HTML is fully local/static at build time. | Add the localized path to the pages and prerender options in apps/tanstack-web/vite.config.ts; keep crawlLinks: true plus the static-route filter enabled. |
| ISR-style CDN revalidation | Public routes backed by slow-changing Rust/backend data, such as models and changelog. | Add route-level headers() with Cache-Control s-maxage plus stale-while-revalidate; add CDN-Cache-Control for Cloudflare. |
| Dynamic no-store | Authenticated, workspace-scoped, session-specific, or secret-backed routes. | Do not prerender; use server functions/internal API calls with forwarded auth and no shared-cache headers. |
| Redirect/static compatibility | Redirect-only compatibility routes such as QR and docs handoffs. | Keep redirect behavior exact; only cache when the target contract is public and invariant. |
CDN-Cache-Control for Cloudflare-specific shared
cache control. Official references:
Static Prerendering
and
Incremental Static Regeneration.
The initial prerender set intentionally includes only public, unauthenticated,
non-backend-backed pages. Backend-backed public pages are not prerendered at
build time because Docker, CI, and Cloudflare builds must not require a live
Rust backend just to emit static HTML. Instead, those pages use conservative
ISR-style CDN headers from apps/tanstack-web/src/lib/platform/cache.ts.
Cloudflare Preview Deployment
Cloudflare preview deployments are supported before cutover so the team can validate the Worker runtime, smoke endpoints, and benchmark numbers without moving production traffic. The preview path uses:apps/backend/wrangler.jsoncfor the Rust Worker bundle.apps/tanstack-web/wrangler.jsoncfor the TanStack Start Worker.@cloudflare/vite-plugininapps/tanstack-web/vite.config.ts, registered beforetanstackStart().- root
wranglertooling plusbun check:cloudflareto validate both Worker configs without contacting Cloudflare.
| Runtime | Cloudflare entrypoint | Deploy command | Compatibility status |
|---|---|---|---|
| Rust backend | apps/backend/wrangler.jsonc | bun wrangler deploy --config apps/backend/wrangler.jsonc | Preview-ready for migrated pure dispatcher routes, health/readiness, protected migration inventory, static/cookie endpoints, Discord cron proxies, and the native/Worker outbound boundary. |
| TanStack Start frontend | apps/tanstack-web/wrangler.jsonc | bun --cwd apps/tanstack-web run deploy:cloudflare | Preview-ready for migrated public routes, redirects, the root migration shell, and Start server-function calls to the Rust backend. |
apps/tanstack-web deployment runs bun run build internally through the
app-local deploy:cloudflare script. Do not run it during docs-only or
inspection work unless the task explicitly allows build commands. For a
configuration-only preflight, use bun check:cloudflare.
Both Wrangler configs declare required secret names with the schema-supported
secrets.required property. The validator requires these names and rejects
secret-looking values under vars:
| Worker | Required preview secrets |
|---|---|
apps/backend/wrangler.jsonc | BACKEND_INTERNAL_TOKEN, TUTURUUU_APP_COORDINATION_SECRET, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, CRON_SECRET, DISCORD_APP_DEPLOYMENT_URL, AURORA_EXTERNAL_URL, AURORA_EXTERNAL_WSID |
apps/tanstack-web/wrangler.jsonc | BACKEND_PUBLIC_ORIGIN, BACKEND_INTERNAL_TOKEN; BACKEND service binding to tuturuuu-backend |
apps/backend/.dev.varsapps/tanstack-web/.dev.vars
.dev.vars* or .env.preview* files. bun check:cloudflare
validates the ignore rules so preview tokens and account-specific Worker
origins do not enter Git.
The backend Worker uses BACKEND_ENV=preview in wrangler.jsonc. Do not set
Cloudflare preview traffic to development; development-only migration routes
remain limited to local development and the explicit local E2E bypass.
Use wrangler secret put for initial preview bootstrapping only: Cloudflare
creates and deploys a new active Worker version when that command changes a
secret. For rotations, canaries, or any deployed Worker that already receives
traffic, use wrangler versions secret put, then promote the resulting version
with wrangler versions deploy.
Deploy the Rust backend Worker first:
BACKEND_INTERNAL_TOKEN is required before backend preview deploys are useful:
/readyz reports not-ready when the token is missing.
TUTURUUU_APP_COORDINATION_SECRET is required before contact/profile preview
routes can verify Tuturuuu ttr_app_ app-session tokens in production-like
Cloudflare environments. CRON_SECRET and DISCORD_APP_DEPLOYMENT_URL are
required before the Rust-owned Discord cron proxy routes can call the Discord
app. AURORA_EXTERNAL_URL is required before the Rust-owned Aurora health and
ingest routes can call the Aurora service, and AURORA_EXTERNAL_WSID is
required before Aurora ingest routes can write rows. Wrangler prompts for
values; do not place those values in wrangler.jsonc, vars, docs, or shell
history.
SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY are required backend Worker
secrets for the Rust-owned contact/profile APIs. They stay server-only: the
backend reads users and user_private_details, updates profile fields, and
inserts support_inquiries through Supabase REST with the service-role key.
GET /api/migration/status exposes only redacted readiness state and the
Supabase origin, never the credential.
Smoke-test the returned workers.dev URL before pointing the frontend at it:
apps/tanstack-web/wrangler.jsonc
declares a BACKEND service binding to tuturuuu-backend, so the backend
Worker must be deployed first. Store only the browser-safe public backend
origin and the shared internal token as Cloudflare secrets for preview runs:
BACKEND_PUBLIC_ORIGIN should initially be the backend Worker origin, for
example the https://<backend-worker>.<subdomain>.workers.dev URL returned by
the backend deploy. It remains the browser-safe origin used for public probes
and non-protected traffic. Start server functions prefer the BACKEND service
binding for Worker-to-Worker backend calls and fall back to
BACKEND_INTERNAL_URL only outside Cloudflare or when the binding is absent.
Use BACKEND_INTERNAL_URL in local Docker, local Node preview, or emergency
HTTP fallback runs; do not make it a required TanStack Worker secret while the
service binding is declared. The TanStack Worker still needs the same
BACKEND_INTERNAL_TOKEN value so Start server functions can call protected Rust
migration inventory endpoints. Local wrangler dev can omit origin bindings
because packages/internal-api falls back to http://localhost:7820; local
migration dashboard calls will fall back to the checked manifest when the
backend token is not configured.
Deploy the TanStack Start Worker after the backend origin secrets are present:
http://localhost:8780 for the Rust backend
and http://localhost:8784 for TanStack Start. Keep those ports stable because
bun check:cloudflare validates them and the smoke examples below assume them.
Set the same env variable names that the deployed Workers use. Keep values in
the shell, local ignored env files, or Wrangler secret storage only:
BACKEND_INTERNAL_TOKEN and BACKEND_PUBLIC_ORIGIN. When the TanStack local
Worker cannot use the BACKEND service binding, set BACKEND_INTERNAL_URL to
the local backend Wrangler origin as an HTTP fallback.
Then run the preview smoke command against the returned Worker origins:
workers.dev or
custom preview origins returned by Wrangler. Set BACKEND_INTERNAL_TOKEN in the
shell before running the smoke command. The smoke command probes /healthz,
/readyz, authenticated /api/migration/status, missing/invalid-token
rejection for the protected migration status endpoint, and the TanStack root
shell. It fails on unexpected 4xx and 5xx responses, requires the TanStack
root shell to show Backend reachable, and redacts the bearer token from
output. That final check proves the deployed Start server function can reach
the Rust Worker through the service binding or configured HTTP fallback and
token, not just that the static shell rendered. Use --output to persist the
smoke report under
ignored tmp/benchmarks/web-migration/<timestamp>/cloudflare-smoke.json when
the run is part of a cutover rehearsal.
For deployed E2E smoke runs, set TANSTACK_EXPECT_BACKEND_REACHABLE=1 and
TANSTACK_EXPECT_BACKEND_TARGET=cloudflare-workers so the migration shell must
prove the frontend can reach the Rust Worker.
For a non-terminal Cloudflare preview gate, attach that smoke report while
explicitly allowing the still-legacy route inventory:
apps/web as the production source of
truth until the manifest, Docker E2E, benchmark, and cutover gates below pass.
Do not map production hostnames to the preview Worker while workers_dev
canary traffic and route parity are still in progress.
Rollback is currently DNS/routing only: remove or roll back any Cloudflare route
or custom-domain mapping that sends traffic to the preview Worker, and leave the
Docker blue/green apps/web production stack serving the canonical host. Do
not delete Wrangler secrets during rollback unless the secret itself is
compromised; keeping them bound makes redeploying the previous Worker version or
re-running smoke checks deterministic. Inspect and roll back preview Worker
deployments with Wrangler:
bun smoke:cloudflare against the
remaining preview origins before resuming canary traffic.
Protected TanStack-to-backend traffic now has a Cloudflare service binding from
the TanStack Worker to the backend Worker: binding name BACKEND, service
tuturuuu-backend. The shared backend client prefers that binding in
server-only TanStack code and keeps BACKEND_INTERNAL_URL as a non-Cloudflare
HTTP fallback. Protected workspace and admin APIs still must not move to
production Worker traffic until each route has backend tests, OpenAPI coverage,
an internal-api facade, and migration gate evidence. Browser code must never
receive service tokens, and server-owned protected data must stay behind
server-owned calls.
Current Cloudflare limitations:
- Runtime service binding smoke is pending. The config and internal client use
the
BACKENDbinding, but deployed smoke still needs to prove the binding path in Cloudflare preview before production host routing. - Production host routing is pending full route manifest completion, Docker
compare-mode E2E evidence, benchmark evidence, and
bun migration:tanstack:gates. - Preview Workers should not become the owner for private workspace/admin APIs until each route has backend tests, OpenAPI coverage, an internal-api facade, and migration gate evidence.
Route Ownership Manifest
The current migration manifest is checked in atapps/tanstack-web/migration/route-manifest.json. It records the current
apps/web/src/app route inventory, intended target owner for each route, and a
progress summary grouped by target owner and route kind. API and route-handler
entries also include a methods array derived from exported Next route methods;
summary.methodCounts tracks total exported GET, POST, PUT, PATCH,
DELETE, HEAD, and OPTIONS handlers. When only some methods on a legacy
route.ts are migrated, route-overrides.json can split that file into
method-level artifacts with parentId and method; the unmigrated paired
methods stay visible as legacy-next.
Rust GET-handler migration wave
The backend port proceeds GET-first: a route’s read path moves to a Rust handler inapps/backend/src/<module>.rs while its mutation methods stay on the live
Next.js route. The Rust handler matches the legacy mount path exactly and returns
None (never 405) for every method it does not own, so the worker falls through
to Next.js for POST/PUT/PATCH/DELETE. Because the route is still the source
of truth for writes, it correctly stays legacy-next in the manifest until the
remaining methods are ported and a cutover decision is recorded — GET-only ports
do not flip ownership status, so they add no manifest debt.
As of this wave the curated non-special fresh-GET surface is migrated: ~235 GET
routes now have Rust handlers. The only deliberately-skipped GET routes are
/api/v1/workspaces/:wsId/mind/boards/:boardId and
/api/v1/workspaces/:wsId/whiteboards/:boardId, whose CRDT/Yjs binary state lives
in a store the worker cannot reach; they stay on Next.js. Still pending as
separate phases: mutation methods for the GET-migrated routes, and special-auth
GET routes (/api/cron/* CRON_SECRET, /api/trpc, /:locale pages, OAuth
callbacks, and Hive routes backed by HIVE_DATABASE_URL).
Each batch is verified with bun check:backend (mirrors the CI Rust gate: cargo fmt --check, cargo clippy --locked --all-targets --features native -- -D warnings, cargo test --locked, and the wasm32-unknown-unknown worker check)
plus a runtime dual coverage probe that asserts every migrated GET is served by
the dispatcher (COVER) and every un-ported method still falls through (FRESH).
Worker-incompatible routes (native-backend or Next.js only)
Some legacy routes cannot run on the Cloudflare Worker build ofapps/backend because the wasm sandbox has no arbitrary sockets, no filesystem,
and no Redis/Postgres drivers. They split into three buckets:
- Native-backend portable (deferred, needs secrets wired): the scheduler
/api/cron/*jobs that just “call an external API + write Supabase” —finance/exchange-rates,inventory/polar-product-sync,payment/{orders,products,subscriptions},ai/sync-models,tasks/generate-embeddings,calendar/{provider-sync,smart-schedule},process-{post-email-queue,topic-announcement-queue,notification-batches}, andhive/simulate. These ARE portable to the native Rust container target (--features native, which can do outbound HTTP and reach external DBs) once each job’s provider secret/connection is added toBackendConfig+wrangler.jsoncsecrets. They are not portable to the wasm Worker build. Until the secrets are wired they stay on Next.js (Bearer CRON_SECRET). - Host/infra-coupled (stay where the runner lives): the cron-runner
monitoring surface —
monitoring/cron/{control,run,runner-recovery,executions}, pluscron/infrastructure/{docker-recovery-alerts,sample-resources}— reads a filesystem archive / controls the deployment host (Docker control), andcron/infrastructure/sync-trust-cacheneeds Redis. These belong with whatever orchestrates the runner, not a stateless handler. - Transport that can’t be a single handler:
/api/trpc/[trpc]is a catch-all that dispatches the entire tRPC procedure router (appRouter). The transport stays on Next.js; its data access migrates incrementally as individual procedures move behindpackages/internal-api/ the Rust backend.
apps/tanstack-web/migration/route-overrides.json with an evidence note rather
than leaving them as untriaged legacy-next backlog.
Current inventory:
173pages56layouts578route handler artifacts8cron handlers811total tracked route artifacts239migrated artifacts,252terminal artifacts, and559remaining legacy-owned artifacts in the checked manifest
apps/tanstack-web/src/routes/** files:
Register augmentation footer that
bun check:cloudflare validates for the Cloudflare-compatible Start runtime,
then formats the generated routeTree.gen.ts with the generator’s isolated
Biome config so repeated route-tree generation does not leave persistent dirty
output. The Rust/TanStack Cloudflare workflow runs
scripts/generate-tanstack-route-tree.test.js whenever the generator changes.
Route ownership status is preserved through
apps/tanstack-web/migration/route-overrides.json. Add an override with a
non-empty evidence note when a route becomes migrated or receives an accepted
removal decision; do not edit the generated manifest by hand.
Check that the manifest still matches the legacy route tree while migration is
in progress:
legacy-next:
tmp/
paths with the source reports. The benchmark report must be created with
--setup compare --profile full and include every required metric comparison;
smoke reports alone are useful for previews but are not sufficient cutover
evidence. The Cloudflare smoke report must come from
bun smoke:cloudflare against distinct live Rust backend and TanStack Worker
origins, and the cutover gate verifies that each required probe URL matches
that provenance.
The manifest also includes progress.byOwner, progress.byKind, and
progress.topLegacyRoutes. Use those fields when splitting the remaining port
work across frontend and backend owners. Use each route’s methods list when
checking API parity so a GET port does not accidentally hide an unmigrated
POST, OPTIONS, or mutation handler on the same route artifact. The Rust
backend exposes the same derived progress at:
apps/tanstack-web reads that endpoint through packages/internal-api and
falls back to the checked manifest when the backend is offline.
Method-level migration ownership is only valid when the deployment path can
route traffic by HTTP method or otherwise avoid sending still-legacy methods to
Rust. For example, the Rust backend can own OPTIONS preflight responses for an
auth route while the corresponding POST or GET artifact remains
legacy-next; a path-only proxy must keep that whole path on Next until the
auth method is migrated too.
First migrated ownership:
| Legacy route | New owner | Evidence |
|---|---|---|
GET /.well-known/* / HEAD /.well-known/* | apps/backend Rust route dispatcher | route-overrides.json marks the route handler migrated; Rust returns a cacheable empty 404 with Cache-Control: public, max-age=300, must-revalidate. |
GET /~recover-browser-state / POST /~recover-browser-state | apps/backend Rust route dispatcher | route-overrides.json marks the route handler migrated; Rust returns the no-store reset HTML, enforces same-origin POST confirmation, emits Clear-Site-Data, clears Supabase auth cookies, and redirects to /login?browserStateReset=1. |
GET /serwist/:path | apps/backend Rust route dispatcher | route-overrides.json marks the route handler migrated; Rust serves a no-store decommissioning worker at /serwist/sw.js that unregisters stale Next/Serwist service workers during Cloudflare cutover and returns deterministic source-map metadata at /serwist/sw.js.map. This is cutover ownership, not offline-cache feature parity. |
GET /api/health | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; GET /api/health returns the legacy ok status JSON with Cache-Control: no-store and JSON security headers. |
GET /api/time-tracking/export | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the browser Supabase session or non-app-session Bearer token, requires a @tuturuuu.com root user and the root workspace, verifies workspace membership, preserves legacy query parsing and the 1000-row limit cap, forwards get_grouped_sessions_paginated through the caller Supabase token, and returns the legacy data/pagination envelope with an empty-result fallback when RPC and JS-style recovery cannot produce rows. |
GET /api/auth/me | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the Supabase browser session cookie or non-app-session Bearer token with Supabase Auth, returns the raw legacy user payload, keeps no-store headers, and preserves the legacy Unauthorized message response for missing or invalid sessions. |
GET /api/auth/mfa/totp/assurance-level | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the Supabase browser session cookie or non-app-session Bearer token with Supabase Auth, derives currentLevel from the JWT aal claim, derives nextLevel from verified Supabase Auth factors on the revalidated user JSON, returns currentAuthenticationMethods from the JWT amr claim, and keeps the legacy no-store/error response shape. |
GET / POST /api/auth/mfa/totp/factors | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the Supabase browser session cookie or non-app-session Bearer token with Supabase Auth, mirrors Auth JS listFactors() from the revalidated user JSON, enrolls TOTP factors through Supabase Auth REST, normalizes TOTP QR codes, and preserves the legacy no-store/error response shape. |
GET / DELETE /api/auth/mfa/totp/factors/:factorId | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the Supabase browser session cookie or non-app-session Bearer token with Supabase Auth, resolves factor detail from the verified TOTP subset returned by Auth JS-compatible listFactors(), unenrolls factors through Supabase Auth REST, and preserves the legacy Factor not found and success-wrapper responses. |
GET /api/:wsId/crawlers/domains | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy no-auth, workspace-agnostic behavior, reads crawled_urls and non-skipped crawled_url_next_urls through the server-owned Supabase REST adapter, extracts valid URL hostnames, deduplicates them, and returns the sorted domain list with cached: false. |
GET /api/:wsId/crawlers/list | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the browser Supabase session, requires a @tuturuuu.com user email before server-owned admin reads, preserves the legacy raw crawled_urls row payload, domain/search filters, created_at.desc ordering, exact-count pagination, and data/count response shape. Unauthorized callers now receive an explicit 401 instead of the legacy catch-all 500. |
GET /api/:wsId/crawlers/uncrawled | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy no-auth, workspace-agnostic behavior, reads non-skipped crawled_url_next_urls, applies legacy URL filters and pagination, removes URLs already present in crawled_urls, groups the remaining rows by origin_id, and returns the legacy uncrawledUrls, groupedUrls, and pagination payload. |
GET /api/v1/workspaces/:wsId/crawlers/status | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy workspace-agnostic URL status lookup, validates the required url query parameter, reads the exact crawled_urls.url row through the server-owned Supabase REST adapter, and returns raw crawledUrl plus raw crawled_url_next_urls rows ordered by created_at.desc; missing crawled URLs still return crawledUrl: null and relatedUrls: []. |
GET /api/v1/calendar/mock | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust returns the deterministic legacy mock calendar event payload with JSON security headers. |
GET /api/v1/devboxes/cache and POST /api/v1/devboxes/cache/prune | apps/backend Rust route dispatcher | route-overrides.json marks both devbox cache routes migrated; Rust accepts CLI app-session Bearer tokens for the platform target with cli:access or browser/non-app-session Supabase credentials, requires root workspace MEMBER access, preserves the legacy empty caches list body, and returns the legacy prune acknowledgement without private devbox table mutations. Other devbox mutation routes remain legacy-owned. |
GET /api/admin/tasks/embeddings/stats | apps/backend Rust route dispatcher | route-overrides.json marks the admin statistics route migrated; Rust validates the browser Supabase auth cookie with Supabase Auth, requires a tuturuuu.com or xwf.tuturuuu.com user email, reads exact system-wide task counts through the server-owned Supabase REST adapter, and returns only the derived legacy embedding coverage payload. The SSE embedding generation route remains legacy-owned. |
GET /api/v1/ai/whitelist/me | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy app-session-first auth behavior for satellite app-session targets, falls back to browser Supabase auth cookies only when no app-session token is present, reads only the enabled flag for the authenticated email from private.ai_whitelisted_emails, and returns the derived legacy email/enabled payload. |
GET / POST /api/v1/infrastructure/ai/whitelist/domains and /emails; PUT / DELETE /api/v1/infrastructure/ai/whitelist/:email / /domain/:domain | apps/backend Rust route dispatcher | route-overrides.json marks the list/create collection methods plus detail PUT and DELETE method artifacts migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, requires a @tuturuuu.com operator email, reads, inserts, patches, and deletes private whitelist rows through the service-role private-schema REST adapter, preserves list pagination and create validation/defaults, applies legacy Boolean(enabled) truthiness for detail updates, and keeps the legacy success, validation, 403, JSON failure, and plain-text failure bodies. |
GET /api/v1/users/me/hive-access | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy app-session-first auth behavior for current-user app-session targets, falls back to browser Supabase auth cookies only when no app-session token is present, reads only hive_members.enabled and platform_user_roles.enabled/allow_role_management for the authenticated user through the server-owned Supabase REST adapter, returns the derived legacy access/admin/member payload, and keeps the legacy private cache directive on successful responses. |
GET /api/v1/cms/workspaces | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves app-session and browser Supabase auth, loads the caller’s admin-visible workspaces through service-role Supabase REST, applies root-admin and per-workspace external-project permission checks, resolves active external-project bindings, and returns the raw legacy workspace array with subscription tier metadata. |
GET /api/v1/notifications/unread-count | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves app-session and browser Supabase auth, validates the optional wsId query filter, verifies workspace membership before scoped counts, builds the legacy notification access filter, reads the exact unread count through the service-role Supabase REST adapter, and returns no-store JSON responses. |
GET /api/v1/mira/achievements | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the browser Supabase session or non-app-session Bearer token, reads the private Mira achievement catalog through the service-role private-schema Supabase REST adapter, reads the caller’s unlocked achievements through the caller-token Supabase REST adapter, and preserves the legacy unlocked-status merge, grouping, XP/stat calculation, and empty-unlocked fallback when the user-achievement read fails. |
GET /api/v1/storage/list | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust validates legacy ttr_ workspace API keys, resolves role/default workspace permissions, requires manage_drive or admin, preserves query coercion and storage path sanitization, blocks mobile-deployment vault paths, lists Supabase Storage through the server-owned storage REST adapter, filters placeholder/reserved entries, recursively counts matching files, and returns the legacy data/pagination and error envelopes. |
GET /api/v1/hive/ai/models | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves Hive-only app-session auth and browser Supabase cookie fallback, requires Hive member or admin access before private reads, reads only UI-safe model columns from private.ai_gateway_models through the server-owned private-schema REST adapter, preserves the legacy enabled/type filters and provider/name ordering, and returns the derived models UI payload. |
GET /api/v1/nova/me/team | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves Nova-only app-session auth and browser Supabase cookie fallback, reads only team_id for the authenticated user from private.nova_team_members through the server-owned private-schema REST adapter, and returns the derived legacy team ID payload. |
GET /api/v1/task-board-status-templates | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves authenticated Supabase browser-cookie and non-app-session Bearer access, rejects Tuturuuu app-session tokens without falling back to stale cookies, reads the global task_board_status_templates catalog through the server-owned Supabase REST adapter, preserves legacy is_default.desc,name.asc ordering, and returns the raw legacy templates payload. |
GET / PUT /api/v1/infrastructure/mobile-versions | apps/backend Rust route dispatcher | route-overrides.json marks both method artifacts migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, requires root workspace manage_workspace_roles through the server-owned has_workspace_permission RPC, reads the fixed root workspace mobile policy config IDs for snapshots, validates and normalizes write payloads, upserts all nine root workspace policy config rows through the server-owned Supabase REST adapter, and preserves the legacy admin policy snapshot plus success/error write bodies. |
GET / POST /api/v1/infrastructure/timezones and PUT / DELETE /api/v1/infrastructure/timezones/:timezoneId | apps/backend Rust route dispatcher | route-overrides.json marks the collection GET/POST and detail PUT/DELETE artifacts migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, requires root workspace manage_workspace_roles, reads and writes private.timezones through the server-owned private-schema Supabase REST adapter, preserves value.asc ordering for reads, normalizes legacy create/update payloads, omits missing/null create IDs so the database UUID default is used, and preserves the legacy success and method-specific failure bodies. |
GET /api/v1/infrastructure/user-status-changes | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust requires a normal Supabase browser session or non-app-session Bearer token, forwards that caller token to Supabase REST so workspace_user_status_changes RLS remains active, preserves the legacy ws_id requirement, parseInt-style limit/offset range behavior, exact-count pagination, raw row list response, and legacy Supabase error body. |
GET /api/v1/infrastructure/users | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust uses the shared caller-token paginated export helper for workspace_users, preserving Supabase RLS, the legacy ws_id requirement, parseInt-style limit/offset range behavior, exact-count pagination, raw row list response, and legacy Supabase error body. |
GET /api/v1/infrastructure/classes, /product-categories, and /score-names | apps/backend Rust route dispatcher | route-overrides.json marks these routes migrated; Rust uses the shared caller-token paginated export helper for workspace_user_groups, product_categories, and user_group_metrics, preserving Supabase RLS, the legacy ws_id requirement, parseInt-style limit/offset range behavior, exact-count pagination, raw row list responses, and legacy Supabase error bodies. |
GET /api/v1/infrastructure/lessons and /packages | apps/backend Rust route dispatcher | route-overrides.json marks these routes migrated; Rust preserves the legacy no-auth service-role private-schema export for lessons, while packages revalidates a normal Supabase browser session or non-app-session Bearer token, normalizes the workspace, requires view_inventory, reads workspace_products through the service-role Supabase REST adapter, and preserves the legacy ws_id, parseInt-style limit/offset, exact-count pagination, data/count body, and error responses. |
GET /api/v1/infrastructure/bills, /roles, and /transaction-categories | apps/backend Rust route dispatcher | route-overrides.json marks these routes migrated; Rust uses the shared caller-token paginated export helper for finance_invoices, workspace_user_groups, and transaction_categories, preserving Supabase RLS, the legacy ws_id requirement, parseInt-style limit/offset range behavior, exact-count pagination, raw row list responses, and legacy Supabase error bodies. |
GET /api/v1/infrastructure/abuse-intelligence | apps/backend Rust route dispatcher | route-overrides.json marks only the GET method artifact migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, requires root workspace view_infrastructure through the shared workspace permission helper, reads reputation subjects, activity signals, and step-up challenges with caller-token Supabase REST, reads active trust overrides with the service-role Supabase adapter, and preserves the legacy limit/signalLimit parsing, summary, topRiskySubjects sorting, and auth/error bodies. POST remains legacy-owned. |
GET /api/v1/infrastructure/abuse-events | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, preserves the root workspace membership gate through caller-token Supabase REST reads, queries abuse_events with the caller token, and preserves the legacy ip/type/success filters, page/pageSize parseInt-style range behavior, exact-count pagination, data/count/page/pageSize/totalPages body, and legacy auth/error responses. |
GET /api/v1/infrastructure/blocked-ips | apps/backend Rust route dispatcher | route-overrides.json marks only the GET method artifact migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, preserves the root workspace membership gate through caller-token Supabase REST reads, queries blocked_ips with the legacy unblocked_by_user embed, and preserves the legacy status/ip filters, page/pageSize parseInt-style range behavior, exact-count pagination, data/count/page/pageSize/totalPages body, and legacy auth/error responses. POST/DELETE remain legacy-owned. |
GET /api/v1/infrastructure/suspensions | apps/backend Rust route dispatcher | route-overrides.json marks only the GET method artifact migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, requires root workspace manage_workspace_roles through has_workspace_permission with the caller token, reads active user_suspensions rows through the service-role Supabase REST adapter ordered by suspended_at.desc, returns the legacy raw row array, and preserves the legacy Unauthorized, Forbidden, and Failed to fetch suspensions error bodies. POST and detail DELETE remain legacy-owned. |
GET / POST /api/v1/infrastructure/email-blacklist and GET / PUT / DELETE /api/v1/infrastructure/email-blacklist/:entryId | apps/backend Rust route dispatcher | route-overrides.json marks all email blacklist collection and detail method artifacts migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, preserves root workspace membership gates and the detail GET non-root 401 quirk, reads, inserts, updates, and deletes through caller-token Supabase REST so RLS remains active, preserves Zod-style write validation bodies, maps duplicate creates to 409, maps detail misses to the legacy 404 bodies, and preserves update/delete prefetch behavior. |
GET /api/v1/infrastructure/bill-coupons, /bill-packages, /class-attendance, /class-members, /class-packages, /class-scores, /package-stock-changes, and /student-feedbacks | apps/backend Rust route dispatcher | route-overrides.json marks these routes migrated; Rust extends the shared caller-token paginated export helper with route-specific embedded select strings and related-table workspace filters, preserving Supabase RLS, the legacy ws_id requirement, parseInt-style limit/offset range behavior, exact-count pagination, raw row list responses, and legacy Supabase error bodies. |
GET /api/v1/infrastructure/coupons, /user-coupons, /user-monthly-reports, and /user-monthly-report-logs | apps/backend Rust route dispatcher | route-overrides.json marks these routes migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, normalizes the requested workspace, requires manage_external_migrations through the shared workspace permission resolver, reads private.workspace_promotions, private.user_linked_promotions, and the private monthly report views through the server-owned Supabase REST adapter with private-schema headers, preserves the user-coupons empty-promotion short-circuit and workspace_promotions relation object reconstruction, and preserves the legacy ws_id requirement, parseInt-style limit/offset range behavior, exact-count pagination, raw row list responses, and legacy auth/error bodies. |
GET /api/v1/infrastructure/payment-methods, /wallets, and /wallet-transactions | apps/backend Rust route dispatcher | route-overrides.json marks these routes migrated; Rust revalidates the normal Supabase browser session or non-app-session Bearer token, normalizes the requested workspace and requires view_transactions for wallet/payment method reads, reads private.workspace_wallets through the server-owned Supabase REST adapter with private-schema headers, forwards wallet transaction reads to get_wallet_transactions_with_permissions with the caller token, and preserves the legacy ws_id requirement, parseInt-style limit/offset behavior, pagination/count envelopes, raw row list responses, and legacy auth/error bodies. |
GET /api/v1/workspaces/limits | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust validates the browser Supabase auth cookie with Supabase Auth, treats tuturuuu.com and xwf.tuturuuu.com user emails as unlimited, otherwise reads only the exact count of non-deleted workspaces created by the authenticated user through the server-owned Supabase REST adapter, and returns the legacy canCreate, currentCount, limit, and remaining payload. |
GET /api/v1/workspaces/:wsId/posts/permissions | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates a normal Supabase session when present, calls the server-owned has_workspace_permission RPC for workspace approve_posts and root workspace manage_workspace_roles, and preserves the legacy quiet-failure behavior where missing auth, inaccessible workspaces, RPC failures, and missing permissions all return 200 with both permission flags false. |
GET /api/v1/workspaces/:wsId/Mention | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy path casing, revalidates a normal Supabase browser session or non-app-session Bearer token, rejects app-session tokens, requires exact MEMBER workspace membership, reads workspace_users.email with the caller token, and preserves the legacy email response, Unauthorized, Forbidden, membership lookup failure, and Supabase error bodies. |
GET /api/v1/workspaces/:wsId/habits/access | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates a normal Supabase browser session or non-app-session Bearer token, rejects app-session tokens, resolves internal, personal, UUID, and handle workspace identifiers, requires exact MEMBER membership through the service-role workspace_members read, reads ENABLE_HABITS from workspace_secrets with exact value === "true" matching, and returns the legacy enabled access payload. |
GET /api/v1/workspaces/:wsId/mobile/module-flags | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates a normal Supabase browser session or non-app-session Bearer token, rejects app-session tokens, resolves the legacy internal workspace slug, requires workspace membership through a caller-token workspace_members read, reads MOBILE_HIDE_EXPERIMENTAL_MODULES and MOBILE_HIDDEN_MODULES from workspace_secrets through the server-owned Supabase REST adapter, preserves JSON-array and comma-separated hidden-module parsing, and returns sorted hiddenModuleIds with the legacy private cache directive. |
GET /api/v1/workspaces/:wsId/education/access | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates a normal Supabase browser session or non-app-session Bearer token, mirrors getPermissions-style workspace permission resolution for ai_lab, reads ENABLE_EDUCATION from workspace_secrets through the server-owned Supabase REST adapter, and preserves the legacy access-probe behavior where workspace, feature-flag, permission, and lookup failures return 200 with enabled: false. |
GET /api/v1/workspaces/:wsId/finance/budgets/status | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust accepts finance/platform app-session tokens and CLI app-session tokens before falling back to a normal Supabase browser session or non-app-session Bearer token, normalizes internal, personal, handle, and UUID workspace identifiers, requires manage_finance through has_workspace_permission, calls get_budget_status with the service-role credential, returns the raw legacy RPC payload, and preserves the legacy Unauthorized, Insufficient permissions, and Error fetching budget status bodies. |
GET /api/workspaces/:wsId/finance/charts/balance | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust accepts finance/platform app-session tokens and CLI app-session tokens before normal Supabase fallback, normalizes workspace identifiers, requires view_finance_stats, preserves the legacy required date query plus includeConfidential parsing, calls get_wallet_balance_at_date, and returns the legacy balance/date payload, Unauthorized, Forbidden, invalid-query, and balance lookup error bodies. |
GET /api/v1/workspaces/:wsId/finance/debts/summary | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust accepts finance/platform app-session tokens and CLI app-session tokens before normal Supabase fallback, normalizes internal, personal, handle, and UUID workspace identifiers, requires manage_finance, calls private-schema get_debt_loan_summary with _actor_id and _ws_id using service-role auth, returns the first legacy RPC row or the zero summary, and preserves the legacy Unauthorized, Insufficient permissions, and Error fetching debt/loan summary bodies. |
GET /api/v1/workspaces/:wsId/finance/filter-users | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust accepts finance/platform app-session tokens and CLI app-session tokens before normal Supabase fallback, normalizes workspace identifiers, requires view_transactions, preserves the legacy type branches, reads transaction and invoice creator filters through service-role Supabase REST with explicit ws_id filters, reads workspace users with the caller token for normal Supabase sessions and service-role auth for app sessions, and preserves the legacy users payload, Unauthorized, and branch-specific failure bodies. |
GET /api/v1/workspaces/:wsId/finance/invoices/subscription/context | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust accepts finance/platform app-session tokens and CLI app-session tokens before normal Supabase fallback, normalizes workspace identifiers, requires create_invoices, preserves the legacy missing-query short-circuit, validates requested student groups inside the workspace, reads month-scoped attendance and completed invoice history through service-role Supabase REST, returns the legacy attendance and latest paid invoice context shape, and preserves the legacy Unauthorized and subscription-context error bodies. |
GET /api/v1/workspaces/:wsId/finance/recurring-transactions/upcoming | apps/backend Rust route dispatcher | route-overrides.json marks only the upcoming transactions route migrated; Rust accepts finance/platform app-session tokens and CLI app-session tokens before normal Supabase fallback, normalizes workspace identifiers, requires view_transactions, preserves JavaScript parseInt-style daysAhead parsing with a 30-day fallback, calls get_upcoming_recurring_transactions with caller-token auth for normal Supabase sessions and service-role auth for app sessions, and preserves the legacy upcomingTransactions payload, 403 Unauthorized, and fetch-failure bodies. Recurring transaction collection and detail routes remain legacy-owned. |
GET /api/v1/workspaces/:wsId/settings/permissions | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates a normal Supabase browser session or non-app-session Bearer token, rejects app-session tokens, resolves personal/workspace identifiers, mirrors getPermissions role/default/creator/admin behavior, and returns the legacy manage_subscription, manage_workspace_settings, and manage_workspace_members flags with the private 30-second success cache directive. |
GET /api/v1/workspaces/:wsId/settings/permissions/check | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates a normal Supabase browser session or non-app-session Bearer token, ignores app-session tokens and the legacy userId query, resolves personal/workspace identifiers, requires workspace access, and mirrors getPermissions role/default/creator/admin behavior before returning the hasPermission payload. |
GET /api/v1/workspaces/:wsId/course-modules and GET /api/v1/workspaces/:wsId/quiz-sets/:setId/linked-modules | apps/backend Rust route dispatcher | route-overrides.json marks both education read endpoints migrated; Rust revalidates a normal Supabase browser session or non-app-session Bearer token, resolves ai_lab workspace permission, requires the ENABLE_EDUCATION secret, reads course modules through service-role Supabase REST with exact-count page/pageSize/q behavior, and verifies linked quiz sets belong to the resolved workspace before listing linked modules. |
GET / PATCH /api/v1/user/onboarding-progress | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust validates the browser Supabase session with Supabase Auth, reads or upserts only the authenticated user’s onboarding_progress row through the server-owned Supabase REST adapter, preserves the legacy allowed-field filter, null missing-row response, invalid/empty update errors, and method handling. |
PATCH /api/v1/user/profile | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust validates the browser Supabase session with Supabase Auth, validates display_name, bio, and avatar_url with the legacy limits, ignores unknown fields, updates only the authenticated user’s users row through the server-owned Supabase REST adapter, and preserves the legacy success/error response messages. |
GET / PATCH /api/v1/users/me/default-workspace | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust accepts current-user app-session tokens or revalidated browser Supabase sessions for reads, preserves the legacy null fallback when workspace data cannot be resolved, falls back from an inaccessible saved default to the caller’s personal workspace, and updates user_private_details.default_workspace_id only after validating the workspaceId field as a UUID or null and verifying workspace membership with the caller token. |
GET / PATCH /api/v1/users/calendar-settings | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust accepts calendar app-session tokens or revalidated browser Supabase sessions, reads and updates the authenticated user’s timezone, first_day_of_week, and time_format from user_private_details, defaults missing values to auto, strips unknown patch fields, validates the legacy enum/string limits, and preserves private read cache plus no-store mutation responses. |
GET /api/v1/users/me/identities | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates a normal Supabase browser session or non-app-session Bearer token with Supabase Auth, rejects Tuturuuu app-session tokens, extracts the Auth JS-compatible identities array from the revalidated Supabase user JSON, returns the legacy identities/canUnlink payload, and keeps the legacy private cache directive plus auth, Supabase rejection, and internal error bodies. |
PATCH /api/v1/users/me/full-name | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust revalidates the browser Supabase session cookie or non-app-session Bearer token with Supabase Auth, validates full_name as a required JSON string with trimmed length 1..100, and upserts user_private_details with user_id fixed to the authenticated user through Supabase REST using the caller token and on_conflict=user_id. |
POST /api/v1/aurora/health | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust validates the browser Supabase session with Supabase Auth, preserves the exact @tuturuuu.com email-domain gate, calls AURORA_EXTERNAL_URL/health, and returns the legacy success, auth, forbidden, and upstream-failure JSON bodies. |
GET / POST /api/v1/aurora/forecast, GET / POST /api/v1/aurora/ml-metrics, GET / POST /api/v1/aurora/statistical-metrics | apps/backend Rust route dispatcher | route-overrides.json marks the Aurora forecast and metrics method artifacts migrated; Rust reads public Aurora forecast and metric tables through the server-owned Supabase REST adapter for GET. POST ingest routes preserve the legacy AURORA_EXTERNAL_URL and AURORA_EXTERNAL_WSID checks, Supabase session revalidation, exact @tuturuuu.com email-domain gate, external Aurora fetches, normalized Supabase inserts with the caller token, and legacy success/error JSON bodies. |
GET / POST /api/v1/infrastructure/changelog, GET / PUT / DELETE /api/v1/infrastructure/changelog/:id, POST /api/v1/infrastructure/changelog/:id/publish, GET /api/v1/infrastructure/changelog/slug/:slug | apps/backend Rust route dispatcher | route-overrides.json marks the collection, detail, publish, and slug route artifacts migrated; Rust reads changelog_entries through the server-owned Supabase REST adapter, validates browser Supabase auth cookies with Supabase Auth before checking root workspace manage_changelog, falls back to published-only public reads for anonymous or unauthorized sessions, preserves exact-count list pagination, singular PostgREST detail/slug lookups, write authorization and validation, publish/unpublish timestamp behavior, and maps PGRST116 to the legacy 404 body. Media upload remains legacy-owned. |
GET /api/v1/inventory/storefronts/:slug, GET /api/v1/inventory/orders/:publicToken | apps/backend Rust route dispatcher | route-overrides.json marks both public inventory read endpoints migrated; Rust keeps storefront/order data behind private inventory RPCs and service-role private-schema metadata reads, preserves public storefront CDN cache headers, private storefront/order app-session and browser-session membership checks, simulated HMAC order tokens, private no-store cache headers, and legacy 401/403/404/500 JSON bodies. Storefront checkout creation, analytics events, Polar webhooks, and workspace inventory management remain legacy-owned. |
GET /api/v1/topic-announcement-verifications/:token | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust decodes the token path segment, hashes it with SHA-256, reads and updates private.topic_announcement_contact_verifications through the server-owned Supabase REST adapter, and returns the legacy public HTML pages for verified, unavailable/already-used, expired, and failed links. Workspace Topic Announcements management APIs remain legacy-owned. |
POST / DELETE /api/v1/infrastructure/languages | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy locale validation bodies and NEXT_LOCALE set/delete cookie behavior. |
POST / DELETE /api/v1/infrastructure/sidebar | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy collapsed-sidebar validation body and sidebar-collapsed set/delete cookie behavior. |
POST / DELETE /api/v1/infrastructure/sidebar/sizes | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy size validation body, two-cookie write behavior, and DELETE behavior that clears only sidebar-size. |
GET /api/v1/infrastructure/users/fields/types | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust returns the deterministic ordered legacy field type payload without opening a Supabase admin client for static metadata. |
GET /api/v1/infrastructure/ai/models | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust reads private.ai_gateway_models through the server-owned Supabase REST adapter with private-schema headers, preserves the fixed public column list, default type=language filtering, provider/tag/enabled/search/ids filters, exact-count pagination, and caps ID filters at 100 so private model metadata stays behind the backend. |
OPTIONS /api/v1/auth/password-login, /otp/send, and /otp/verify; GET / OPTIONS /api/v1/auth/otp/settings | apps/backend Rust route dispatcher | route-overrides.json marks the shared auth preflight method artifacts plus OTP settings GET migrated; Rust preserves wildcard CORS, public client/platform validation, WEB_OTP_ENABLED reads for web/tulearn, mobile OTP policy reads, non-mobile fail-open diagnostics, and mobile fail-closed errors while the paired OTP send/verify and password auth methods remain legacy-next. |
OPTIONS /api/v1/auth/mobile/password-login, /send-otp, and /verify-otp | apps/backend Rust route dispatcher | route-overrides.json marks only the OPTIONS method artifacts migrated; Rust preserves the shared legacy wildcard CORS 204 response while the POST auth methods remain legacy-next. |
GET / OPTIONS /api/v1/mobile/version-check | apps/backend Rust route dispatcher | route-overrides.json marks both method artifacts migrated; Rust preserves public strict query validation, root workspace mobile policy config reads through the server-owned Supabase REST adapter, legacy update-status evaluation, and the shared wildcard CORS response headers. |
OPTIONS /api/v1/auth/qr-login/challenges, /:challengeId, /:challengeId/approve | apps/backend Rust route dispatcher | route-overrides.json marks only the OPTIONS method artifacts migrated; Rust preserves the legacy bare empty 204 response while QR challenge creation, polling, and approval remain legacy-next. |
OPTIONS /api/v1/auth/mfa/mobile/challenges and /approvals | apps/backend Rust route dispatcher | route-overrides.json marks only the OPTIONS method artifacts migrated, including dynamic challenge polling and approval paths; Rust preserves the legacy bare empty 204 response while challenge creation, polling, approval, and approval listing remain legacy-next. |
OPTIONS /api/v1/workspaces/:wsId/external-projects/webgl-packages/upload | apps/backend Rust route dispatcher | route-overrides.json marks only the OPTIONS method artifact migrated; Rust preserves the legacy origin-dependent CMS upload CORS 204 response while the protected PUT upload remains legacy-next. |
POST /api/v1/workspaces/:wsId/user-groups/:groupId/group-checks/:postId/email | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy 410 Gone response for removed direct post email sending. |
GET / POST /api/v1/workspaces/:wsId/slides | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the current 501 Not implemented placeholder contract without adding protected workspace slide data access. |
PUT / DELETE /api/v1/workspaces/:wsId/slides/:slideId | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the current 501 Not implemented placeholder contract without adding protected workspace slide data access. |
PUT /api/v1/infrastructure/migrate/grouped-score-names | apps/backend Rust route dispatcher | route-overrides.json marks the route migrated; Rust preserves the legacy development-only guard and the disabled 410 MIGRATION_DISABLED response for the removed user_group_indicators table. |
GET / PUT / PATCH / POST /api/v1/infrastructure/migrate/:migration | apps/backend Rust route dispatcher | route-overrides.json marks the legacy one-off batch migration helpers accepted-removal; Rust preserves the development/local-E2E guard and legacy method allow lists, but returns terminal 410 MIGRATION_DISABLED instead of exposing broad admin batch reads or writes through the Cloudflare-compatible backend. |
PUT /api/workspaces/:wsId/products/categories/migrate, /products/units/migrate, /transactions/categories/migrate, /users/indicators/migrate, and /wallets/transactions/migrate | apps/backend Rust route dispatcher | route-overrides.json marks these obsolete workspace migration writes accepted-removal; Rust preserves the development-only guard and returns the terminal 410 MIGRATION_DISABLED decommission body instead of preserving legacy Supabase data writes. |
GET / POST /api/v1/workspaces/:wsId/encryption/migrate, POST /api/v1/workspaces/:wsId/storage/migrate, GET /api/v2/workspaces/:wsId/migrate/:module | apps/backend Rust route dispatcher | route-overrides.json marks these production auth/API-key migration helpers accepted-removal; Rust preserves each legacy method allow list but returns terminal 410 MIGRATION_DISABLED in every environment instead of preserving broad admin calendar encryption, storage migration, or migration export data paths. |
GET /api/share/course/:courseId, GET /api/sync-logs, GET /api/users/search, GET /api/v1/proxy/tuturuuu | apps/backend Rust route dispatcher | route-overrides.json marks these retired legacy API aliases, broad maintenance/search routes, and the development-only Tuturuuu API proxy accepted-removal; Rust returns terminal 410 ENDPOINT_REMOVED with legacy Allow headers while maintained replacements, workspace-scoped readers, phase-specific routes, or direct backend/internal API clients remain separate migration work. Payment paths are not claimed by this compatibility responder and therefore return the normal platform 404. |
| Legacy route | New owner | Evidence |
|---|---|---|
/:locale | apps/tanstack-web TanStack Start static route | route-overrides.json marks the landing page, landing metadata layout, and shared marketing layout migrated; the Start route preserves the public English and Vietnamese landing content with local primitives and no framer-motion, Next.js APIs, auth, Supabase, or protected workspace data access. |
/:locale/docs | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page migrated; /:locale/docs throws a TanStack Router 307 redirect to https://docs.tuturuuu.com. |
/:locale/calendar/meet-together/[[...slug]] | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page migrated; /:locale/calendar/meet-together and nested slug paths redirect to /meet-together while preserving trailing slug segments. |
/:locale/pricing | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page migrated; /pricing and /:locale/pricing throw a TanStack Router 307 redirect to /?hash-nav=1#pricing. |
/:locale/about | apps/tanstack-web TanStack Start static route | route-overrides.json marks the about page and metadata-only layout migrated; the Start route preserves the legacy English and Vietnamese about.* message namespace through TanStack-local message files and renders without framer-motion, Next.js APIs, auth, Supabase, or protected workspace data access. |
/:locale/contact | apps/tanstack-web TanStack Start route | route-overrides.json marks the page and metadata layout migrated; the Start route preserves the visible contact shell, hydrates the current-user contact profile through TanStack Query and Start server functions, and submits inquiries through @tuturuuu/internal-api Rust backend facades for /api/v1/users/me/profile and /api/v1/inquiries. |
/:locale/users/:handle | apps/tanstack-web TanStack Start dynamic route | route-overrides.json marks the auth-gated marketing profile page migrated; the Start route preserves fail-closed current-user auth, locale-aware login redirects with nextUrl, private no-store headers, caller-scoped reads of the legacy public users profile fields through the internal-api users-server facade, the profile background/avatar shell, and explicit no-auth Playwright coverage. A Rust-owned public profile reader remains the follow-up before removing the temporary request-scoped Supabase helper. |
/:locale/contributors | apps/tanstack-web TanStack Start route | route-overrides.json marks the page migrated; the Start route preserves the public contributors shell, GitHub repository/contributor data loading, loading and error states, stats, contributor list, CTA links, and analytics sections through TanStack Query. Dependency-free CSS/SVG equivalents are accepted for the legacy framer-motion, Recharts, and react-confetti visuals. |
/:locale/women-in-tech | apps/tanstack-web TanStack Start route | route-overrides.json marks the page and metadata layout migrated; the Start route preserves the localized legacy title, Open Graph/Twitter/head metadata, public Vietnamese Women’s Day content, copied media, local language switcher, and section structure. Dependency-free native image and CSS animation replacements are accepted for the legacy Next/framer-motion runtime. |
/:locale/acceptable-use, /community-guidelines, /privacy, and /terms | apps/tanstack-web TanStack Start static routes | route-overrides.json marks each legal page and metadata-only layout migrated; the Start routes preserve the legacy static legal content, local legal primitives, and metadata without auth, Supabase, or protected workspace data access. |
/:locale/partners | apps/tanstack-web TanStack Start static route | route-overrides.json marks the partners page and metadata-only layout migrated; the Start route preserves the legacy partner content, CTAs, outbound links, local partner primitives, and copied public logo assets without auth, Supabase, or protected workspace data access. |
/:locale/products/ai, /calendar, /crm, /documents, /drive, /finance, /inventory, /lms, /mail, /tasks, and /workflows | apps/tanstack-web TanStack Start static routes | route-overrides.json marks each static product page and layout migrated; the Start routes preserve the legacy product copy, metadata, and shared page primitives without adding auth, Supabase, or protected workspace data access. |
/:locale/ai/chats/:chatId | apps/tanstack-web TanStack Start route | route-overrides.json marks the public AI chat page and metadata layout migrated; the Start route fetches only ai_chats.is_public=true rows and their ordered public messages through a server function backed by Supabase REST, hydrates with TanStack Query, preserves not-found behavior for missing/private chats, and renders a read-only transcript instead of the dashboard streaming chat client. |
/:locale/documents/:documentId | apps/tanstack-web TanStack Start route | route-overrides.json marks the public document page and layout migrated; the Start route fetches only public workspace_documents rows through a server function, hydrates with TanStack Query, preserves fail-closed not-found behavior, and keeps the current empty document body shell. The migrated layout uses stable localized generic head metadata instead of the legacy document-name Open Graph lookup to avoid a second metadata-time Supabase dependency. |
/:locale/products/meet-together | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page migrated; /products/meet-together and /:locale/products/meet-together throw a TanStack Router 307 redirect to /meet-together. |
/:locale/qr-generator | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page migrated; /qr-generator and /:locale/qr-generator redirect to the QR app origin and forward the raw query string so duplicate query keys are preserved. |
/:locale/changelog | apps/tanstack-web TanStack Start route | route-overrides.json marks the changelog index page migrated; the Start route reads the Rust-owned public changelog GET API through a server function, hydrates the list with TanStack Query, applies ISR-style CDN headers, and falls back to an empty public state when the backend cannot return published entries. |
/:locale/changelog/:slug | apps/tanstack-web TanStack Start route | route-overrides.json marks the changelog detail page migrated; the Start route reads the Rust-owned public changelog slug GET API through a server function, hydrates the entry with TanStack Query, reuses the public changelog list for adjacent navigation, applies ISR-style CDN headers, and throws the TanStack not-found response when the slug is missing. No-auth coverage uses a deterministic missing-slug 404 example so empty databases remain valid. |
/:locale/:wsId/changelog | apps/tanstack-web TanStack Start dynamic route | route-overrides.json marks the dashboard changelog page artifact migrated; the Start route preserves fail-closed current-user auth, forwarded workspace resolution, dashboard card/list parity, public changelog links, and TanStack Query loading through the Rust-owned changelog list API instead of direct Supabase reads. |
/:locale/:wsId/infrastructure/changelog | apps/tanstack-web TanStack Start dynamic route | route-overrides.json marks the infrastructure changelog admin list page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, manage_changelog settings redirect parity, URL search filters, TanStack Query hydration, legacy table columns/actions, and Rust-backed changelog list loading instead of direct service-role Supabase reads. New/edit pages and media upload remain separately tracked. |
/tools/random, /:locale/tools/random | apps/tanstack-web TanStack Start route loaders | The Start routes preserve the current web proxy contract by redirecting to apps/tools /random and forwarding the raw query string. The generator UI is owned by the tools satellite, not the platform shell. |
/:locale/branding, /blog, and /careers | apps/tanstack-web TanStack Start static routes | route-overrides.json marks the visible marketing pages and metadata-only layouts migrated; the Start routes preserve the static brand, blog placeholder, and careers content without auth, Supabase, or protected workspace data access. Branding Open Graph/Twitter image artifacts remain legacy-owned. |
/:locale/facebook-mockup | apps/tanstack-web TanStack Start client route | route-overrides.json marks the page migrated; the Start route preserves the public Facebook mockup demo with local browser-safe components and no auth, Supabase, or protected workspace data access. |
/:locale/security | apps/tanstack-web TanStack Start static route | route-overrides.json marks the security landing page and metadata-only layout migrated; the Start route preserves the legacy static security copy, vulnerability-reporting CTAs, trust sections, and local primitives without framer-motion, Next.js APIs, auth, Supabase, or protected workspace data access. |
/:locale/security/policy and /bug-bounty | apps/tanstack-web TanStack Start static routes | route-overrides.json marks the security policy page, Security Hall of Fame page, and bug-bounty metadata-only layout migrated; the Start routes preserve the legacy responsible-disclosure and researcher-credit copy with local security primitives and no auth, Supabase, or protected workspace data access. |
/:locale/solutions/construction, /education, /healthcare, /hospitality, /manufacturing, /pharmacies, /realestate, /restaurants, and /retail | apps/tanstack-web TanStack Start static routes | route-overrides.json marks every static solution page and layout migrated; the Start routes preserve legacy copy, metadata, FAQ content, CTAs, success metrics, and local solution primitives without framer-motion, Next.js APIs, auth, Supabase, or protected workspace data access. |
/:locale/ui, /:locale/ui/setup, /:locale/ui/contributing, /:locale/ui/components, /:locale/ui/components/:componentId | apps/tanstack-web TanStack Start static routes | route-overrides.json marks the public UI showcase layout and pages migrated; the Start routes preserve the UI docs shell, setup/contribution pages, component index, and component detail views through local registry/docs data without auth, Supabase, or protected workspace data access. |
/:locale/visualizations/horse-racing | apps/tanstack-web TanStack Start client route | route-overrides.json marks the page migrated; the Start route preserves the public horse-racing algorithm visualization with local TanStack-safe visualization components and no auth, Supabase, or protected workspace data access. |
/:locale/verify-token | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page migrated; the Start route preserves the legacy nextUrl redirect sanitizer and /onboarding fallback without importing Next auth/session runtime into the Cloudflare-compatible frontend. |
/:locale/shared/user-profile/:code | apps/tanstack-web TanStack Start route | route-overrides.json marks the page artifact migrated; the Start route preserves the legacy noindex head, profile-link loader, fail-closed auth redirect for protected links, unavailable shell for expired/revoked links, localized fill form, and allowlist-scoped prefill behavior. Submit/avatar APIs still route through packages/internal-api and remain separate backend migration work. |
/:locale/shared/task/:shareCode | apps/tanstack-web TanStack Start route | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user resolution before task data fetch, the legacy login redirect with nextUrl, noindex metadata, unavailable shell for revoked links, and shared task dialog rendering. /api/v1/shared/tasks/:shareCode remains legacy-owned backend work. |
/:locale/shared/task-boards/:code | apps/tanstack-web TanStack Start dynamic route | route-overrides.json marks the page artifact migrated; the Start route preserves noindex metadata, unavailable-shell behavior for missing or revoked public board links, no-store loading through the packages/internal-api public board facade, and read-only public BoardViews rendering through TanStack-local payload adapters. /api/v1/shared/task-boards/:code remains legacy-owned backend work. |
/:locale/:wsId/finance route layout plus /:locale/:wsId/finance and /:locale/:wsId/finance/{analytics,budgets,categories,debts,debts/:debtId,invoices,invoices/:invoiceId,invoices/new,recurring,tags,transactions,transactions/:transactionId,wallets,wallets/:walletId} | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks the Finance route-specific layout and page artifacts migrated; the Start routes preserve the accepted 307 redirects to the platform Finance paths and forward raw query strings so creation/search/pagination handoff parameters survive. Dynamic finance IDs are encoded before handoff. The legacy Finance layout’s command/provider UI is not rendered in TanStack because these migrated leaves redirect; parent dashboard/session and Finance data ownership remain legacy-owned until workspace provider parity is complete. |
/:locale/:wsId/mail route layout plus /:locale/:wsId/mail and /:locale/:wsId/mail/sent pages | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks the Mail leaf pages migrated and the legacy route-specific Mail layout accepted-removal; the Start leaves preserve 307 handoff to the standalone Mail app through buildMailRedirectHref, while the Mail app centralized auth proxy and workspace-normalization boundary replace the legacy dashboard layout gate. Parent dashboard/session ownership remains legacy-owned until workspace provider parity is complete. |
/:locale/:wsId/workforce, /ai-chat/new, /meet, /qr-generator, /drive, education library/builder pages, /epm, and /external-projects | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks these page artifacts migrated; the Start routes preserve the legacy 307/308 redirects to workspace user database, chat, meet plans, QR app with query forwarding, Drive app handoff with workspace slug normalization, education library/builder, and CMS app destinations. Parent dashboard layout/session ownership remains legacy-owned until workspace provider parity is complete. |
/:locale/:wsId/education/valsea | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, full workspace resolution, localized education metadata/header content, and the shared ValseaClassroomClient. Parent dashboard/session ownership and the Valsea audio/processing APIs remain separately tracked backend work. |
/:locale/:wsId/education/quiz-sets/:setId | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, quiz table search/pagination with the legacy 10-row default, forwarded-auth internal-api quiz reads, and TanStack Query-backed create/update/delete plus AI explanation actions. The quiz-set detail layout and quiz APIs remain separately tracked. |
/:locale/:wsId/education/quiz-sets/:setId/linked-modules | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, linked course module table parity, and link/unlink workflow through forwarded-auth internal-api facades backed by Rust-owned education read endpoints. Parent dashboard/session ownership remains legacy-owned. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/content | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, forwarded internal-api module reads, localized module content summary, and TanStack Query/internal-api-backed debounced content saves. The parent module layout and module API ownership remain separately tracked. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/quizzes | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, the legacy update_user_groups not-found gate before data loading, URL-backed quiz search/pagination, and forwarded-auth internal-api quiz reads plus shared quiz table edit/delete actions. Quiz API and AI quiz-generation backend ownership remain separately tracked. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/quizzes/new | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, localized manual quiz creation shell, and TanStack Query-backed submission through the internal-api quiz facade. Quiz create/update API ownership and the module quiz list page remain separately tracked. |
/:locale/:wsId/hive route layout | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks the route-specific layout artifact migrated; the migrated Hive leaves redirect to the standalone Hive app, while the legacy layout only imported @xyflow/react styles and returned children. Hive APIs and parent dashboard/session ownership remain legacy-owned. |
/:locale/:wsId/mind/boards/:boardId route layout | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the route-specific layout artifact migrated; the migrated Mind board page redirects to the standalone Mind board route with query forwarding, while the legacy layout only imported @xyflow/react styles and returned children. Mind APIs and parent dashboard/session ownership remain legacy-owned. |
/:locale/:wsId/documents/:documentId route layout | apps/tanstack-web TanStack Start metadata | route-overrides.json marks the static Document Details metadata layout artifact migrated; the legacy layout only exported title/description metadata and returned children. The document detail page, workspace dashboard/session ownership, and document data/API routes remain legacy-owned. |
/:locale/:wsId/infrastructure and /:locale/:wsId/platform parent layouts | apps/tanstack-web TanStack Start parent loaders | route-overrides.json marks both layout artifacts migrated; the Start parent routes preserve fail-closed current-user auth, workspace resolution, root view_infrastructure permission gating, and Outlet rendering for migrated children. The exact infrastructure analytics page, platform billing, platform roles, and remaining settings children stay separately tracked as legacy-next artifacts. |
/:locale/:wsId/epm/collections/:collectionId, /epm/entries/:entryId, /platform/external-projects, and /users/topic-announcements | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks these page artifacts migrated; the Start routes preserve the legacy 307 redirects to CMS collection/entry/admin destinations and legacy dashboard aliases. Infrastructure settings/app-coordination routes now live in apps/infrastructure and the old TanStack/web route is recorded as an accepted removal. Parent dashboard layout/session ownership remains legacy-owned until workspace provider parity is complete. |
/:locale/:wsId/ai-chat/chatbots | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, ai_chat permission gating, route metadata, and localized FeatureSummary content. The create action intentionally targets the canonical /:locale/:wsId/ai-chat/my-chatbots/new Start route instead of the legacy /:wsId/chat alias. Parent dashboard and AI chat session/provider ownership remains legacy-owned. |
/:locale/:wsId/ai-chat/my-chatbots | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, the legacy ai_chat layout permission gate, URL-backed table search/pagination, forwarded-auth group-tag reads, internal-api-backed row deletion, and localized FeatureSummary/CustomDataTable UI. Parent dashboard and AI chat session/provider ownership remains legacy-owned. |
/:locale/:wsId/ai-chat/my-chatbots/new | apps/tanstack-web TanStack Start client route | route-overrides.json marks the static metadata layout and client-only form page migrated; the Start route preserves the local validation, localized summary strings, and submit toast behavior without adding protected API, Supabase, or server-action access. Parent dashboard and AI chat session/provider ownership remains legacy-owned. |
/:locale/:wsId/users/group-tags | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, URL-backed table search/pagination, forwarded-auth group-tag reads, internal-api-backed group-tag mutations/row actions, localized FeatureSummary/CustomDataTable UI, and locale-prefixed detail hrefs. Group-tag API ownership remains separately tracked for the backend Rust wave. |
/:locale/:wsId/users/group-tags/:tagId | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the dynamic no-store Start route preserves fail-closed current-user auth, workspace resolution, URL-backed linked-group search/pagination, forwarded-auth tag detail and linked-group reads, TanStack Query-backed add/remove linked-group actions, localized FeatureSummary/CustomDataTable UI, and locale-prefixed group detail hrefs. Group-tag API ownership remains separately tracked for the backend Rust wave. |
/:locale/:wsId/settings/reports | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, manage_user_report_templates gating, URL-backed q search state, report and lead-generation template tables, preview panels, and edit/reset actions through TanStack Query server functions plus packages/internal-api workspace-config facades. |
/:locale/:wsId/settings/notifications | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, workspace resolution, account notification status, workspace-wide enable/disable, browser permission controls, and editable event/channel preferences through TanStack Query server functions plus packages/internal-api notification preference facades. Notification preference API artifacts remain separately tracked Rust backend work. |
/:locale/:wsId/billing/success | apps/pay satellite app via TanStack redirect | route-overrides.json marks the legacy success page as a satellite-app accepted replacement; the Start route issues a 307 to Pay and preserves the complete query string, including checkoutId. Checkout result rendering and payment reads remain Pay-owned. |
/:locale/:wsId/inventory | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the root inventory dashboard page artifact migrated; the Start route preserves fail-closed current-user auth, forwarded-auth workspace resolution, view_inventory permission handling, localized access-denied state, statistic-card loading/error states, and inventory statistics loaded through the internal-api facade. /api/v1/workspaces/:wsId/inventory/statistics and deeper inventory pages remain separately tracked. |
/:locale/:wsId/inventory/batches | apps/tanstack-web TanStack Start dynamic route | route-overrides.json marks the inventory batches page artifact migrated; the Start route preserves fail-closed current-user auth, forwarded-auth workspace resolution, view_inventory permission handling, localized access-denied state, URL-backed q/page/pageSize search state, and TanStack Query table loading through the internal-api inventory facade. /api/v1/workspaces/:wsId/inventory/batches remains separately tracked backend work. |
/:locale/:wsId/inventory/categories, /manufacturers, /suppliers, /units, and /warehouses | apps/tanstack-web TanStack Start dynamic routes | route-overrides.json marks these inventory resource page artifacts migrated; the Start routes preserve fail-closed current-user auth, forwarded-auth workspace resolution, inventory view/create/update/delete or catalog/setup permission booleans, localized access-denied states, URL-backed q/page/pageSize table state, and TanStack Query table loading plus create/update/delete actions through the internal-api inventory facades. The matching workspace inventory and product compatibility APIs remain separately tracked backend work. |
/:locale/:wsId/inventory/products and /:productId | apps/tanstack-web TanStack Start dynamic routes | route-overrides.json marks the inventory product list and product detail/new form page artifacts migrated; the Start routes preserve fail-closed auth, workspace resolution, inventory and stock permission parity, route metadata, localized access-denied state, and TanStack Query product list/form loading plus mutations through internal-api inventory facades. Workspace inventory product APIs remain separately tracked backend work. |
/:locale/:wsId/inventory/promotions | apps/tanstack-web TanStack Start dynamic route | route-overrides.json marks the inventory promotions page artifact migrated; the Start route preserves fail-closed auth, workspace resolution, inventory view/create/update/delete permission context, route metadata, and TanStack Query CRUD through internal-api promotion facades. Workspace promotion API routes remain separately tracked backend work. |
/:locale/:wsId/inventory/storefronts | apps/tanstack-web TanStack Start dynamic route | route-overrides.json marks the inventory storefronts page artifact migrated; the Start route preserves fail-closed auth, workspace resolution, inventory catalog permission parity, route metadata, localized access-denied state, and TanStack Query reads/mutations through internal-api inventory storefront facades. Workspace storefront, listing, option-template, product, and public storefront APIs remain separately tracked backend work. |
/:locale/:wsId/members | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the workspace members page artifact migrated; the Start route preserves fail-closed auth, workspace resolution, personal-workspace/settings redirect, manage_workspace_members and manage_workspace_roles context, tab search validation, metadata, and the shared workspace-access client. disableInvite currently defaults to false until a Rust/internal-api workspace secret reader lands for DISABLE_INVITE; invite-link creation remains protected by the existing server API check. |
/:locale/:wsId/tasks plus task cycles, estimates, initiatives, labels, logs, notes, projects, templates, and template marketplace pages | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks these page artifacts migrated; the Start routes preserve authenticated workspace resolution, route metadata, and shared task UI clients. Project/cycle/initiative/log/template/estimate/label routes keep the legacy manage_projects permission gate through the forwarded-auth internal permission check, while the project/template detail routes load their initial data through forwarded-auth internal-api facades. Parent dashboard/session and remaining task data APIs remain separately owned. |
/:locale/:wsId/tasks/boards and /:locale/:wsId/tasks/boards/:boardId | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks both page artifacts migrated; the Start routes preserve authenticated board index/detail shells through shared task-board UI, the next/navigation runtime shim, forwarded-auth board authorization, legacy not-found mapping, and member/guest board access handling. The detail page omits the legacy Mira idle chat island until its local Next.js API/UI dependencies move behind shared TanStack/Rust facades. |
/:locale/:wsId/calendar, /chat, /cron, and /memories | apps/tanstack-web TanStack Start route loaders | route-overrides.json marks these page artifacts migrated; the Start routes preserve authenticated workspace shells, route metadata, and legacy permission gates (manage_calendar, view_chat, or ai_lab) through forwarded-auth internal permission checks. Calendar/chat clients self-load through existing facades, while cron and memories keep data-free shared headers until app-local data clients move behind shared internal-api/Rust facades. |
/:locale/:wsId/users/tutoring | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, forwarded-auth full workspace resolution, personal-workspace and view_user_groups not-found handling, update_user_groups_scores management context, route metadata, and the shared tutoring client. Tutoring backing APIs remain separately tracked Rust migration work. |
/:locale/:wsId/polls | apps/tanstack-web TanStack Start static route | route-overrides.json marks the page artifact migrated; the Start route preserves the legacy mock polls dashboard with local English/Vietnamese message bundles and shared UI primitives, without adding auth, Supabase, protected API, or server-action access. Parent dashboard layout/session ownership remains legacy-owned. |
/:locale/:wsId/users/structure | apps/tanstack-web TanStack Start static route | route-overrides.json marks the page artifact migrated; the Start route ports the legacy local-state organizational-structure mock page, metadata, message bundle keys, canvas interactions, profile/details panel, and management dialogs without adding Supabase, protected API, or server-action access. Parent dashboard layout/session ownership remains legacy-owned. |
/:locale/:wsId/users/feedbacks | apps/tanstack-web TanStack Start route loader | route-overrides.json marks the page artifact migrated; the Start route preserves fail-closed current-user auth, full workspace resolution, personal-workspace and view_user_groups not-found handling, update_user_groups_scores management context, route metadata, and the shared feedbacks client through internal-api user facades. Feedback data APIs remain separately tracked backend/internal-api work. |
/:locale error and not-found shells | apps/tanstack-web root route | route-overrides.json marks both artifacts migrated; the Start root route owns the legacy reset button, localized 404 copy, and onboarding link through route error/not-found components. |
/~offline page | apps/tanstack-web TanStack Start route | route-overrides.json marks the page migrated; the Start route renders the shared OfflinePage with the legacy title, message, and foreground/background classes. |
/~offline layout | apps/tanstack-web root document | route-overrides.json marks the layout migrated; the Start root document imports shared UI globals and applies the legacy scroll/background body classes without relying on Next.js font helpers. |
| Legacy artifact | Decision | Evidence |
|---|---|---|
apps/web/src/app/api/auth/me/session/route.ts | accepted-removal | The debug-style route returns raw sb-* auth cookie values plus the full Supabase session payload. No in-repo caller references /api/auth/me/session, and the TanStack/Rust cutover must not preserve raw session export behavior. |
apps/web/src/app/api/workspaces/[wsId]/categories/route.ts | accepted-removal | The file is zero bytes and exports no HTTP methods, so there is no runtime behavior to port. The override keeps the artifact visible and terminal instead of silently dropping it from the inventory. |
apps/web/src/app/api/v1/workspaces/[wsId]/encryption/migrate/route.ts | accepted-removal | The legacy route performs admin calendar-event encryption status reads and E2EE data writes. Rust owns a terminal 410 MIGRATION_DISABLED response with the original GET, POST allow list so cutover does not preserve broad migration writes. |
apps/web/src/app/api/v1/workspaces/[wsId]/storage/migrate/route.ts | accepted-removal | The legacy route mutates workspace storage providers after privileged permission checks. Rust owns a terminal 410 MIGRATION_DISABLED response with the original POST allow list; storage moves must use maintained runbooks or local backfills. |
apps/web/src/app/api/v2/workspaces/[wsId]/migrate/[module]/route.ts | accepted-removal | The legacy route exposes broad API-key migration exports backed by admin Supabase reads, private schemas, and RPCs. Rust owns a terminal 410 MIGRATION_DISABLED response with the original GET allow list instead of preserving this export surface. |
| Legacy route | Decision | Evidence |
|---|---|---|
GET /api/auth/me | migrated | Rust handle_backend_request revalidates the Supabase browser cookie or non-app-session Bearer token with Supabase Auth, preserves the raw legacy user payload, no-store headers, and unauthorized response. |
GET /api/auth/mfa/totp/assurance-level | migrated | Rust handle_backend_request revalidates the Supabase browser cookie or non-app-session Bearer token with Supabase Auth, then derives the no-argument Supabase MFA AAL payload from JWT claims and verified factors. |
GET / POST /api/auth/mfa/totp/factors | migrated | Rust handle_backend_request mirrors Auth JS factor listing from the revalidated Supabase user JSON and enrolls TOTP factors through Supabase Auth REST with QR-code normalization. |
GET / DELETE /api/auth/mfa/totp/factors/:factorId | migrated | Rust handle_backend_request resolves verified TOTP factor detail from the Auth JS-compatible list and unenrolls factors through Supabase Auth REST with the legacy success wrapper. |
GET /api/v1/workspaces/:wsId/posts/permissions | migrated | Rust handle_backend_request returns the legacy post approval/force-send flags through has_workspace_permission RPC checks, with missing auth or permission failures collapsed to false flags. |
GET /api/v1/workspaces/:wsId/Mention | migrated | Rust handle_backend_request returns the legacy singular email array after Supabase auth revalidation and exact MEMBER workspace membership, with caller-token workspace_users.email reads and legacy error bodies. |
GET /api/v1/workspaces/:wsId/habits/access | migrated | Rust handle_backend_request returns the legacy enabled habits access probe after Supabase auth revalidation, workspace normalization, service-role MEMBER validation, and exact ENABLE_HABITS=true secret matching. |
GET /api/v1/workspaces/:wsId/mobile/module-flags | migrated | Rust handle_backend_request returns the legacy sorted hiddenModuleIds payload after Supabase auth revalidation, caller-token workspace membership, and server-owned workspace_secrets mobile module flag reads. |
GET /api/v1/workspaces/:wsId/education/access | migrated | Rust handle_backend_request returns the legacy enabled education access probe after Supabase auth, getPermissions-compatible ai_lab checks, and server-owned workspace_secrets feature-flag reads, with workspace/secret/permission lookup failures collapsed to enabled: false. |
GET /api/v1/workspaces/:wsId/finance/budgets/status | migrated | Rust handle_backend_request accepts finance/platform app-session and CLI credentials before Supabase fallback, normalizes the workspace, checks manage_finance, calls get_budget_status with service-role auth, and returns the raw legacy payload/error bodies. |
GET /api/workspaces/:wsId/finance/charts/balance | migrated | Rust handle_backend_request accepts finance app-session, CLI, or Supabase credentials, normalizes the workspace, checks view_finance_stats, calls get_wallet_balance_at_date, and returns the legacy balance/date payload. |
GET /api/v1/workspaces/:wsId/finance/debts/summary | migrated | Rust handle_backend_request accepts finance app-session, CLI, or Supabase credentials, normalizes the workspace, checks manage_finance, calls private get_debt_loan_summary with _actor_id, and returns the first row or legacy zero summary. |
GET /api/v1/workspaces/:wsId/finance/filter-users | migrated | Rust handle_backend_request accepts finance app-session, CLI, or Supabase credentials, normalizes the workspace, checks view_transactions, returns legacy users filter rows, and preserves caller-token workspace user reads for normal sessions. |
GET /api/v1/workspaces/:wsId/finance/invoices/subscription/context | migrated | Rust handle_backend_request accepts finance app-session, CLI, or Supabase credentials, normalizes the workspace, checks create_invoices, validates requested student groups, and returns the legacy attendance plus latest paid invoice context. |
GET /api/v1/workspaces/:wsId/finance/recurring-transactions/upcoming | migrated | Rust handle_backend_request accepts finance app-session, CLI, or Supabase credentials, normalizes the workspace, checks view_transactions, preserves daysAhead parseInt behavior, and returns the legacy upcomingTransactions envelope. |
GET /api/v1/workspaces/:wsId/settings/permissions | migrated | Rust handle_backend_request mirrors the legacy getPermissions result for settings permission flags after Supabase auth revalidation and workspace membership/default/role permission resolution. |
GET /api/v1/workspaces/:wsId/settings/permissions/check | migrated | Rust handle_backend_request mirrors the legacy getPermissions(...).containsPermission(...) result after Supabase auth revalidation and workspace membership/default/role permission resolution. |
GET / PUT /api/v1/infrastructure/mobile-versions | migrated | Rust handle_backend_request revalidates the browser cookie or non-app-session Bearer token, requires root manage_workspace_roles, returns the legacy mobile policy snapshot, and upserts normalized mobile policy writes through the server-owned Supabase REST adapter. |
GET / POST /api/v1/infrastructure/timezones and PUT / DELETE /api/v1/infrastructure/timezones/:timezoneId | migrated | Rust handle_backend_request revalidates the browser cookie or non-app-session Bearer token, requires root manage_workspace_roles, reads and writes private.timezones with private-schema headers, normalizes legacy create/update payloads, omits missing/null create IDs for database UUID defaults, and preserves legacy success/error bodies. |
GET /api/v1/infrastructure/user-status-changes | migrated | Rust handle_backend_request forwards the caller’s Supabase token to PostgREST for workspace_user_status_changes, preserving RLS, required ws_id, parseInt-style range headers, exact count, and the legacy data/count body. |
GET /api/v1/infrastructure/users | migrated | Rust handle_backend_request forwards the caller’s Supabase token to PostgREST for workspace_users, preserving RLS, required ws_id, parseInt-style range headers, exact count, and the legacy data/count body. |
GET /api/v1/infrastructure/classes, /product-categories, and /score-names | migrated | Rust handle_backend_request uses the shared caller-token paginated export helper for workspace_user_groups, product_categories, and user_group_metrics, preserving RLS, exact count, and the legacy data/count bodies. |
GET /api/v1/infrastructure/lessons and /packages | migrated | Rust handle_backend_request preserves the no-auth private-schema lesson export and revalidates package callers before requiring view_inventory, while keeping exact-count pagination and the legacy data/count bodies. |
GET /api/v1/infrastructure/product-prices, /product-units, and /warehouses | migrated | Rust handle_backend_request accepts inventory app-session credentials or normal Supabase browser/Bearer credentials, requires inventory catalog/setup read permissions, and reads private inventory setup rows through the service-role Supabase REST adapter with exact-count pagination. Product prices scope through the workspace_products inner workspace filter. |
GET / POST /api/v1/infrastructure/ai/whitelist/domains and /emails | migrated | Rust handle_backend_request revalidates the Supabase browser session or non-app-session Bearer token, requires a @tuturuuu.com operator email, reads and inserts private whitelist rows through the service-role private-schema REST adapter, and preserves page/pageSize/q, created_at.desc ordering, exact-count pagination, Zod-style create validation messages, enabled defaults, 201 create wrappers, 403 denial bodies, and plain-text 500 bodies. |
PUT / DELETE /api/v1/infrastructure/ai/whitelist/:email and /domain/:domain | migrated | Rust handle_backend_request revalidates the same operator boundary as the list routes, decodes the path segment, patches/deletes matching private whitelist rows through the service-role private-schema REST adapter, applies legacy Boolean(enabled) update truthiness, and preserves the legacy success/error bodies. |
GET /api/v1/infrastructure/post-email-queue | migrated | Rust handle_backend_request revalidates the Supabase browser session or non-app-session Bearer token, requires root workspace membership, reads post_email_queue through the service-role Supabase REST adapter, preserves the legacy summary/workspace/recent-batch aggregation payload, and keeps workspace/batch breakdown failures non-fatal. |
GET /api/v1/infrastructure/bills, /roles, and /transaction-categories | migrated | Rust handle_backend_request uses the shared caller-token paginated export helper for finance_invoices, workspace_user_groups, and transaction_categories, preserving RLS, exact count, and the legacy data/count bodies. |
GET /api/v1/infrastructure/wallet-transactions | migrated | Rust handle_backend_request forwards the caller’s Supabase token to get_wallet_transactions_with_permissions, preserving the legacy RPC payload, raw rows, and first-row total_count envelope. |
GET /api/v1/infrastructure/abuse-intelligence | migrated | Rust handle_backend_request validates the Supabase browser session or Bearer token, requires root view_infrastructure, reads caller-scoped abuse reputation subjects, activity signals, and challenges, reads active overrides with service-role auth, and returns the legacy summary plus topRiskySubjects payload while leaving POST legacy-owned. |
GET /api/v1/infrastructure/abuse-events | migrated | Rust handle_backend_request validates the Supabase browser session or Bearer token, checks root workspace membership with the caller token, reads abuse_events with legacy filters and page/pageSize pagination, and returns the legacy pagination envelope. |
GET /api/v1/infrastructure/blocked-ips | migrated | Rust handle_backend_request validates the Supabase browser session or Bearer token, checks root workspace membership with the caller token, reads blocked_ips with legacy filters and page/pageSize pagination, and leaves POST/DELETE legacy-owned. |
GET /api/v1/infrastructure/suspensions | migrated | Rust handle_backend_request validates the Supabase browser session or Bearer token, requires root manage_workspace_roles, reads active user_suspensions rows through the service-role Supabase REST adapter, and leaves POST/detail DELETE legacy-owned. |
GET / POST /api/v1/infrastructure/email-blacklist and GET / PUT / DELETE /api/v1/infrastructure/email-blacklist/:entryId | migrated | Rust handle_backend_request validates the Supabase browser session or Bearer token, checks root workspace membership with the caller token, returns the legacy ordered collection/detail rows, writes with caller-token Supabase REST, preserves POST/PUT Zod-style validation bodies, maps duplicate creates to 409, and preserves detail update/delete prefetch/not-found behavior. |
GET /api/v1/infrastructure/bill-coupons, /bill-packages, /class-attendance, /class-members, /class-packages, /class-scores, /package-stock-changes, and /student-feedbacks | migrated | Rust handle_backend_request uses the shared caller-token paginated export helper with route-specific embedded select strings and related-table workspace filters while preserving exact count and the legacy data/count bodies. |
GET /api/v1/infrastructure/user-monthly-reports and /user-monthly-report-logs | migrated | Rust handle_backend_request requires manage_external_migrations, resolves workspace aliases through the shared permission helper, and reads the private monthly report views through private-schema Supabase REST with exact-count pagination. |
GET /api/v1/workspaces/:wsId/crawlers/status | migrated | Rust handle_backend_request preserves the legacy exact-URL crawler status lookup, raw Supabase row payloads, missing-URL validation, and crawledUrl: null fallback when no row exists. |
GET /api/v1/workspaces/:wsId/course-modules and GET /api/v1/workspaces/:wsId/quiz-sets/:setId/linked-modules | migrated | Rust handle_backend_request resolves education workspace access, requires ENABLE_EDUCATION, reads service-role course-module rows with exact-count pagination, and verifies linked quiz sets belong to the resolved workspace before listing linked modules. |
PATCH /api/v1/user/profile | migrated | Rust handle_backend_request validates browser Supabase auth, validates legacy profile fields, and updates only the authenticated user’s users row through the server-owned Supabase REST adapter. |
GET / PATCH /api/v1/users/me/default-workspace | migrated | Rust handle_backend_request resolves the authenticated user’s default workspace with the legacy personal-workspace/null fallback and updates default_workspace_id after caller-token membership validation. |
GET / PATCH /api/v1/users/calendar-settings | migrated | Rust handle_backend_request accepts calendar app-session tokens or revalidated browser Supabase sessions, reads and updates the authenticated user’s calendar settings in user_private_details, defaults missing values to auto, and preserves legacy patch validation/cache behavior. |
GET /api/v1/users/me/identities | migrated | Rust handle_backend_request revalidates browser Supabase auth, reads the raw Supabase Auth user JSON, returns the legacy linked identities list plus canUnlink, and preserves the private cache directive. |
PATCH /api/v1/users/me/full-name | migrated | Rust handle_backend_request validates browser Supabase auth, validates the required trimmed full_name, and upserts user_private_details for the authenticated user with the caller token. |
GET /api/cron/discord/daily-report | migrated | Rust handle_backend_request proxies to DISCORD_APP_DEPLOYMENT_URL/daily-report with cron bearer auth, upstream status/body passthrough, invalid-JSON fallback, OpenAPI coverage, and native/Worker outbound support. |
GET /api/cron/discord/wol/daily/remind | migrated | Rust handle_backend_request reuses the same proxy contract for DISCORD_APP_DEPLOYMENT_URL/wol-reminder with route tests and Cloudflare Worker config requirements for the cron secret and Discord app deployment URL. |
| Legacy route | Status | Evidence |
|---|---|---|
/:locale/add-account | migrated | Dynamic no-store TanStack Start route /$locale/add-account is registered in routeTree.gen.ts, preserves the legacy account-switcher add-account handoff, carries returnUrl through TanStack Router search validation, renders localized loading/success/error states, and persists the current session through a TanStack Query mutation backed by @tuturuuu/internal-api auth helpers instead of Next navigation or raw protected API calls. |
/:locale/:wsId/habits | migrated | TanStack Start route /$locale/$wsId/habits is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, checks the Rust-owned /api/v1/workspaces/:wsId/habits/access feature probe, and renders the shared HabitsClientPage. |
/:locale/:wsId/posts | migrated | TanStack Start route /$locale/$wsId/posts is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves pass-through URL search state for the shared posts client, and uses internal-api facades including the Rust-owned posts permission probe. |
/:locale/:wsId/crawlers | migrated | TanStack Start route /$locale/$wsId/crawlers is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves legacy ai_lab gating, carries URL page/pageSize/domain/search state through TanStack Router, and renders a read-only crawled URL table plus uncrawled/domain stats through Rust-owned crawler backend facades. |
/:locale/:wsId/crawlers/uncrawled | migrated | TanStack Start route /$locale/$wsId/crawlers/uncrawled is registered in routeTree.gen.ts, uses the same authenticated workspace and ai_lab gate, carries URL filters through TanStack Router, and renders grouped read-only uncrawled URLs through the Rust-owned crawler backend facades while leaving crawl-trigger mutations out of scope. |
/:locale/:wsId/pipelines | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/pipelines is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves legacy ai_lab gating, carries URL page/pageSize/domain/search state through TanStack Router, and renders the crawler-backed read-only list through Rust-owned crawler backend facades. Legacy crawler create/update actions remain separately tracked. |
/:locale/:wsId/queues | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/queues is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves legacy ai_lab gating, carries URL page/pageSize/domain/search state through TanStack Router, and renders the crawler-backed read-only list through Rust-owned crawler backend facades. Legacy crawler create/update actions remain separately tracked. |
/:locale/:wsId/cron layout | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/cron preserves the legacy cron route-specific layout gate by requiring current-user auth, resolving the workspace, enforcing ai_lab, and rendering exact-match Overview, Cron jobs, and Executions tabs. Child cron pages stay separately tracked until their tables and mutations move behind internal-api or Rust facades. |
/:locale/:wsId/cron/jobs | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/cron/jobs is registered in routeTree.gen.ts, duplicates fail-closed current-user/workspace/ai_lab gates before loading protected data, carries q, page, and pageSize through TanStack Router search state, and renders the cron job list through a typed internal-api facade instead of direct Supabase reads or raw browser /api fetches. Create, edit, delete, next-run calculation, and job detail navigation remain separately tracked until dataset readers, mutation flows, and /:locale/:wsId/cron/jobs/:jobId move behind internal-api or Rust facades. |
/:locale/:wsId/documents | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/documents is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy manage_documents permission gate, and renders the workspace document list/create/delete flow through TanStack Query plus the typed documents internal-api facade. Document editor mutations and workspace document APIs remain separately tracked. |
/:locale/:wsId/documents/:documentId | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/documents/$documentId is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy manage_documents permission gate, loads the protected document row through the typed documents internal-api facade with forwarded request auth, and renders document metadata plus a read-only rich-text preview. Document edit/share/delete/autosave behavior and workspace document APIs remain separately tracked. |
/:locale/:wsId/infrastructure/abuse-events | migrated | TanStack Start route /$locale/$wsId/infrastructure/abuse-events is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves view_infrastructure not-found gating, carries URL search filters through TanStack Router, and loads rows through the Rust-owned abuse-events backend facade. |
/:locale/:wsId/infrastructure/abuse-intelligence | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/abuse-intelligence is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy root-workspace redirect boundary, requires root view_infrastructure, and renders shared TanStack Query/internal-api-backed reputation subject, signal, and trust override controls. Abuse Intelligence mutation APIs remain separately tracked. |
/:locale/:wsId/infrastructure/app-coordination | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/app-coordination is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy root-workspace redirect boundary, accepts root manage_workspace_secrets or manage_workspace_roles, and renders shared TanStack Query/internal-api-backed app-session policy controls. App Coordination APIs remain separately tracked. |
/:locale/:wsId/infrastructure/blocked-ips | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/blocked-ips is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves root and workspace view_infrastructure not-found gating, carries URL search/status/pagination filters through TanStack Router, and renders localized block/unblock controls through typed internal-api facades instead of direct Supabase reads or raw client /api fetches. Blocked IP APIs remain separately tracked. |
/:locale/:wsId/infrastructure/realtime | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/realtime is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace alias, preserves root and workspace view_infrastructure not-found gating, and renders the realtime analytics TanStack Query surface through createServerFn wrappers plus typed internal-api facades instead of raw protected /api fetches. Realtime analytics API artifacts remain separately tracked backend migration work. |
/:locale/:wsId/infrastructure/external-apps | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/external-apps is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy root-workspace redirect boundary, accepts root manage_workspace_secrets or manage_workspace_roles, and renders shared TanStack Query/internal-api-backed external app registration and secret rotation controls. External Apps APIs remain separately tracked. |
/:locale/:wsId/infrastructure/github-bot | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/github-bot is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy root-workspace redirect boundary, requires root manage_workspace_secrets, loads the initial GitHub Bot state through forwarded internal-api auth, and renders localized TanStack Query/internal-api-backed configuration, validation, watcher client, and audit controls. GitHub Bot APIs remain separately tracked. |
/:locale/:wsId/infrastructure/ai/whitelist/{domains,emails} | migrated | TanStack Start routes /$locale/$wsId/infrastructure/ai/whitelist/domains and /emails are registered in routeTree.gen.ts, gate anonymous users through requireCurrentUser, preserve the @tuturuuu.com operator not-found boundary plus root view_infrastructure gating, carry URL pagination/search through TanStack Router, and load/mutate rows through the Rust-owned AI whitelist internal-api facade. |
/:locale/:wsId/infrastructure/mobile-versions | migrated | TanStack Start route /$locale/$wsId/infrastructure/mobile-versions is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, preserves the legacy root-workspace redirect boundary, requires root manage_workspace_roles, loads policies through the Rust-owned mobile-versions internal-api facade, and saves updates through TanStack Query mutations. |
/:locale/:wsId/infrastructure/mobile-deployment | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/mobile-deployment is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy root-workspace redirect boundary, requires root manage_mobile_deployment_vault, loads the initial vault state through forwarded internal-api auth, and renders localized secret, file, activation, rollback, and CI token controls through TanStack Query/internal-api facades. Mobile Deployment APIs remain separately tracked. |
/:locale/:wsId/infrastructure/monitoring/stress-tests | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/monitoring/stress-tests is registered under the TanStack monitoring layout in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy root-workspace redirect boundary and root view_infrastructure not-found gate, renders the localized monitoring hero/section navigation, and uses TanStack Query/internal-api facades for stress-test snapshots, queue, abort, run detail polling, metrics, and history. Stress-test APIs remain separately tracked. |
/:locale/:wsId/infrastructure/monitoring/cron | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/monitoring/cron is registered under the TanStack monitoring layout in routeTree.gen.ts, relies on the parent current-user, root-workspace redirect, and root view_infrastructure gates, and uses TanStack Query/internal-api facades for cron snapshots, execution archives, manual run queueing, control toggles, and console-log detail. Cron APIs remain separately tracked. |
/:locale/:wsId/infrastructure/monitoring/requests | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/monitoring/requests is registered under the TanStack monitoring layout in routeTree.gen.ts, relies on the parent current-user, root-workspace redirect, and root view_infrastructure gates, and uses TanStack Query/internal-api facades for retained request archives, status/route/render/traffic filters, pagination, deployment context, and request inspection. Request archive APIs remain separately tracked. |
/:locale/:wsId/infrastructure/monitoring/watcher-logs | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/monitoring/watcher-logs is registered under the TanStack monitoring layout in routeTree.gen.ts, relies on the parent current-user, root-workspace redirect, and root view_infrastructure gates, and uses TanStack Query/internal-api facades for watcher snapshots, deployment scope/level/rollout status filters, pagination, commit context, and log detail inspection. Watcher-log APIs remain separately tracked. |
/:locale/:wsId/infrastructure/monitoring/rollouts | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/monitoring/rollouts is registered under the TanStack monitoring layout in routeTree.gen.ts, relies on the parent current-user, root-workspace redirect, and root view_infrastructure gates, and uses TanStack Query/internal-api facades for rollout summaries, deployment stage panels, standby sync controls, deployment pin controls, watcher event streams, and deployment history. Rollout mutation APIs remain separately tracked. |
/:locale/:wsId/infrastructure/monitoring{,/analytics,/deployments,/logs,/observability,/projects,/resources} | migrated | Dynamic no-store TanStack Start routes are registered under the TanStack monitoring layout in routeTree.gen.ts, rely on the parent current-user, root-workspace redirect, and root view_infrastructure gates, and render the observability overview, analytics, deployment history, grouped logs, health signals, project controls, and resource inventory through TanStack Query/internal-api facades. Project deletion and deeper observability API ownership remain separately tracked follow-ups. |
/:locale/:wsId/infrastructure/timezones | migrated | TanStack Start route /$locale/$wsId/infrastructure/timezones is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, preserves the legacy root-workspace redirect boundary, requires root manage_workspace_roles, overlays Rust-owned persisted timezone rows onto the bundled timezone catalog, and performs create/update/delete sync mutations through the backend timezones facade. |
/:locale/:wsId/infrastructure/holidays | migrated | TanStack Start route /$locale/$wsId/infrastructure/holidays is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, preserves the legacy root-workspace redirect boundary, requires root manage_workspace_roles, carries the year filter through TanStack Router search state, and performs list/create/update/delete/bulk-import work through the Rust-owned holidays backend facade. |
/:locale/:wsId/infrastructure/email-blacklist | migrated | TanStack Start route /$locale/$wsId/infrastructure/email-blacklist is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves view_infrastructure not-found gating, carries URL search/type/pagination filters through TanStack Router, and loads/mutates rows through the Rust-owned email blacklist backend facade. |
/:locale/:wsId/infrastructure/email-templates | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/email-templates is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves root and workspace view_infrastructure not-found gating, and renders the localized React Email template selector, property editor, server-function preview renderer, dark-mode simulation, and iframe HTML preview without raw /api fetches or Supabase reads. |
/:locale/:wsId/infrastructure/rate-limits | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/rate-limits is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy root-workspace redirect boundary, requires root view_infrastructure, forwards manage_workspace_roles as can-manage state, and renders the shared TanStack Query/internal-api-backed protection toggles, rate-limit rule, live-usage, and workspace-secret controls. Rate-limit APIs remain separately tracked. |
/:locale/:wsId/infrastructure/post-email-queue | migrated | TanStack Start route /$locale/$wsId/infrastructure/post-email-queue is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves view_infrastructure not-found gating, and renders the read-only queue summary, workspace breakdown, and recent batches through the Rust-owned post-email-queue backend facade while leaving the legacy cron trigger out of scope. |
/:locale/:wsId/education | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, and renders the legacy education overview shell with forwarded-auth internal-api counts for courses, flashcards, and quizzes. Education list APIs remain separately tracked. |
/:locale/:wsId/education/library/flashcards | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/library/flashcards is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries q/page/pageSize search state through TanStack Router, and renders the legacy flashcard library table through forwarded internal-api auth plus shared TanStack Query-backed create/update/delete components. Flashcard API ownership remains separately tracked. |
/:locale/:wsId/education/library/quizzes | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/library/quizzes is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries q/page/pageSize search state through TanStack Router with the legacy 10-row default, and renders the legacy quiz library table through forwarded internal-api auth plus shared TanStack Query-backed create/update/delete components and AI explanation generation. Quiz API ownership remains separately tracked. |
/:locale/:wsId/education/library/quiz-sets | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/library/quiz-sets is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries q/page/pageSize search state through TanStack Router with the legacy 10-row default, and renders the legacy quiz-set library table through forwarded internal-api auth plus linked course/module label hydration and shared TanStack Query-backed create/update/delete components. Quiz-set and linked-module API ownership remains separately tracked. |
/:locale/:wsId/education/attempts | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/attempts is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy view_user_groups_reports not-found gate, carries filter/sort/page/pageSize search state through TanStack Router, and renders the legacy attempts review table through forwarded internal-api auth with learner and quiz-set metadata. Attempts APIs remain separately tracked. |
/:locale/:wsId/education/attempts/:attemptId | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/attempts/$attemptId is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the view_user_groups_reports not-found gate used by the list/API, and renders the legacy attempt detail header, learner card, KPI strip, and per-question answer correctness cards through forwarded internal-api auth. Attempts APIs remain separately tracked. |
/:locale/:wsId/education/courses | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/courses is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries q/page/pageSize/view search state through TanStack Router, and renders the legacy course card/table page through forwarded internal-api auth plus shared CourseCardView, CoursePagination, CustomDataTable, and internal-api-backed create/edit/delete actions. Course API ownership and course builder remain separately tracked. |
/:locale/:wsId/education/quiz-sets/:setId | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/quiz-sets/$setId is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries q/page/pageSize search state through TanStack Router with the legacy 10-row default, and renders the legacy quiz-set quiz table through forwarded internal-api auth plus shared TanStack Query-backed create/update/delete components and AI explanation generation. The exact /education/quiz-sets redirect is an index route so detail children are reachable; the quiz-set detail layout and quiz APIs remain separately tracked. |
/:locale/:wsId/ai-chat layout | migrated | Dynamic no-store TanStack Start parent route /$locale/$wsId/ai-chat wraps migrated AI chat child routes with fail-closed current-user auth, workspace resolution, the legacy ai_chat permission redirect, and localized New Chat, Chatbots, and My Chatbots tabs. The exact /ai-chat leaf deliberately remains not-found in TanStack until the legacy chat page is migrated; parent dashboard/session ownership also remains separately tracked. |
/:locale/:wsId/ai-chat/my-chatbots | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/ai-chat/my-chatbots is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy ai_chat permission gate, carries q/page/pageSize search state through TanStack Router, and renders the legacy My Chatbots table through forwarded internal-api auth plus internal-api-backed row deletion. Group-tag API ownership remains separately tracked. |
/:locale/:wsId/users/approvals | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/approvals is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the personal-workspace notice and approve reports/posts not-found gating, carries status/page/limit/groupId/userId/creatorId filter state through TanStack Router, and renders the shared approvals tabs through TanStack Query-backed reads and internal-api-backed approve/reject/unapprove mutations. Approval APIs remain separately tracked. |
/:locale/:wsId/users/group-tags | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/group-tags is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries q/page/pageSize search state through TanStack Router, and renders the legacy group-tag table through forwarded internal-api auth plus shared create/update/delete components and locale-prefixed detail hrefs. Group-tag API ownership remains separately tracked. |
/:locale/:wsId/users/group-tags/:tagId | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/group-tags/$tagId is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries q/page/pageSize search state through TanStack Router, and renders the legacy linked user-group table through forwarded internal-api auth plus TanStack Query-backed linked-group add/remove components. Group-tag API ownership remains separately tracked. |
/:locale/:wsId/users/topic-announcements/announcements | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/topic-announcements/announcements is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves personal-workspace not-found parity, enforces ENABLE_TOPIC_ANNOUNCEMENTS and manage_users, carries status/q/page search state through TanStack Router, and renders the legacy announcements composer/table with send-permission-aware create/send/schedule flows, attachment upload, live email preview, save-as-template, and typed topic-announcement internal-api contracts. |
/:locale/:wsId/users/topic-announcements/templates | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/topic-announcements/templates is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves personal-workspace not-found parity, enforces ENABLE_TOPIC_ANNOUNCEMENTS and manage_users, and renders the legacy templates CRUD page through TanStack Query plus typed topic-announcement and user-group internal-api facades. The exact parent redirect now only fires on /topic-announcements, so migrated child tabs can render. |
/:locale/:wsId/users/topic-announcements/contacts | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/topic-announcements/contacts is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves personal-workspace not-found parity, enforces ENABLE_TOPIC_ANNOUNCEMENTS and manage_users, and renders the legacy contacts table, create dialog, linked workspace-user selector, delete confirmation, and verification request action through TanStack Query plus typed topic-announcement and workspace-user internal-api facades. Verification controls stay hidden unless the caller has send_user_group_post_emails. |
/:locale/:wsId/users/topic-announcements/delivery | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/topic-announcements/delivery is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves personal-workspace not-found parity, enforces ENABLE_TOPIC_ANNOUNCEMENTS and manage_users, and renders the legacy read-only delivery history with forwarded-auth listTopicAnnouncements({ status: "sent" }) loader hydration, calendar timezone normalization, TanStack Query refreshes, sent-only defensive filtering, recipient summary chips, sent-at formatting, and empty-state compose handoff. Delivery does not require send_user_group_post_emails. |
/:locale/:wsId/users/topic-announcements/import | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/topic-announcements/import is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves personal-workspace not-found parity, enforces ENABLE_TOPIC_ANNOUNCEMENTS and manage_users, derives send_user_group_post_emails for create-and-send availability, and renders the legacy bulk import flow with client-only XLSX template download/first-sheet parsing, custom CSV/header alias parsing, editable spreadsheet grid, row validation/result summaries, and TanStack Query mutations through importTopicAnnouncements plus sendTopicAnnouncementsBulk. Rust backend ownership of the import and send-bulk API routes remains separately tracked. |
/:locale/:wsId/settings/reports | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/settings/reports is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves manage_user_report_templates permission gating, carries q search state through TanStack Router, and renders the legacy reports and lead-generation template tables plus previews through TanStack Query server functions and the shared workspace-config internal-api facade. |
/:locale/:wsId/users/groups/calendar | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/groups/calendar is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves manage-users/view-user-groups not-found gating, forwards update-user-groups schedule permission state, and renders the shared user-group session calendar through internal-api-backed session reads and mutations. User-group session APIs remain separately tracked. |
/:locale/:wsId/users/groups/:groupId/attendance | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/groups/$groupId/attendance is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves check_user_attendance not-found gating and update_user_attendance save gating, hydrates group/session/member/config/attendance data through forwarded internal-api auth, and renders the attendance calendar/session/member cards with TanStack Query-backed reads and saves. User-group attendance/member/config/session APIs remain separately tracked for the backend Rust wave. |
/:locale/:wsId/users/groups/:groupId/requests | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/groups/$groupId/requests is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves approve reports/posts not-found gating, and renders the shared group requests tabs through TanStack Query and internal-api-backed approval mutations. Parent group detail page and approval APIs remain separately tracked. |
/:locale/:wsId/users/groups/:groupId/schedule | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/users/groups/$groupId/schedule is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, loads the target group through forwarded internal-api auth, preserves update-user-groups schedule permission state, and renders the shared end-date dialog and user-group session calendar. Parent group detail page and schedule APIs remain separately tracked. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/content | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/courses/$courseId/modules/$moduleId/content is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, loads the requested module through forwarded internal-api auth, and renders the legacy rich-text module content editor with TanStack Query/internal-api-backed debounced saves. Parent module layout and module API ownership remain separately tracked. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/youtube-links | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/courses/$courseId/modules/$moduleId/youtube-links is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, loads the requested module through forwarded internal-api auth, and renders the legacy Youtube Links management page with shared form/delete/embed UI backed by strict internal-api mutations. Parent module layout and module API ownership remain separately tracked. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/quiz-sets | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/courses/$courseId/modules/$moduleId/quiz-sets is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries list search state through TanStack Router, and renders the legacy module quiz-set table through forwarded internal-api auth plus shared TanStack Query-backed create/update/delete components. Course-module quiz-set API ownership remains separately tracked. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/quizzes | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/courses/$courseId/modules/$moduleId/quizzes is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the legacy update_user_groups not-found gate before quiz reads, carries search state through TanStack Router, and renders the shared quiz table through forwarded internal-api auth. Quiz API and AI quiz-generation backend ownership remain separately tracked. |
/:locale/:wsId/education/courses/:courseId/modules/:moduleId/quizzes/new | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/education/courses/$courseId/modules/$moduleId/quizzes/new is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, renders the legacy manual quiz creation shell, and submits through the shared TanStack Query/internal-api quiz form before returning to the locale-prefixed module quizzes route. Quiz API ownership and the module quiz list page remain separately tracked. |
/:locale/logout | migrated | Dynamic TanStack Start route /$locale/logout is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, renders the legacy localized confirmation card with from copy, and logs out through the typed internal-api browser-session facade without raw protected app API or Supabase access in TanStack source. The underlying POST /api/auth/logout route remains legacy-owned until the auth backend wave. |
/:locale/:wsId/infrastructure/ai-agents | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/infrastructure/ai-agents is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, preserves the root-workspace and manage_workspace_secrets redirect gates, and renders the legacy AI Agents controls through forwarded internal-api auth plus shared TanStack Query-backed agent, channel, identity, secret, and external-thread actions. AI Agents APIs remain separately tracked for Rust backend ownership. |
/:locale/:wsId/notifications | migrated | Dynamic no-store TanStack Start route /$locale/$wsId/notifications is registered in routeTree.gen.ts, gates anonymous users through requireCurrentUser, resolves the workspace, carries tab/type/scope/priority/page/pageSize search state through TanStack Router, and renders the legacy read-only notifications inbox through forwarded internal-api auth. Mark read/unread, mark all read, delete, invite actions, metadata updates, realtime subscription behavior, and entity action links remain separately tracked follow-ups. |
| Legacy route | Blocker | Required design |
|---|---|---|
/:locale/meet and /:locale/meet-together | Public TanStack preview shells are available, but the legacy routes also load authenticated meeting plans and create plans through Next-only Supabase/server-action paths. | Add Rust-owned or TanStack server-function-backed plan list/create APIs, route them through packages/internal-api, preserve unauthenticated empty/login-required behavior, and add E2E evidence before adding the page:/:locale/meet or page:/:locale/meet-together overrides. |
/:locale/:wsId/usage | The wrapper is small, but the content fans out into many server-side workspace stats backed by Supabase RPCs, admin reads, storage provider helpers, and per-feature permission checks. | Create a Rust-owned workspace usage summary endpoint or a small set of typed server functions that return the same permission-masked stats, then render the dashboard through TanStack Query without direct Supabase reads. |
/:locale/:wsId/ai/spark, /:locale/:wsId/mira, and /:locale/:wsId/assistant | These look compact at the page file level, but their clients call AI object generation, Mira focus/task/calendar/pet APIs, live voice/audio helpers, or assistant multimodal providers that are still Next/API coupled. | Move each AI surface as a dedicated product lane with typed AI/Mira/assistant facades and focused browser evidence; avoid shell-only migrations that would expose incomplete AI behavior. |
/:locale/games/farm | The visible game page is client-only, but the legacy layout gates access through Supabase auth and isValidTuturuuuEmail(user?.email) before rendering. | Add a TanStack server gate that validates the session and email domain through server-owned auth helpers, then port the game UI without exposing it publicly. |
/:locale app-shell providers | The root route now centralizes locale validation, legacy root head metadata, html lang, theme bootstrapping, Query, and tooltip providers, but full legacy layout parity still includes next-intl, NuqsAdapter, theme-aware toasts, auth-backed version/DB badges, and service-worker runtime behavior. | Finish the provider/runtime contract in TanStack Start, decide which legacy badges and service-worker behaviors are accepted removals versus ports, then add route-level E2E or screenshot evidence before marking remaining localized layout artifacts terminal. |
/:locale/login | Login owns OAuth callback forwarding, Supabase session redirects, app-token confirmation, OTP/password/passkey/MFA flows, account switching, Turnstile state, and session hydration. | Complete the auth/session contract for TanStack Start and Rust, then port login as a dedicated auth milestone with focused E2E coverage. |
Frontend Runtime Adapters
TanStack route ports should use the adapter modules underapps/tanstack-web/src/lib/platform/ instead of rebuilding Next.js behavior in
each route:
| Adapter | Owns |
|---|---|
locale.ts | en / vi locale detection, NEXT_LOCALE, as-needed prefixes, and Accept-Language fallback. |
head.ts | TanStack-compatible metadata, canonical links, alternates, and stylesheet descriptors. |
theme.ts | The class-based system / light / dark theme boot script used by the root shell. |
navigation.ts | Typed redirect and not-found errors that can be converted to Response objects in loaders or server functions. |
session.ts | Sanitized auth/session hydration snapshots from request cookies without exposing token values to the browser. |
query.ts | Shared TanStack Query defaults and dehydration behavior for loader-prefetched data. |
app-shell.ts | Root locale validation, localized document language derivation, and legacy-compatible head descriptors. |
redirects.ts | Legacy-compatible redirect destinations for public, auth, dashboard alias, QR, Mail, CMS, CMS deep-link, and education routes. |
createPageHead, prefetch loader data through the shared QueryClient, and pass
only sanitized session state to client components.
Data And API Rules
- TanStack loaders and server functions may act as a BFF layer for SSR, cookies, headers, and query hydration.
- Product data reads/writes move to Rust-owned endpoints in
apps/backend. - Browser/shared UI code calls
packages/internal-apihelpers, not scattered raw API paths. - Protected data stays behind server-owned private/admin access. Do not expose private Supabase or protected workspace reads directly to browser code.
- Use TanStack Query for client fetching and mutation. Do not fetch data in
useEffect. bun checkrunsnode scripts/check-tanstack-api-access.jsto enforce thatapps/tanstack-web/srcdoes not call relative protected/api,/internal, or/trpcpaths directly and does not import or create Supabase clients. Run the focused command when reviewing a frontend port before the full repo check.
Backend Crate Structure And The 700-LOC Ceiling
Every source file in the repo — Rust included — must stay well-maintained and under a hard 700-LOC ceiling whenever possible (start splitting around ~400 LOC). Theapps/backend crate root was decomposed to honor this:
src/lib.rs(~680 LOC) is now just the module registry (mod <handler>;), the public types, andpub(crate) usere-exports.src/dispatch/holdshandle_backend_requestplus onedispatch_chunk_NN.rsper route-table chunk. New route arms append to adispatch_chunk_NN.rs; when a chunk approaches 700 LOC, add a freshchunk_NN.rsand wire it intodispatch/mod.rs. Each chunk doesuse crate::*;to reach crate-root helpers/types.- Cohesive helper families live in named submodules, each under 700 LOC:
types.rs,response.rs,runtime.rs,migration.rs,legacy_routes.rs,static_routes.rs,route_predicates.rs,config_env.rs,constants.rs,native.rs,worker_runtime.rs. Each is re-exported fromlib.rswithpub(crate) use <mod>::*;so existing call sites resolve unchanged. - The unit-test suite lives in
src/tests.rs(mod tests;), split by area so no test file crosses the ceiling.
src/<mod>.rs, header it with
use crate::*; (plus any external use serde…), give moved items pub(crate)
visibility, then add mod <mod>; pub(crate) use <mod>::*; to lib.rs. Keep a
struct and the functions that read its private fields in the same module so
fields only need pub(crate) where a cross-module reader (e.g. tests.rs)
requires it. Do not bulk-restructure lib.rs/dispatch/ while batches are
appending without a tmp/agent-coordination/ claim. See apps/backend/AGENTS.md
for the full rules.
No New Debt While The Switch Is Pending
Treatapps/web, apps/backend, and apps/tanstack-web as one system. The
migration runs in parallel with normal feature work, so any change that touches
only apps/web silently grows the backlog the cutover must clear. All future
work must keep the three surfaces consistent where applicable:
- New or changed
apps/webAPI route (any method). Ifapps/backendalready owns that path, port the same behavior change into the Rust handler in the same PR (match status codes, body shape, cache headers; migrate GET first and returnNonefor un-ported methods so they fall through). If it is not owned yet, register/refresh the route inapps/tanstack-web/migration/route-overrides.jsonand regenerate withbun migration:tanstack:manifest, so the new surface is tracked as backlog instead of invisible debt. Verify ownership with the runtime coverage probe inapps/backend/AGENTS.md(migrated method = COVER, un-ported = FRESH). - New or changed dashboard page/route. Mirror the manifest registration so
apps/tanstack-webtracking stays accurate, and route shared data access throughpackages/internal-api(consumed by both frontends) rather than app-local fetchers, so the eventual TanStack port is a move, not a rewrite. - Shared data access. Prefer adding a
packages/internal-apifacade over a one-offapps/webfetcher; the facade is the seam both the Next.js and TanStack frontends call, and it forwards to the Rust backend server-side. - Tracking, not blocking. You do not have to finish the Rust/TanStack port in
every PR, but you must leave the manifest accurate. A route that is added to
apps/weband not reflected in the manifest is the debt this migration exists to avoid.bun migration:tanstack:checkand the backend coverage probe are the guards.
Security And Test Requirements
Every migrated Rust endpoint needs the same ownership evidence before its manifest entry can move out oflegacy-next:
- a
route-overrides.jsonentry with a non-empty evidence note that marks the legacy artifact asmigratedoraccepted-removal - an OpenAPI path or schema update in
apps/backend/api/openapi.yaml - a Rust route dispatcher test covering the success case; full-route ownership also needs unsupported method behavior, while method-level ownership needs an assertion that still-legacy sibling methods are not claimed by Rust
- a
packages/internal-apifacade when the TanStack app or shared UI needs to call the endpoint
GET /api/v1/users/me/profile,
PATCH /api/v1/users/me/profile, and POST /api/v1/inquiries verify
ttr_app_ app-session JWTs, enforce same-origin mutation checks for cookie
auth, validate request bodies, call Supabase REST through the server-owned Rust
outbound adapter, and have mocked native/Worker persistence tests.
PATCH /api/v1/users/me/full-name separately revalidates the browser Supabase
session, validates the required trimmed full_name, and upserts the
authenticated user’s user_private_details row with the caller token.
GET / PATCH /api/v1/users/me/default-workspace separately preserves the
legacy default-workspace read fallback to null, supports current-user
app-session reads, and updates the authenticated user’s saved default workspace
only after caller-token workspace membership validation.
PATCH /api/v1/inquiries/:id separately revalidates the browser Supabase
session, requires a Tuturuuu/XWF email domain, and updates the inquiry admin
flags through the same Rust Supabase REST adapter. Broader Supabase session
revalidation remains part of the dedicated auth migration milestone, so route
notes must stay explicit about the app-session versus browser-session boundary.
scripts/backend-openapi-migration-contract.test.js compares the migrated
Rust-owned route artifacts in apps/tanstack-web/migration/route-manifest.json
with apps/backend/api/openapi.yaml. Add or update the OpenAPI operation in the
same commit that marks a Rust route artifact migrated; otherwise bun check
fails.
For method-level overrides, the same evidence applies to each migrated method,
and the route override must leave every unmigrated sibling method as a generated
legacy-next artifact. Do not mark a full route migrated only because a safe
preflight or placeholder method is implemented in Rust.
The manifest check compares both aggregate method counts and each route’s method
list against the current apps/web/src/app tree, including generated export
patterns such as createSerwistRoute(...) exports. Regenerate
the manifest after adding, removing, or changing exported methods in a legacy
route.ts. Non-terminal routes with methods: [] are still artifacts in the
ownership inventory; port, restore an exported method, or mark them
accepted-removal with an explicit reason before cutover.
Rust JSON responses must keep the shared response security defaults:
Content-Type: application/json, Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; base-uri 'none', Referrer-Policy: no-referrer,
X-Content-Type-Options: nosniff, and X-Frame-Options: DENY. Route ports that
replace legacy public probes or API handlers must preserve explicit cache
behavior, including Cache-Control: no-store for /api/health and
Cache-Control: public, max-age=300, must-revalidate for /.well-known/*.
Non-JSON routes should use the empty-response path instead of serializing JSON
null when the legacy handler returned no body.
Protected workspace, cron, job, and admin endpoints stay server-owned. Browser
code cannot call protected Rust routes directly, cannot receive service tokens,
and cannot bypass packages/internal-api / TanStack server functions for
session-aware data access. Worker-bound secrets belong in Cloudflare secret
bindings; keep local, Docker, and Wrangler configuration to environment
variable names only.
For Cloudflare specifically:
- Bind
BACKEND_INTERNAL_TOKEN,BACKEND_PUBLIC_ORIGIN,SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY,CRON_SECRET, andDISCORD_APP_DEPLOYMENT_URL, plusAURORA_EXTERNAL_URLandAURORA_EXTERNAL_WSID, withwrangler secret put,wrangler versions secret put, or Cloudflare dashboard secret bindings. The TanStack Worker reaches the backend Worker through theBACKENDservice binding; configureBACKEND_INTERNAL_URLonly for non-binding HTTP fallback runs. Usesecret putfor first preview bootstrap only because it deploys a new active version immediately; use the versions command family for rotations and canaries. - Bind
TUTURUUU_APP_COORDINATION_SECRETon the backend Worker before testing contact/profile routes. The Rust verifier also accepts existing app-coordination fallback secret names for compatibility, but the dedicated secret name is the preferred Cloudflare binding. - Keep local Worker secret values in ignored
apps/backend/.dev.varsandapps/tanstack-web/.dev.varsfiles. Do not commit literal origins that are account-specific private targets, tokens, API keys, cookies, or session material. CMS_APP_URLandNEXT_PUBLIC_CMS_APP_URLare public origin allowlist inputs for the WebGL upload preflight. They may be supplied through Wrangler vars or local.dev.vars, but they are not backend tokens and must not be listed as required secrets.- Keep private/admin data ownership server-side. If a migrated endpoint needs a Supabase service role or private schema access, the Rust backend owns that call path; the browser receives only the authorized response shape.
- Review CORS, cookie domain,
SameSite, secure-cookie, and session-origin behavior before mapping a custom hostname. Previewworkers.devorigins are different sites fromtuturuuu.localhostand productiontuturuuu.com, so cookie/session behavior must be proven with smoke or E2E evidence rather than assumed from Docker. - Keep
BACKEND_ENV=previewfor Cloudflare preview. Development-only migration routes and local E2E bypasses must not be enabled by Worker deploys. - Do not bypass the migration gate because a Worker smoke passed. Worker smoke proves deploy compatibility; cutover still requires manifest, Docker E2E, and benchmark evidence.
GET /api/migration/status,
GET /api/migration/manifest, GET /api/migration/progress, and
GET /api/migration/cutover-gates require
Authorization: Bearer <BACKEND_INTERNAL_TOKEN>. The TanStack migration
dashboard calls them from a Start server function through
packages/internal-api, which adds the bearer token only on the server.
The first Rust-owned migration contracts are exposed from apps/backend and
consumed by the TanStack shell through a Start server function:
| Endpoint | Purpose |
|---|---|
GET /.well-known/* / HEAD /.well-known/* | Legacy-compatible cacheable empty 404 for unsupported well-known probes. |
GET /~recover-browser-state / POST /~recover-browser-state | Legacy-compatible browser recovery route with no-store HTML, same-origin POST protection, Clear-Site-Data, auth cookie clearing, and login redirect. |
GET /api/health | Legacy-compatible health route migrated from apps/web to Rust. |
GET /api/auth/me | Legacy-compatible current Supabase user route backed by browser Supabase cookie or non-app-session Bearer revalidation through Supabase Auth, returning the raw user payload with no-store headers. |
GET /api/auth/mfa/totp/assurance-level | Legacy-compatible Supabase MFA assurance-level route backed by browser Supabase cookie or non-app-session Bearer revalidation, JWT aal/amr claims, and verified factors from the revalidated user JSON. |
GET / POST /api/auth/mfa/totp/factors | Legacy-compatible Supabase TOTP factor list/enrollment routes backed by browser Supabase cookie or non-app-session Bearer revalidation and Supabase Auth REST for enrollment. |
GET / DELETE /api/auth/mfa/totp/factors/:factorId | Legacy-compatible Supabase TOTP factor detail/unenrollment routes backed by Auth JS-compatible factor listing and Supabase Auth REST unenrollment. |
GET /api/v1/calendar/mock | Legacy-compatible deterministic mock calendar events migrated from apps/web to Rust. |
GET /api/v1/devboxes/cache and POST /api/v1/devboxes/cache/prune | Legacy-compatible devbox cache routes accepting platform CLI app-session access tokens or browser Supabase sessions, requiring root workspace MEMBER access, returning the current empty cache list body, and acknowledging prune requests without private devbox table mutations. |
GET / POST /api/v1/aurora/forecast, /ml-metrics, and /statistical-metrics | Legacy-compatible Aurora forecast and metric readers plus protected ingest routes backed by Supabase Auth, the legacy Tuturuuu email-domain gate, external Aurora fetches, and caller-token Supabase inserts. |
POST / DELETE /api/v1/infrastructure/languages | Legacy-compatible locale preference cookie route for NEXT_LOCALE. |
POST / DELETE /api/v1/infrastructure/sidebar | Legacy-compatible sidebar collapsed preference cookie route for sidebar-collapsed. |
POST / DELETE /api/v1/infrastructure/sidebar/sizes | Legacy-compatible sidebar sizing preference cookie route for sidebar-size and main-content-size. |
GET /api/v1/infrastructure/users/fields/types | Legacy-compatible static user field type metadata route returning TEXT, NUMBER, BOOLEAN, DATE, and DATETIME in the original order. |
GET /api/v1/infrastructure/ai/models | Legacy-compatible public AI model catalog backed by private-schema Supabase REST reads with a fixed public column list, filters, sanitized search, capped ID filters, and exact-count pagination. |
GET /api/admin/tasks/embeddings/stats | Legacy-compatible Tuturuuu-admin task embedding coverage stats backed by Supabase Auth cookie validation and server-owned exact task counts. The SSE embedding generator remains legacy-owned. |
GET /api/:wsId/crawlers/list | Legacy-compatible authenticated crawled URL listing backed by Supabase Auth cookie validation, server-owned raw crawled_urls reads, exact-count pagination, and an explicit 401 for non-Tuturuuu callers. |
GET /api/v1/workspaces/:wsId/crawlers/status | Legacy-compatible workspace-agnostic crawler status lookup backed by server-owned exact crawled_urls.url reads and raw related crawled_url_next_urls rows ordered by created_at.desc. |
GET /api/v1/ai/whitelist/me | Legacy-compatible authenticated current-user AI whitelist status backed by satellite app-session auth or browser Supabase cookie auth and a server-owned private-schema enabled-flag lookup. |
GET /api/v1/cms/workspaces | Legacy-compatible CMS workspace list backed by app-session or browser Supabase auth, service-role workspace reads, root-admin/per-workspace external-project permission checks, active binding resolution, and subscription tier metadata. |
GET /api/v1/mira/achievements | Legacy-compatible Mira achievement catalog backed by browser Supabase auth, private-schema service-role catalog reads, caller-token unlocked-achievement reads, and derived unlock/grouping/stat payloads. |
GET /api/v1/storage/list | Legacy-compatible workspace Drive object list backed by ttr_ workspace API-key validation, manage_drive permission checks, path sanitization, reserved mobile-deployment vault blocking, server-owned Supabase Storage list calls, placeholder/reserved-entry filtering, and recursive file-count pagination. |
GET /api/time-tracking/export | Legacy-compatible root-only grouped time-tracking export backed by browser Supabase auth, Tuturuuu email-domain gating, root workspace membership checks, caller-token get_grouped_sessions_paginated RPC calls, parseInt-style query defaults, a 1000-row limit cap, and the legacy empty-result fallback. |
GET /api/v1/hive/ai/models | Legacy-compatible Hive AI model catalog backed by Hive app-session or browser Supabase auth, Hive member/admin access, and server-owned private-schema model reads mapped to the shared UI model shape. |
GET /api/v1/users/me/hive-access | Legacy-compatible authenticated current-user Hive access status backed by current-user app-session auth or browser Supabase cookie auth and server-owned membership/admin flag lookups. |
GET /api/v1/nova/me/team | Legacy-compatible authenticated current-user Nova team lookup backed by Nova app-session auth or browser Supabase cookie auth and a server-owned private-schema team membership lookup. |
GET /api/v1/task-board-status-templates | Legacy-compatible authenticated global task-board status template catalog backed by Supabase cookie or Bearer auth and server-owned ordered catalog reads. |
GET /api/v1/workspaces/limits | Legacy-compatible authenticated workspace creation limit check backed by Supabase Auth cookie validation and server-owned exact counts of non-deleted workspaces created by the caller. |
GET /api/v1/workspaces/:wsId/posts/permissions | Legacy-compatible post permission flag reader backed by Supabase Auth revalidation and server-owned has_workspace_permission RPC checks, preserving quiet false flags for missing auth or unresolved permissions. |
GET /api/v1/workspaces/:wsId/Mention | Legacy-compatible mention email endpoint backed by Supabase Auth revalidation, exact MEMBER workspace membership, and caller-token workspace_users.email reads. |
GET /api/v1/workspaces/:wsId/habits/access | Legacy-compatible habits feature access probe backed by Supabase Auth revalidation, workspace normalization, service-role membership validation, and exact ENABLE_HABITS=true workspace secret matching. |
GET /api/v1/workspaces/:wsId/mobile/module-flags | Legacy-compatible mobile module flag endpoint backed by Supabase Auth revalidation, caller-token workspace membership, and server-owned workspace_secrets reads for hidden module policy. |
GET /api/v1/workspaces/:wsId/education/access | Legacy-compatible education feature access probe backed by Supabase Auth revalidation, getPermissions-compatible ai_lab checks, and server-owned workspace_secrets ENABLE_EDUCATION reads. |
GET /api/v1/workspaces/:wsId/finance/budgets/status | Legacy-compatible budget status probe backed by finance/platform app-session or Supabase Auth revalidation, workspace normalization, manage_finance permission checks, and server-owned get_budget_status RPC reads. |
GET /api/workspaces/:wsId/finance/charts/balance | Legacy-compatible balance chart point backed by finance/platform app-session or Supabase Auth revalidation, workspace normalization, view_finance_stats checks, and get_wallet_balance_at_date RPC reads. |
GET /api/v1/workspaces/:wsId/finance/debts/summary | Legacy-compatible debt and loan summary probe backed by finance/platform app-session or Supabase Auth revalidation, workspace normalization, manage_finance checks, and private get_debt_loan_summary RPC reads. |
GET /api/v1/workspaces/:wsId/finance/filter-users | Legacy-compatible finance filter user endpoint backed by finance/platform app-session or Supabase Auth revalidation, workspace normalization, view_transactions checks, service-role creator reads, and caller-token workspace user reads. |
GET /api/v1/workspaces/:wsId/finance/invoices/subscription/context | Legacy-compatible subscription invoice context endpoint backed by finance/platform app-session or Supabase Auth revalidation, workspace normalization, create_invoices checks, student group validation, and service-role attendance/invoice reads. |
GET /api/v1/workspaces/:wsId/finance/recurring-transactions/upcoming | Legacy-compatible upcoming recurring transaction probe backed by finance/platform app-session or Supabase Auth revalidation, workspace normalization, view_transactions checks, and get_upcoming_recurring_transactions RPC reads. |
GET /api/v1/workspaces/:wsId/settings/permissions | Legacy-compatible workspace settings permission flags backed by Supabase Auth revalidation, personal/workspace identifier resolution, membership validation, server-owned role/default permission reads, and the private 30-second success cache directive. |
GET /api/v1/workspaces/:wsId/settings/permissions/check | Legacy-compatible workspace permission checker backed by Supabase Auth revalidation, personal/workspace identifier resolution, membership validation, and server-owned role/default permission reads. |
GET /api/v1/workspaces/:wsId/course-modules and GET /api/v1/workspaces/:wsId/quiz-sets/:setId/linked-modules | Legacy-compatible education module readers backing the TanStack linked-modules page, with browser Supabase auth, ai_lab permission resolution, ENABLE_EDUCATION gating, exact-count pagination, and quiz-set workspace binding. |
GET / PATCH /api/v1/user/onboarding-progress | Legacy-compatible authenticated onboarding progress reader/updater backed by Supabase Auth cookie validation, server-owned onboarding_progress reads/upserts, and the legacy allowed-field update contract. |
PATCH /api/v1/user/profile | Legacy-compatible browser-session profile update backed by Supabase Auth cookie validation, legacy profile field validation, and server-owned users row updates scoped to the authenticated user. |
GET / PATCH /api/v1/users/me/default-workspace | Legacy-compatible default-workspace reader/updater backed by current-user app-session or browser Supabase auth for reads, caller-token membership validation for writes, and the legacy personal-workspace/null fallback. |
GET / PATCH /api/v1/users/calendar-settings | Legacy-compatible current-user calendar settings reader/updater backed by calendar app-session or browser Supabase auth, user_private_details reads/writes, auto defaults, and legacy enum/string patch validation. |
GET /api/v1/users/me/identities | Legacy-compatible browser-session linked identity reader backed by Supabase Auth revalidation, raw user JSON identity extraction, derived canUnlink, and the private success cache directive. |
PATCH /api/v1/users/me/full-name | Legacy-compatible browser-session full-name update backed by Supabase Auth cookie validation, required trimmed full_name validation, and caller-token user_private_details upsert scoped to the authenticated user. |
POST /api/v1/aurora/health | Legacy-compatible protected Aurora health probe backed by Supabase Auth cookie validation, the legacy Tuturuuu email-domain gate, and an outbound AURORA_EXTERNAL_URL/health check. |
GET / POST /api/v1/internal/holidays, POST /api/v1/internal/holidays/bulk, and PUT / DELETE /api/v1/internal/holidays/:holidayId | Legacy-compatible Vietnamese holiday list/create/bulk-import/update/delete routes. GET uses the Rust server-owned Supabase REST adapter with optional parseInt-style year filtering. Mutations revalidate Supabase auth, require root workspace MEMBER access, and write with the caller token so holiday RLS stays active. Bulk import preserves the legacy replace-existing year delete plus date-conflict upsert behavior. |
GET /api/v1/topic-announcement-verifications/:token | Legacy-compatible public Topic Announcements email verification route backed by server-owned private-schema Supabase REST reads and updates. Workspace Topic Announcements management APIs remain legacy-owned. |
GET /api/v1/users/me/profile | App-session current-user profile route. It verifies ttr_app_ JWTs, reads users and user_private_details through the server-owned Supabase REST adapter, and returns the legacy profile shape with no-store headers. |
PATCH /api/v1/users/me/profile | App-session profile mutation route. It enforces same-origin confirmation for cookie auth, validates display_name, bio, and avatar_url, and persists the allowed fields to the users row through Supabase REST. |
POST /api/v1/inquiries | App-session support-inquiry route. It enforces same-origin confirmation for cookie auth, validates the legacy payload and field limits, and inserts support_inquiries with creator_id from the resolved app-session user. |
PATCH /api/v1/inquiries/:id | Browser-session inquiry admin update route. It validates the legacy is_read and is_resolved flags, requires a Tuturuuu/XWF email domain, and patches support_inquiries through the server-owned Supabase REST adapter. |
OPTIONS /api/v1/auth/password-login, /otp/send, and /otp/verify; GET / OPTIONS /api/v1/auth/otp/settings | Legacy-compatible shared wildcard CORS preflights plus public OTP availability lookup backed by the root workspace OTP config reads. Paired OTP send/verify and password auth methods remain legacy-owned. |
OPTIONS /api/v1/auth/mobile/password-login, /send-otp, and /verify-otp | Method-level legacy-compatible shared wildcard CORS 204 preflights; paired mobile auth methods remain legacy-owned. |
GET / PUT /api/v1/infrastructure/mobile-versions | Legacy-compatible protected mobile policy snapshot and write route requiring a revalidated Supabase browser session or Bearer token plus root manage_workspace_roles; writes normalize the policy payload and upsert all nine root config rows. |
GET / POST /api/v1/infrastructure/timezones and PUT / DELETE /api/v1/infrastructure/timezones/:timezoneId | Legacy-compatible protected timezone collection plus detail update/delete routes requiring a revalidated Supabase browser session or Bearer token plus root manage_workspace_roles, backed by server-owned private-schema timezones reads/writes. |
GET /api/v1/infrastructure/user-status-changes | Legacy-compatible workspace user status change list backed by caller-token Supabase REST reads so workspace_user_status_changes RLS, exact count, required ws_id, and legacy limit/offset range behavior stay intact. |
GET /api/v1/infrastructure/users | Legacy-compatible workspace user export list backed by caller-token Supabase REST reads so workspace_users RLS, exact count, required ws_id, and legacy limit/offset range behavior stay intact. |
GET /api/v1/infrastructure/classes, /product-categories, and /score-names | Legacy-compatible catalog export lists backed by caller-token Supabase REST reads so workspace_user_groups, product_categories, and user_group_metrics RLS and exact-count pagination stay intact. |
GET /api/v1/infrastructure/lessons and /packages | Legacy-compatible content export lists for private user_group_posts and workspace_products, preserving exact-count pagination, legacy auth shape for packages, and the no-auth lesson export behavior. |
GET /api/v1/infrastructure/product-prices, /product-units, and /warehouses | Legacy-compatible inventory setup exports for private inventory_products, inventory_units, and inventory_warehouses, preserving inventory app-session auth, catalog/setup permission checks, exact-count pagination, and error bodies. |
GET / POST /api/v1/infrastructure/ai/whitelist/domains and /emails | Legacy-compatible protected AI whitelist collection routes backed by service-role private-schema reads/inserts after Supabase auth and @tuturuuu.com operator email validation. |
PUT / DELETE /api/v1/infrastructure/ai/whitelist/:email and /domain/:domain | Legacy-compatible protected AI whitelist detail update/delete backed by service-role private-schema writes after Supabase auth and @tuturuuu.com operator email validation. |
GET /api/v1/infrastructure/post-email-queue | Legacy-compatible protected post email queue infrastructure summary backed by service-role post_email_queue reads after root workspace membership validation, preserving summary, workspace, and batch aggregation behavior. |
GET /api/v1/infrastructure/bills, /roles, and /transaction-categories | Legacy-compatible workspace export lists backed by caller-token Supabase REST reads so finance_invoices, workspace_user_groups, and transaction_categories RLS and exact-count pagination stay intact. |
GET /api/v1/infrastructure/wallet-transactions | Legacy-compatible protected wallet transaction export backed by the caller-token get_wallet_transactions_with_permissions RPC with legacy ordering, limit/offset, raw rows, and first-row total_count extraction. |
GET /api/v1/infrastructure/abuse-intelligence | Legacy-compatible protected abuse intelligence snapshot backed by caller-token reputation subject, signal, and challenge reads plus service-role active trust override reads after root view_infrastructure permission validation. |
GET /api/v1/infrastructure/abuse-events | Legacy-compatible root-workspace abuse event list backed by caller-token Supabase REST reads with legacy ip/type/success filters, page/pageSize pagination, exact counts, and auth/error bodies. |
GET /api/v1/infrastructure/blocked-ips | Legacy-compatible root-workspace blocked IP list backed by caller-token Supabase REST reads with the legacy unblocked_by_user embed, status/ip filters, page/pageSize pagination, exact counts, and auth/error bodies. |
GET /api/v1/infrastructure/suspensions | Legacy-compatible active user suspension list backed by service-role user_suspensions reads after root manage_workspace_roles; POST and detail DELETE remain legacy-owned mutation methods. |
GET / POST /api/v1/infrastructure/email-blacklist and GET / PUT / DELETE /api/v1/infrastructure/email-blacklist/:entryId | Legacy-compatible root-workspace email blacklist reads, creation, detail update, and detail deletion backed by caller-token Supabase REST with Zod-style write validation parity. |
GET /api/v1/infrastructure/bill-coupons, /bill-packages, /class-attendance, /class-members, /class-packages, /class-scores, /package-stock-changes, and /student-feedbacks | Legacy-compatible related-filter export lists backed by caller-token Supabase REST reads with embedded workspace relationships and exact-count pagination. |
GET /api/v1/infrastructure/user-monthly-reports and /user-monthly-report-logs | Legacy-compatible protected monthly report export lists backed by shared workspace permission resolution and private-schema Supabase REST exact-count pagination. |
GET / OPTIONS /api/v1/mobile/version-check | Legacy-compatible public mobile version policy evaluation and shared wildcard CORS preflight backed by fixed root workspace policy config IDs read through the Rust backend Supabase REST adapter. |
OPTIONS /api/v1/auth/qr-login/challenges[...] | Method-level legacy-compatible bare empty 204 preflights for QR login challenge create, poll, and approve routes. |
OPTIONS /api/v1/auth/mfa/mobile/challenges[...] and /approvals[...] | Method-level legacy-compatible bare empty 204 preflights for MFA mobile challenge create, poll, approve, and approval listing routes. |
OPTIONS /api/v1/workspaces/:wsId/external-projects/webgl-packages/upload | Method-level legacy-compatible WebGL upload preflight with credentialed CMS CORS headers only for allowed CMS origins. |
POST /api/v1/workspaces/:wsId/user-groups/:groupId/group-checks/:postId/email | Legacy-compatible removed direct post email route returning 410 Gone; queue-based sending owns approved emails. |
GET / POST /api/v1/workspaces/:wsId/slides | Legacy-compatible workspace slides collection placeholder returning 501 Not implemented. |
PUT / DELETE /api/v1/workspaces/:wsId/slides/:slideId | Legacy-compatible workspace slide item placeholder returning 501 Not implemented. |
PUT /api/v1/infrastructure/migrate/grouped-score-names | Disabled infrastructure migration route migrated from apps/web to Rust with the same development-only guard and 410 MIGRATION_DISABLED body. |
GET / PUT / PATCH / POST /api/v1/infrastructure/migrate/:migration | Accepted-removal terminal decommission for legacy batch migration helpers; Rust preserves the development/local-E2E guard and per-slug legacy method allow lists while returning 410 MIGRATION_DISABLED. |
PUT /api/workspaces/:wsId/products/categories/migrate, /products/units/migrate, /transactions/categories/migrate, /users/indicators/migrate, and /wallets/transactions/migrate | Obsolete workspace migration writes accepted for removal; Rust keeps the development-only guard and returns a terminal 410 MIGRATION_DISABLED response. |
GET / POST /api/v1/workspaces/:wsId/encryption/migrate, POST /api/v1/workspaces/:wsId/storage/migrate, GET /api/v2/workspaces/:wsId/migrate/:module | Production auth/API-key migration helpers accepted for removal; Rust keeps the legacy method allow lists and returns terminal 410 MIGRATION_DISABLED in all environments. |
GET /api/migration/status | Runtime, environment, deployment target, and manifest pointer. |
GET /api/migration/manifest | The checked route manifest JSON. |
GET /api/migration/progress | Owner/kind progress buckets and representative remaining legacy route artifacts. |
GET /api/migration/cutover-gates | Backend-derived manifest gates plus required E2E and benchmark evidence placeholders. |
/api/migration/cutover-gates is the dashboard authority for cutover state. It
must stay blocked while any manifest route remains legacy-next, any backend
route artifact is not mapped to rust-backend, or required Docker E2E and
benchmark evidence is missing.
Docker And E2E
The production compose stack definestanstack-web, tanstack-web-blue, and
tanstack-web-green services. The Docker Bake file includes matching
blue-green-tanstack-web* targets so benchmark and cutover work can build
candidate TanStack images beside the legacy web images.
apps/backend/Dockerfile copies
apps/tanstack-web/migration/route-manifest.json into the Rust build context
because the backend includes the manifest at compile time for the migration
contract endpoints. Run bun check:docker after manifest path or Dockerfile
changes.
Legacy E2E remains the default:
tmp/e2e/web-migration/compare-report.json after running
both frontends. Each frontend result includes normalized origin evidence,
passRate, wallMs, and Playwright JSON reporter test counts so
bun migration:tanstack:gates can evaluate same-origin mistakes, E2E
regressions, and zero-test false positives from the same evidence file. The gate
rejects missing, credentialed, invalid, or identical Next/TanStack origins, and
it rejects compare reports that do not prove nonzero Playwright execution for
both frontends. Set E2E_COMPARE_REPORT_PATH when a run needs to write the file
elsewhere under tmp/.
apps/web/e2e/public-marketing-routes.noauth.spec.ts is the first shared
public-route parity suite for this migration. It runs under the existing
apps/web Playwright project so --frontend tanstack and --frontend compare
reuse the same assertions for migrated landing, product, legal, redirect,
offline, branding, blog, careers, demo, security, partners, UI docs,
visualization, and static solution routes.
scripts/public-marketing-e2e-coverage.test.js compares the migrated public
page entries in apps/tanstack-web/migration/route-manifest.json with that
no-auth Playwright spec. When a public marketing, UI docs, redirect, or offline
page is marked migrated, the route needs a concrete default-locale E2E
example in the shared spec before bun check can pass.
Benchmarks
Use the benchmark harness to compare reachable Next and TanStack frontend routes, plus independent Rust backend smoke routes. It does not yet compare legacy Next.js API route timing against equivalent Rust endpoints. Reports are written under ignoredtmp/benchmarks/web-migration/<timestamp>/report.json.
BACKEND_INTERNAL_TOKEN when running the benchmark against local Docker,
preview Workers, or any backend that requires internal authorization; otherwise
the protected samples correctly fail as unreachable 4xx responses.
To compare the legacy production/staging origin against Cloudflare preview
Workers, pass all origins explicitly:
bun benchmark:web-setups
rejects same-origin compare runs before writing a report, and
bun migration:tanstack:gates rejects benchmark evidence with missing origins,
credentialed origins, identical Next/TanStack origins, route/sample URLs that do
not match the recorded setup origin, or matched frontend routes without their
own frontend-route-p95 comparison. Docker E2E compare evidence uses the same
distinct-origin rule for the browser-facing Next and TanStack frontend runs.
Use full mode when both frontends are running with representative seeded data:
--require-all fails the benchmark command when any required
metric evidence is missing. That keeps local benchmark rehearsals aligned with
bun migration:tanstack:gates instead of deferring missing dev-ready, build,
image-size, RSS/CPU, JS-output, E2E, or API latency evidence until cutover.
Pass reviewer-approved non-HTTP metrics and accepted regression notes through
--evidence when the harness cannot measure them directly:
bun migration:tanstack:gates with the Docker E2E compare report and
Cloudflare smoke report. Generated benchmark, smoke, and E2E reports stay under
ignored tmp/ paths. Cutover gates reject evidence older than 24 hours by
default; use --evidence-max-age-ms <milliseconds> only when a rehearsal
explicitly accepts a longer freshness window.
Default gates:
- frontend route p95 must not regress more than
25% - Cloudflare smoke evidence must include passing
backend-health,backend-ready,backend-migration-status,backend-migration-status-missing-token,backend-migration-status-invalid-token, andtanstack-rootprobes - cutover reports must include the full metric comparison contract: API p50/p95/p99, dev ready time, first-route cold time, warm navigation time, Docker build time, image size, JS output size, production RSS/CPU baseline, E2E wall time, and E2E pass rate, with numeric baseline, candidate, ratio, and threshold values for each required comparison
- full compare evidence must include complete matching frontend route coverage;
unmatched Next-only or TanStack-only routes fail
--require-alland cutover gate validation - representative backend smoke routes must stay below the smoke ceiling
- strict runs fail when any required route is unreachable
p50Ms, p95Ms, and p99Ms, plus coldMs
for the first successful request and warmP50Ms / warmP95Ms / warmP99Ms
for later samples. Use those fields for first-route cold time, warm navigation
time, and representative API latency notes. Add Docker build time, image size,
process RSS/CPU, JS output size, and E2E wall-time evidence to the same
benchmark directory when running full cutover rehearsals.
Record approved exceptions in the migration PR. Do not silently widen thresholds
to make a run pass.
Cutover Checklist
- Every manifest route is
migratedoraccepted-removal. bun migration:tanstack:cutover-checkpasses.bun test:e2e:web:docker -- --frontend comparepasses and has a compare evidence report.bun benchmark:web-setups -- --setup compare --profile full --require-all --insecurepasses or has approved exceptions.bun smoke:cloudflare --output <path>passes against the preview Workers.bun migration:tanstack:gates -- --e2e-report <path> --benchmark-report <path> --cloudflare-smoke-report <path>passes.bun check:dockerandbun checkpass.- Legacy
apps/webremains available as the rollback fixture until production monitoring shows the TanStack/Rust path is stable.