Skip to content

feat: add reports page with cost/token charts and CSV export#854

Draft
diogenesc wants to merge 2 commits into
Soju06:mainfrom
diogenesc:feat/reports-page
Draft

feat: add reports page with cost/token charts and CSV export#854
diogenesc wants to merge 2 commits into
Soju06:mainfrom
diogenesc:feat/reports-page

Conversation

@diogenesc
Copy link
Copy Markdown

@diogenesc diogenesc commented May 29, 2026

New /reports page in the dashboard for historical cost and usage analysis.

What's implemented

Backend — new app/modules/reports/ module:

  • GET /api/reports endpoint with filters (start_date, end_date, account_id, model)
  • SQL aggregations by day, model, and account on the request_logs table
  • SQLite and PostgreSQL support

Frontend — new /reports page:

  • Summary cards (total cost, tokens, requests)
  • Area chart: Cost per Day
  • Area chart: Tokens per Day (input/output)
  • Donut: Cost Distribution by Model
  • Daily detail table with CSV export
  • Filters with presets 7d/30d/90d and custom date picker
  • Consistent design with shadcn/ui + Tailwind + Recharts

@Soju06
Copy link
Copy Markdown
Owner

Soju06 commented Jun 1, 2026

Hermes owner-review blocker pass (current head c73f1b9):

  • SQLite /api/reports path currently crashes. app/modules/reports/repository.py:54 calls cast(RequestLog.requested_at, String).substring(0, 10), but SQLAlchemy Cast has no .substring() comparator. Local smoke result: AttributeError: Neither 'Cast' object nor 'Comparator' object has an attribute 'substring'. Use the existing SQLite func.strftime(...)-style date aggregation pattern instead.
  • OpenSpec merge gate is missing for this behavior/API/UI change. The PR adds GET /api/reports and a new dashboard /reports page, but git diff --name-only origin/main...HEAD -- openspec/changes openspec/specs openspec is empty. Please add a real openspec/changes/<slug>/ change with parseable deltas for the new reports API/UI contract.
  • Current backend lint fails. uvx ruff check app/modules/reports app/dependencies.py app/main.py reports I001 import ordering in app/modules/reports/service.py:1.

Also worth fixing before re-review: nullable request_logs.account_id can flow into AccountCostEntry.account_id: str (repository.py:175-178, schemas.py:25-29), which can break response construction for historical rows whose account was deleted.

@Soju06 Soju06 added the hermes: needs-followup Hermes left a blocker/comment that needs follow-up observation label Jun 1, 2026
@Komzpa Komzpa removed the hermes: needs-followup Hermes left a blocker/comment that needs follow-up observation label Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants