Skip to content

F3.B — Admin WebUI: usage dashboard with uPlot + CSV export #35

@HXYerror

Description

@HXYerror

Part of #23. Depends on F1.D, F3.A.

Background

Operators need to see token spend by key × model × time without writing SQL.

Goal

/admin/usage renders charts (requests/min, tokens/h, p95 latency/h) with filters for time range, key, and model; supports CSV export.

Tasks

  • Server-rendered HTML page with 3 uPlot charts:
    • Requests per minute (stacked by model)
    • Prompt + completion tokens per hour
    • p95 latency per hour
  • Filter form: time range (1h, 24h, 7d, 30d, custom), key (multi-select), model (multi-select)
  • Top-N tables: top keys by tokens, top models by requests, error rate by key
  • All queries use covering indices from F3.A; verify via EXPLAIN QUERY PLAN in tests
  • CSV export at /admin/usage/export.csv?… — streams rows for >1M-row windows; RFC 4180 quoting (per backend review [Epic] Admin Plane: model config, multi-key auth, usage dashboard, debug mode #23) so model names with commas don't break Excel
  • Vendored uPlot (~12 KB) from /admin/assets/uplot.min.js; no CDN
  • Use events snapshot or BEGIN IMMEDIATE for consistent reads during long aggregations
  • Tests: TTFB < 200 ms with 1M fixture events, query plans use indices, CSV parses cleanly in csv-parse

Acceptance criteria

  • Charts render in browser with 1M-event fixture in < 1s
  • CSV opens correctly in Excel/Numbers, no broken rows for models with commas
  • All queries on the dashboard hit indices (verified)

⚠️ Open question

Should CSV export be paginated (download in chunks) or a single streamed file? Recommended: streamed file (Bun handles this natively). Flag if you want pagination instead.

File pointers

  • New: src/admin/usage/{page,export}.tsx, src/admin/usage/queries.ts, tests/usage-queries.test.ts
  • Touch: src/admin/layout.tsx

Dependencies

Depends on F1.D, F3.A.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions