Dashboard 📊
The first thing you see when you sign in, and honestly the page you'll leave open all day. The
landing page (/, Components/Pages/Index.razor) is a live, mobile-first command center for the
signed-in user's activity across cBot runs, backtests, resources and (for admins) the node
cluster. It refreshes itself, looks great on a phone, and never makes you hit F5.
What it shows
Top to bottom, priority-ordered for a phone (every block is a full-width stack item on mobile, a responsive grid on tablet/desktop):
- Header — title, a live indicator (a real pulsing dot; static under
prefers-reduced-motion), the last-updated time, and a period toggle (1H · 24H · 7D · 30D) that drives the KPIs and chart. - Hero KPIs — four glanceable cards, each a big number + an inline SVG sparkline, and (where
meaningful) a delta vs the previous period:
- Active now — runs + backtests currently starting/running.
- Success rate — completed ÷ (completed + failed) over the period; delta in percentage points.
- Completed — finished runs/backtests this period; delta vs previous period.
- Failed — failures this period; delta (fewer is better, so a drop shows green).
- Activity chart — an ApexCharts area timeline of started / completed / failed per time bucket.
- Instance status ring — a donut of running / backtests / pending / completed / failed, total in the centre.
- Backtests — a three-tile snapshot (running / completed / failed), click-through to
/backtest. - Copy trading — your copy-trading profiles with a live status dot, destination count, and a Live
badge on running profiles; click-through to
/copy-trading. - AI agents — your persona-driven trading agents with run state (archetype · status) and last-action
time; click-through to
/agent-studio. - Live activity feed — the 20 most recent events (newest first) with a status-coloured dot and a relative timestamp.
- Cluster health (admins only) — active-vs-total nodes and a capacity-in-use gauge.
- Resource tiles — cBots, trading accounts, cTrader IDs, MCP keys (click through to their pages).
Customize your dashboard
Every block above is a widget you control. Hit Customize (top-right of the header) to open a dialog where you show/hide any widget and reorder them with up/down arrows. Reset to default restores the catalog order. Your choice is persisted server-side per user, so it follows you across browsers and devices — not just this tab.
- Feature-gated and admin-only widgets (Copy trading, AI agents, Cluster health) only appear in the dialog when your deployment/role can use them.
- The widget catalog is a single source of truth in
Core/Dashboard/DashboardWidgets.cs; presentation (label + icon + availability) lives inComponents/Dashboard/DashboardWidgetMeta.cs.
How it stays live
The page polls GET /api/dashboard/overview?period=<1h|24h|7d|30d> every 10 seconds and re-renders the
widgets in place — no manual reload. A transient fetch failure is swallowed and retried on the next tick;
the loop stops cleanly on dispose. The first load shows a skeleton; a persistent failure shows an error
card with Retry; a user with no data sees zeroed KPIs and empty-state copy.
Backend
Endpoints/DashboardEndpoints.csmaps/overview(and keeps the older scalar/stats). It is per-user and admin-gated viaICurrentUser; the clock comes fromTimeProvider. It also mapsGET/PUT /api/dashboard/layout— the user's widget layout, loaded on page start and saved from the Customize dialog.- Layout persistence is the
UserDashboardaggregate (Core/Dashboard/UserDashboard.cs): one board per user (unique onUserId), owning an ordered list of widget settings (visible + order) stored as ajsonbcolumn. The ordered list is only ever mutated throughApply/Reset, which validate every key against theDashboardWidgetscatalog and keep the collection complete and de-duplicated. Unknown keys are rejected with aDomainException→400. Endpoints/DashboardQuery.csbuilds the compositeDashboardOverviewread model: an all-time status snapshot (grouped counts), a windowed set of instances materialized once, and resource/node counts. Instance status and terminal timestamps live on TPH subtypes (not columns), so rows are read in memory via the sharedInstanceEndpoints.GetStartedAt/GetStoppedAthelpers. Event time =stopped ?? started ?? created.Endpoints/DashboardModels.csholds the DTOs, the period→(window, bucket-count) plan, andDashboardMath— pure, deterministic bucketing + KPI/delta math (no I/O,nowis passed in).
KPI deltas compare the current window against the immediately preceding one (the query fetches a double window for this). There is no live account P&L feed — the platform only has equity for backtests and prop-firm tracking — so the dashboard is deliberately operational (activity, throughput, success rate), not a brokerage balance ticker.
Design & tokens
All colour comes from design tokens (var(--app-success|-warning|-error|-info|-primary|-text*)), so a
white-label palette flows through for free — including the chart, whose series colours are read from the
resolved tokens at runtime via window.appReadTokens (SVG can't consume CSS variables directly). No
hard-coded hex anywhere in the dashboard. See ../ui-guidelines.md.
The "Powered by cMind" link
The dashboard shows a small, tasteful "Powered by cMind" link that points to this documentation
site. It's shown by default — we're proud of the project and it helps other traders find
it — but it's entirely your call. Resellers running a fully white-labeled instance flip
App:Branding:ShowSiteLink to false and it disappears. See
White-label branding.
Tests
- Unit-style (
tests/IntegrationTests/DashboardMathTests.cs) — bucketing, success-rate, previous-period deltas, period parsing, empty/boundary (event atnow, divide-by-zero guard). - Unit (
tests/UnitTests/Dashboard/UserDashboardTests.cs) — theUserDashboardaggregate: default seed, apply order/visibility, append-omitted, duplicate-collapse, unknown-key rejection, reset. - Integration (
tests/IntegrationTests/DashboardQueryTests.cs,DashboardLayoutTests.cs) — the read model against real Postgres (status/KPIs/activity/resources, admin node health, empty-user path), the new backtests/copy-profiles/agents sections, and a layout round-trip (save custom layout → reload → order + visibility persisted). - E2E (
tests/E2ETests/DashboardTests.cs,DashboardCustomizeTests.cs) — desktop + mobile: KPI cards, chart, ring and feed render; the period toggle switches the active period and reloads; a KPI drills through to/run; hiding a widget persists across a reload, Reset brings it back, and the Customize dialog works on a phone with no horizontal overflow./is also inPageSmokeTests,MobileLayoutTests(shell + no-overflow) andMobileJourneyTests.