apps/web
TanStack Start on Vite: one app with two very different route trees, kept apart on purpose.
---
config:
look: handDrawn
theme: neo-dark
---
flowchart TD
R["__root"] --> P["_public<br><small>Header + Footer shell</small>"]
R --> A["_admin<br><small>auth-gated shell</small>"]
P --> L["/ landing"]
P --> S["/signin 路 /signup<br>/reset-password"]
P --> D["/device 路 /device/approve<br>/device/done"]
A --> DA["/dashboard<br><small>tab layout</small>"]
DA --> DA2["/dashboard 路 /dashboard/stats"]
A --> AG["/agent<br><small>tab layout</small>"]
AG --> AG2["/agent/widget 路 /agent/sandbox"]
A --> PR["/profile"]
A --> AD["/admin<br><small>admin-only layout</small>"]
AD --> AD2["/admin/dashboard"]
AD --> U["/admin/users 路 /admin/users/$userId"]
AD --> M["/admin/models"]
Public
The landing page at / has four sections: a hero, a showcase carousel, a feature strip and install instructions. The carousel holds a live barkochba game driven by the same widget turn endpoint a third-party site would use, and a card that opens the chat widget when the site has a chat widget key. The game talks to the API with plain fetch instead of importing the widget workspace, so it exercises the public contract.
/device, /device/approve and /device/done are where the CLI鈥檚 device login lands: sign in, confirm the code the terminal printed, done.
Signed in
Everything behind _admin (the auth-gated shell, despite the name) needs a signed-in, non-banned user.
The top menu is a static list, not something each page assembles. Visitors see Sign In, Sign Up and Docs. Signed-in users see one item per section (Dashboard, Agent and Profile), and admins also get Admin. A section is a layout route with a tab bar (SectionTabs, tabs from nav-items.ts) over its pages. Every admin-only page sits under /admin, whose layout also requires the Better Auth admin role and sends anyone else to the dashboard. The menu hides the item and the layout enforces it.
| Route | What it is |
|---|---|
/dashboard | a welcome and the Telegram connect card |
/dashboard/stats | your usage stats |
/agent/widget | widget keys: create, edit, disable, delete |
/agent/sandbox | your sandbox key and run command, your sandboxes (online or last seen, place, hardware, servers running; offline ones can be removed), and the share and use-shared switches |
/profile | your account: name and avatar, email, password, ability API keys, and deleting it |
/admin/dashboard | what the platform鈥檚 services are doing right now, starting with the MCP sandboxes (/admin redirects here) |
/admin/users, /admin/users/$userId | accounts, roles, bans |
/admin/models | providers and their models, per task |
Stack notes
- Data: React Query, with the API token pulled from the Better Auth session
- Auth: the Better Auth client lives in
hooks/auth-client.ts, and cookies are prefixedkaja - Forms: TanStack Form
- Styling: Tailwind v4, Base UI React primitives, lucide icons
- i18n: Paraglide, generated into
src/paraglide/. Every string exists inen-GB,en-US,hu-HU,nan-TWandzh-TW - Errors: anything worth knowing goes to Sentry, and user-facing errors already show a toast
src/routeTree.gen.tsis generated by the router plugin. Don鈥檛 hand-edit it; the pre-commit hook regenerates it whenever route files change
There are no automated UI tests yet.
Next: