Skip to main content

Web (apps/web)

apps/web is a Vite + React 19 SPA that does double duty as the marketing site (Home, Product, Tech, Careers, News, About, Waitlist) and the authenticated dashboard (Console and its sub-views: Chat, Episodic Memories, Semantic Memories, Sources, Monitoring, Access Control). The same nginx container that ships the SPA also reverse-proxies /api, /admin, /static, /mcp, and /docs to the right upstream — so users only ever touch one origin.

Stack

  • React 19 + TypeScript strict
  • react-router 7 (BrowserRouter, Routes, Route, Link, useNavigate)
  • Tailwind v4 with the new optimizer (@tailwindcss/vite)
  • Vite 8 (alias @clone/design../../packages/design; dev /api proxy → localhost:8001)
  • geist font

What lives here

  • Marketing routes (Home, Product, Tech, Careers, News, About, Waitlist) — public, no auth, optimized for first paint and SEO.
  • Console routes (/console/...) — gated by useAuth(); every fetch sends Authorization: Bearer <access>.
  • Auth flow — JWT access token + refresh token persist to localStorage under key clone_auth; the AuthContext refreshes on a 50-minute timer.
  • No global stateuseAuth() + per-page useState is the established pattern; do not introduce Redux / Zustand here.

Build and run

cd apps/web
npm install
npm run dev # localhost:5173, hot reload
npm run build # tsc -b && vite build → dist/
npm run lint # eslint

The production Docker image is multi-stage: a Node builder runs npm run build, and the final stage is nginx:alpine serving /app/dist plus the routing rules in nginx.conf. See Self-hosting → docker-compose.

Routing inside the SPA

All route definitions live in src/main.tsx; there is no App.tsx indirection. Marketing pages compose from components/ (Navbar, Footer, CloneStageSequence, ProductSwap, WaitlistForm); dashboard pages live in pages/ and own their own data fetching against /api/....

Surface contract: Web is the edit-and-analyze surface; Desktop is the view-and-act surface. Anything that requires text input, search, or longer reads goes here. Live actions (record, transcribe, hand off to an agent) belong on Desktop.