Skip to content

Application Structure

The dashboard is a React 19 + TypeScript + Vite single-page application (ecc-dps-dashboard/), styled with Tailwind CSS 4 and the shadcn/base-ui component model. The same bundle serves both the normal DPS dashboard and the Training Center; the app chooses which to boot from the hostname at load time.

Entry point and app split

  • src/main.tsx imports global CSS and mounts App in StrictMode.
  • src/App.tsx:
    • computes IS_TRAINING from window.location (training.eccdps.org, any training.* host, or a /training path) and boots TrainingApp instead of the normal dashboard when true;
    • wraps the normal routes in AuthProviderThemeProvider;
    • ProtectedRoutes redirects unauthenticated users to /login while /auth/me is loading or fails.

Pages

RouteComponentPurpose
/loginpages/Login.tsxDiscord sign-in entry and OAuth error display
/dashboardpages/Dashboard.tsxOperational overview and recent dockets
/docketspages/Dockets.tsxServer-paginated, filterable docket list
/dockets/:idpages/DocketDetail.tsxCase detail: timeline, evidence, notes, actions, contact thread
/evidencepages/Evidence.tsxGlobal evidence workspace
/analyticspages/Analytics.tsxAggregate metrics (recharts)
/agentspages/Agents.tsxAgent directory
/agents/:idpages/Agentdetail.tsxAgent record detail
/queuepages/Queue.tsxOperator/supervisor action queues with failure recovery
/auditpages/AuditLog.tsxGlobal timeline/audit history
/punishmentspages/Punishments.tsxDiscipline records list
/punishments/:punishment_idpages/PunishmentDetail.tsxSingle punishment + delivery state
/adminpages/Admin.tsxCapability-gated System Administration (health, queue, audit, agents, access, reports, schema)
/settingspages/Settings.tsxPreferences, theme, avatar

Components

  • components/layout/AppLayout.tsx — sidebar navigation, top bar, user identity, sign-out, local clock, and capability-filtered nav (can(permission) for regular items, canAdmin("admin_panel") for admin).
  • components/DiscordProfileCard.tsx / DiscordProfileModal.tsx — stored Discord profile snapshots for parties on a docket.
  • components/GlobalSearch.tsx — global search across dockets, evidence, appeals, users, and the audit log (backed by lib/search/commands.ts).
  • components/NotificationCenter.tsx — notification feed (rendered from API data; see the component for the current source).
  • components/SensitiveField.tsx — masks sensitive identifiers (agent IDs, clearance IDs, agreement IDs); reveal requires clearance 4+ and a double-click confirmation.
  • components/AdminConfirmDialog.tsx — confirmation dialog for admin/destructive actions with reason input.
  • components/DataState.tsxLoadingState / ErrorState presentational components.
  • components/OverlayPortal.tsx — portal helper for overlays.

Shared state model

There is no global application store (no Redux/Zustand). State is:

  • AuthProvider (src/auth/AuthProvider.tsx) — live agent, permission flags, admin capabilities, loading, refresh, sign-out.
  • ThemeProvider (src/lib/theme.tsx) — applies saved color theme + dark mode to <html>, re-applies on storage/focus events.
  • ToastProvider (src/lib/toast.tsx) — notification toasts.
  • Page-local stateuseState/useEffect/useCallback per page; server state is fetched through the API client and held in page state.
  • localStorage preferencessrc/lib/prefs.ts (ecc-dps:prefs): display density, docket filters, date format, theme.
  • Avatar state — localStorage in AppLayout/Settings.

Shared utilities

ModulePurpose
lib/api/Typed API wrappers (client.ts, auth.ts, reports.ts, agents.ts, admin.ts, punishments.ts, types.ts)
lib/urlSafety.tssafeHttpUrl / safeImageUrl — URL sanitization at every media/navigation sink
lib/format.tsStatus/date formatting helpers
lib/agents.tsAgent-related helpers
lib/search/commands.tsGlobal search command resources (docket/evidence/appeal/user/log)
lib/environment.tsappEnvironment / isDemoEnvironment from hostname or VITE_APP_ENV
lib/prefs.tsPreference store
lib/theme.tsx, lib/toast.tsxTheme + toast providers
lib/usePageTitle.tsSets document.title per page
lib/utils.tscn() class merger

Training Center

src/training/ is a self-contained app inside the same bundle:

  • TrainingApp.tsx — its own BrowserRouter, providers, and role-branched route trees (trainer routes under TrainingLayout; trainee routes inside TraineeShell from TrainingRoleGate.tsx). The role branch renders two separate literal <Routes> trees — React Router v7 rejects non-<Route> children directly under <Routes>.
  • Pages: TrainingDashboard, TrainingDockets, TrainingSessions, TrainingSessionPage, TrainingLogin, NoActiveTraining.
  • Components: TrainerControlCenter.tsx, TraineeInvestigation.tsx.
  • realtime.tsuseTrainingRealtime() hook (private channels, token refresh, presence, status reporting).
  • api.ts / types.ts — training endpoint wrappers and payload types.

Routing and UI architecture

  • React Router v7 (react-router-dom) with a flat <Routes> table in App.tsx; the Training Center re-normalizes any non-/training path on the training host to its /training equivalent.
  • The UI is presentational-first: pages fetch via the API client, render LoadingState/ErrorState while in flight, and perform mutations through typed wrappers, then refresh local state from the response or a re-fetch.
  • Component styling uses Tailwind utility classes with the project's design tokens (bg-card, text-muted-foreground, border-border, …); new UI should follow the existing patterns rather than introducing new styling systems.