Dashboard¶
Purpose¶
The Dashboard is the operator's at-a-glance view of platform health: KPIs (registrations, FTDs, deposits, withdrawals, GGR/NGR, ATPU/ARPU), turnover by game type, and finance reconciliation. It is the single screen leadership and operations look at first thing in the morning to see whether yesterday went sideways. Evospin ships two implementations living side by side — the older v1 dashboard/ controller and the v2 dashboard-v2/ controller — and the admin-fe wires both.
Audience¶
Operations, finance, leadership. Engineering uses it secondarily as a "did our deploy break GGR" smoke test.
Path in admin-fe¶
| Tab | URL | Page |
|---|---|---|
| Overview (landing) | / |
ebit-admin-fe/src/app/(dashboard)/page.tsx → components/pages/overview/index.tsx |
| Dashboard (general) | /dashboard |
ebit-admin-fe/src/app/(dashboard)/dashboard/page.tsx |
| Dashboard / Games | /dashboard-games |
ebit-admin-fe/src/app/(dashboard)/dashboard-games/page.tsx |
| Dashboard / Game by Slug | /dashboard-game-by-slug-stats |
ebit-admin-fe/src/app/(dashboard)/dashboard-game-by-slug-stats/page.tsx |
| Dashboard / Finances | /dashboard/finances |
ebit-admin-fe/src/app/(dashboard)/dashboard/finances/page.tsx |
| Games chart (in-house) | /games-chart |
ebit-admin-fe/src/app/(dashboard)/games-chart/page.tsx |
Tab routing: components/common/DashboardTabs/index.tsx reads usePathname() to highlight the active tab.
Backing API endpoints¶
| Endpoint | Source |
|---|---|
GET /admin/dashboard/quick-stats |
apps/api/src/dashboard/admin.dashboard.controller.ts:27 |
GET /admin/dashboard/finance-tab |
apps/api/src/dashboard/admin.dashboard.controller.ts:33 |
GET /admin/dashboard/games-stats |
apps/api/src/dashboard/admin.dashboard.controller.ts:41 |
GET /admin/dashboard/games-charts |
apps/api/src/dashboard/admin.dashboard.controller.ts:49 |
GET /admin/dashboard/affiliate-stats |
apps/api/src/dashboard/admin.dashboard.controller.ts:57 |
GET /admin/dashboard/users-stats |
apps/api/src/dashboard/admin.dashboard.controller.ts:64 |
GET /admin/dashboard/providers-stats |
apps/api/src/dashboard/admin.dashboard.controller.ts:71 |
GET /admin/dashboard-v2/main/stats |
apps/api/src/dashboard-v2/admin.dashboard-combined.controller.ts:27 |
GET /admin/dashboard-v2/game/stats |
apps/api/src/dashboard-v2/admin.dashboard-combined.controller.ts:34 |
GET /admin/dashboard-v2/main/options |
apps/api/src/dashboard-v2/admin.dashboard-combined.controller.ts:41 |
GET /admin/dashboard-v2/query/games-by-slug |
apps/api/src/dashboard-v2/admin.dashboard-separated.controller.ts:27 |
GET /admin/dashboard-v2/query/games-by-type |
apps/api/src/dashboard-v2/admin.dashboard-separated.controller.ts:34 |
GET /admin/dashboard-v2/query/bets-by-type |
apps/api/src/dashboard-v2/admin.dashboard-separated.controller.ts:41 |
GET /admin/dashboard-v2/query/payments |
apps/api/src/dashboard-v2/admin.dashboard-separated.controller.ts:48 |
GET /admin/dashboard-v2/query/registrations |
apps/api/src/dashboard-v2/admin.dashboard-separated.controller.ts:55 |
Frontend wiring: ebit-admin-fe/src/queries/dashboard/index.ts, queries/overview/, queries/finances/.
Key actions¶
| Action | Required role | API call | DB / source | Audit-logged? |
|---|---|---|---|---|
| View KPIs (reg, FTD, deposit, withdraw) | dashboard.view permission |
GET /admin/dashboard/quick-stats |
aggregations over User, Withdraw, Deposit, Bet |
yes (read-through AdminActionLog) |
| View finance tab (reconciliation) | dashboard.view |
GET /admin/dashboard/finance-tab |
Vault*, Accounting* tables |
yes |
| Drill into per-game stats | dashboard.view |
GET /admin/dashboard-v2/query/games-by-slug?slug=... |
Bet, Game |
yes |
| Drill into in-house RTP charts | dashboard.view |
GET /admin/dashboard/games-charts |
Bet (house games) |
yes |
| Switch date range / granularity | n/a (UI-only) | passes startDate, endDate, granularity query params |
- | no |
AdminActionLog rows are written per request via the action-log middleware; see data-model/ for the full schema (AdminActionLog lives in libs/_prisma/src/schema/api.prisma:1479-1497).
Filters and views¶
- Date range selector (today, last 24h, custom). Posted as
startDate/endDate(ISO). - Granularity (
hour/day). Drives thegroupByclause server-side. - Game type filter on Games tab (slots / house games / sportbook).
- Per-graph visibility toggles in
components/pages/dashboard/Filters/. - Currency context is always USD-equivalent — see
getUserUsdBalanceQueryand theadmin/accounting/usd-balance/...endpoints. There is no per-currency dashboard breakdown.
Common workflows¶
- Morning health check. Operator opens
/, scans Overview cards (OverviewCards), then jumps to/dashboardfor time-series. Looks for: anomalous deposit-vs-withdraw ratio, NGR drift, registration spike (bot signal). - Spike investigation. Spike on
Reg Count. Operator opens/dashboard→ users-stats → cross-references with/admin-logs(see admin-logs.md) to see if a promo code drove it. If not, escalate to bots — see bots.md. - Finance reconciliation. Finance opens
/dashboard/financesfor vault balances and net flow per currency. They cross-check against the live accounting endpoint atGET /admin/accounting/balances(seeapi-reference/bo.md). - Per-game RTP audit. RTP looks "off" on Plinko. Operator opens
/games-chart, picks Plinko, narrows date range. Calls/admin/dashboard/games-chartsserver-side; compares to provably-fair seed validation inflows/. - Provider performance. Operator opens
/games/stats/providers. ViewsGET /admin/dashboard/providers-statsto compare BGaming vs PM8 vs ST8 vs evogames revenue + margin.
Edge cases / gotchas¶
- Two dashboard backends. v1 (
/admin/dashboard/...) is in maintenance mode; v2 (/admin/dashboard-v2/...) is the new home. The admin-fe still calls both. If a metric disagrees across tabs, that's why — they query slightly different aggregations. Tracked in repo issues; do not "fix" by editing v1. - Online-count is inflated. Any "online users" widget on Overview is sourced from the
UsersOnlineUpdatedsocket event, which adds afakeUserOnlinefloor of 180-500. Per-screen counters are intentionally padded — seeproject_online_count_inflationmemory. - Day boundaries are UTC. Granularity is computed against
UTC, not browser-local. A 23:30 EST bet lands in tomorrow's bucket on the chart. - No per-locale segmentation. No EU / UK / RoW split surfaces here. For that, query
admin/country(api-reference/bo.md). - Data lag. Dashboard reads BullMQ-aggregated rollups for some stats (
user-stats-migrationqueue); a fresh deposit may take up to 60 s to surface inusers-stats.
Cross-links¶
- Runbook for stale dashboard data:
runbooks/→ "dashboard not updating" - ADR on the v1 → v2 split:
adr/ - Related flow:
flows/→ bet-place / deposit / withdraw (the screens that feed these aggregates) - For per-user rollups (not platform-wide): see user-profile.md
- The Overview card definitions:
ebit-admin-fe/src/components/pages/overview/const/
Sequence — opening the Overview tab¶
sequenceDiagram
actor admin
participant admin-fe
participant api
participant pg as Postgres
admin->>admin-fe: GET /
admin-fe->>admin-fe: middleware.ts checks JWT + MFA cookie
admin-fe->>api: GET /admin/dashboard/quick-stats?startDate=...&endDate=...
api->>api: PermissionGuard('dashboard.view')
api->>pg: aggregate User/Bet/Deposit/Withdraw
pg-->>api: rows
api-->>admin-fe: KPI payload
admin-fe->>api: GET /admin/dashboard-v2/query/registrations?...
api->>pg: time-series aggregate
pg-->>api: bucketed rows
api-->>admin-fe: chart series
admin-fe-->>admin: rendered cards + charts