src/App.tsx owns the route tree, wraps everything in the auth and toast providers, and lazy-loads every page so the initial bundle stays small.
Provider Stack
App.tsx mounts three nested providers around the router:
AuthProvider(src/auth/AuthContext.tsx) holds the JWT token, the current user, and role booleans.ToastProvider(src/components/Toast.tsx) supplies theuseToast()notification helper used across pages.SuspenseshowsRouteFallback(a simple “Loading…” div) while a lazy page chunk is fetched.
Two Layouts, Two Audiences
There are two top-level protected branches, each behindProtectedRoute with a roles allow-list and rendering a distinct layout via <Outlet />.
| Branch | Layout file | Allowed roles | Purpose |
|---|---|---|---|
/dashboard/* | src/layouts/DashboardLayout.tsx | admin, super_admin | Admin/operator console |
/agent-console/* | src/layouts/AgentLayout.tsx | agent, supervisor | Agent Desk handling surface |
path="*" renders RoleRedirect, which sends agents/supervisors to /agent-console (when ADK is on) and everyone else to /dashboard.
Dashboard Routes
All children of/dashboard are nested routes rendered inside DashboardLayout.
| Route | Page component | File |
|---|---|---|
/dashboard (index) | Overview | src/pages/Overview.tsx |
/dashboard/bots | BotList | src/pages/BotList.tsx |
/dashboard/bots/create | BotCreate | src/pages/BotCreate.tsx |
/dashboard/bots/:id | BotDetail | src/pages/BotDetail.tsx |
/dashboard/knowledge-bases | KnowledgeBases | src/pages/KnowledgeBases.tsx |
/dashboard/knowledge-bases/:id | KnowledgeBaseDetail | src/pages/KnowledgeBaseDetail.tsx |
/dashboard/calls | CallList | src/pages/CallList.tsx |
/dashboard/calls/:id | CallDetail | src/pages/CallDetail.tsx |
/dashboard/campaigns | Campaigns | src/pages/Campaigns.tsx |
/dashboard/campaigns/new, /dashboard/campaigns/:id/edit | CampaignCreate | src/pages/CampaignCreate.tsx |
/dashboard/campaigns/:id | CampaignDetail | src/pages/CampaignDetail.tsx |
/dashboard/carriers | CarrierList | src/pages/CarrierList.tsx |
/dashboard/carriers/create | CarrierCreate | src/pages/CarrierCreate.tsx |
/dashboard/carriers/exotel | ExotelDetail | src/pages/ExotelDetail.tsx |
/dashboard/carriers/:id | CarrierDetail | src/pages/CarrierDetail.tsx |
/dashboard/fleet | Fleet | src/pages/Fleet.tsx |
/dashboard/api-keys | ApiKeys | src/pages/ApiKeys.tsx |
/dashboard/changelog | ChangeLog | src/pages/ChangeLog.tsx |
/dashboard/settings | Settings | src/pages/Settings.tsx |
/dashboard/users | Users | src/pages/Users.tsx |
/dashboard/agent-desk | AgentDeskMetrics | src/pages/AgentDeskMetrics.tsx |
/dashboard/agent-assist | AgentAssistMoments | src/pages/AgentAssistMoments.tsx |
The
agent-desk and agent-assist dashboard routes are only registered when the ADK flag is true (see below).Agent Console Routes
The entire/agent-console branch is registered only when ADK is true.
| Route | Page component | File |
|---|---|---|
/agent-console (index) | AgentQueue (imported as AgentHome) | src/pages/AgentQueue.tsx |
/agent-console/analytics | AgentAnalytics | src/pages/AgentAnalytics.tsx |
/agent-console/call | AgentCall | src/pages/AgentCall.tsx |
/agent-console/history | AgentHistory | src/pages/AgentHistory.tsx |
/agent-console/calls/:id | CallDetail | src/pages/CallDetail.tsx |
/agent-console/agents | SupervisorDashboard | src/pages/SupervisorDashboard.tsx |
/agent-console/assist | AgentAssistMoments | src/pages/AgentAssistMoments.tsx |
CallDetail is shared between dashboard and agent console. It branches on location.pathname: under /agent-console it loads from /api/v1/agent-desk/calls/:id and hides the admin-only raw JSON export.Role Gating
DashboardLayout builds its sidebar from a navSections array. Each item can declare superAdmin or gated flags:
superAdmin: trueitems (Carriers, Settings) are only shown whenuser.role === 'super_admin'.gated: trueitems (Agent Desk, Agent Assist) are only shown whenADKis true.
AgentLayout filters its navItems by a supervisorOnly flag, so agents see Home/Analytics/My History while supervisors additionally get Agent Overview and Agent Assist.
ProtectedRoute (src/auth/ProtectedRoute.tsx) enforces the same boundaries at the route level: while auth is loading it shows a spinner; with no token it redirects to /login; and when the user’s role is not in the route’s roles list it redirects to the role’s home surface.
The ADK Feature Flag
src/tier.ts derives a single boolean ADK by hashing the lowercased BRAND_NAME (FNV-1a) against a fixed allow-list. When false, the Agent Desk / Agent Console routes and nav items are never registered. This keeps Agent Desk out of brands that have not licensed it, without per-brand source changes.
Lazy Loading
Every page and both layouts are wrapped inReact.lazy(() => import(...)). Route transitions therefore fetch the page chunk on demand, falling back to RouteFallback during load.
Related Docs
API Client & Auth
JWT injection, 401 handling, and ProtectedRoute internals.
Design System
Shared UI primitives, DataTable, and form patterns.
White-Label Build
Brand config, CSS-var injection, and the ADK gate.
CXB Console Overview
Product role and main workflows.