Skip to content

Frontend Reference

Yigtwxx edited this page Jul 12, 2026 · 1 revision

Frontend Reference

The frontend is Next.js 16 (App Router) with React 19, strict TypeScript, Zustand 5 for state, and Tailwind 3.4. There is no runtime component library — UI primitives are hand-rolled on the class-variance-authority + clsx + tailwind-merge pattern. Path alias @/*./src/*.

A design principle runs through the whole codebase: one Docker image, many hosts. No domain, Sentry DSN, or analytics id is baked at build time; all such values are read server-side at request time (SITE_URL, SENTRY_DSN, UMAMI_WEBSITE_ID, BACKEND_ORIGIN, INTERNAL_API_ORIGIN).

Two structural facts to save you a search: there is no src/hooks/ directory (cross-component state is Zustand stores + lib/ module functions), and there is no components/dashboard/ folder (the dashboard composes ui/ + effects/ primitives inline).

Route groups

src/app/ uses three route groups plus root-level files (layout.tsx, manifest.ts, robots.ts, sitemap.ts, opengraph-image.tsx, apple-icon.tsx, icon.svg, error.tsx, global-error.tsx, not-found.tsx).

(app)/ — authenticated shell

Client-side auth gate: hydrates the auth store, redirects unauthenticated users to /login, renders Sidebar / TopBar / FooterStatusBar / VerifyEmailBanner / OnboardingCoachmark. A template.tsx remounts per navigation (which is why task state lives in a store, not component state).

Route Purpose
/dashboard Metrics: task counts, success rate, token usage, cost by provider, daily trends.
/architect The core product screen — pick expert/provider, write a prompt, watch the live agent graph + event log + streamed synthesis; history panel.
/agents List built-in + custom agents.
/agents/[id] Create/edit a custom agent (name, domain, system prompt, tools).
/marketplace Browse / install / publish agent teams; ratings + reviews.
/documents RAG knowledge-base document manager.
/settings/profile Profile, identity, security, 2FA, sessions, preferences, subscription, danger zone.
/settings/api-keys BYOK key management.
/settings/billing Plan grid, subscribe (mock card), quota meter.

(auth)/ — public auth screens

login, register, forgot-password, reset-password, verify-email (Aurora WebGL backdrop).

(marketing)/ — public marketing + legal

pricing (force-dynamic, prices from backend), templates (force-dynamic showcase), use-cases, how-it-works, docs, and the legal hub legal plus terms / privacy / security / acceptable-use / cookies.

API client — src/lib/api.ts

Everything goes through a private request<T>(): JSON, Authorization: Bearer from tokenStore, transparent one-shot 401 refresh, FastAPI error extraction (extractDetail handles string detail and 422 arrays), 204 handling. ApiError carries status.

Token/session infra:

  • tokenStoreget/set/clear access + refresh (localStorage maestro.access_token, maestro.refresh_token).
  • ensureFreshAccessToken() — decodes JWT exp, refreshes 60s before expiry (used before every WS handshake).
  • tryRefresh() — coalesces concurrent refreshes into one in-flight promise (avoids refresh-token reuse → family revocation).
  • apiBase() — same-origin in the browser; INTERNAL_API_ORIGIN / http://backend:8000 on the server.

The api object mirrors the backend (see API-Reference): auth (register, login, loginVerifyTotp, verifyEmail, resendVerification, forgotPassword, resetPassword), users (getCurrentUser, updateProfile, changePassword), sessions, 2FA, account lifecycle (requestAccountDeletion, cancelAccountDeletion, exportAccountData), billing, api-keys, tasks (startTask, getTask, listTasks, cancelTask, deleteTask, answerTask), dashboard, agents, marketplace, documents.

State — src/stores/ (Zustand)

Store Holds / notable actions
auth.ts (useAuthStore) isAuthenticated, hydrated, user; hydrate, login (returns MfaChallenge when 2FA), completeMfa, logout. Tokens live in localStorage, not the store.
tasks.ts (useTaskStore) activeTaskId, events[], status, streamingAnswer (accumulated agent_delta), question, history[], private _stream + _generation (stale-write guard). applyEvent reduces the event types; module-level attachStream() wires openTaskStream back into the store, re-checking _generation on each message to prevent A→B→A cross-paint. Only activeTaskId is persisted; events are refetched (Mongo is source of truth).
consent.ts Cookie/analytics consent (necessary always true, analytics default false).
onboarding.ts Onboarding progress (active/done/skipped), localStorage only.
toast.ts Toast queue; exposes a toast.{success,error,info} helper readable from non-React code (api client, WS handlers).

Key components

  • ui/Button (cva, exports buttonVariants), Input, Select, Card, Badge, Modal, Markdown (react-markdown + remark-gfm + rehype-slug), Sparkline, StatBlock, ProgressBar, Skeleton, Toast/Toaster.
  • architect/AgentGraph (node graph), FlowLayer (Bézier connector edges), EventLog (streamed feed), AgentCatalog (expert picker), HistoryPanel.
  • billing/PlanGrid, CardForm (live Luhn + brand detection), CardBrandLogos, QuotaMeter.
  • settings/ — eight cards: IdentityCard, AccountCard, SecurityCard, TwoFactorCard, SessionsCard, PreferencesCard, SubscriptionCard, DangerZoneCard.
  • marketplace/RatingStars, ReviewsDialog. agents/AgentForm. legal/LegalDocument, CookieNotice, ConsentManager.
  • effects/ + root effects — Aurora, SplashCursor, LetterGlitch, DecryptedText, CountUp, Reveal, Stagger, GradientText (WebGL via ogl, animation via motion / animejs).

Types — src/types/index.ts

A single module mirroring the backend Pydantic schemas: LLMProvider (20 values), SubscriptionPlan (starter|pro|scale), TaskStatus (pending/running/needs_review/awaiting_answer/completed/completed_with_warnings/failed/cancelled/timeout), plus auth/billing/task/dashboard/agent/marketplace/document types. Provider metadata (labels, chat-capability) lives separately in lib/providers.ts.

WebSocket consumption

lib/ws.ts openTaskStream is driven by the tasks store, not the components. The architect page only reads store state and folds node_update / review_result into per-node graph state. Full protocol, reconnect, and fallback behavior: Realtime-and-WebSockets.

SEO / legal / observability layers

  • SEO (lib/seo/) — buildPageMetadata({title, description, path}) gives relative canonical + OG; root metadataBase (resolved at request time via connection()) makes them absolute. siteUrl() is server-only and reads SITE_URL at request time. Images (opengraph-image.tsx, apple-icon.tsx) are generated with next/og.
  • Legal (lib/legal/) — a LEGAL_DOCS registry drives the hub, footer, sitemap, and each page; adding a doc there wires it everywhere. Operator facts live once in config.ts.
  • Observability (lib/observability/, instrumentation.ts) — Sentry DSN read at runtime; the SDK is dynamically imported so nothing downloads when the DSN is empty (zero egress). Analytics is self-hosted Umami, consent-gated, marketing paths only.

Config files

  • next.config.tsoutput: 'standalone', reactStrictMode, conditional /api/* rewrite to BACKEND_ORIGIN (only when set).
  • tsconfig.jsonstrict: true, paths: {"@/*": ["./src/*"]}.
  • tailwind.config.ts — brand colors (champagne #d3cbc0), per-domain neon hues, custom shadows/keyframes.
  • package.json scripts — dev, build, start, lint, type-check. No test runner (npm test intentionally absent). See Development-Setup.

Clone this wiki locally