Skip to content

feat(panel): Insights dashboard, home KPI deltas, and daily activity trend#239

Merged
upsetbit merged 16 commits into
masterfrom
feat/panel-insights-analytics
Jun 12, 2026
Merged

feat(panel): Insights dashboard, home KPI deltas, and daily activity trend#239
upsetbit merged 16 commits into
masterfrom
feat/panel-insights-analytics

Conversation

@upsetbit

@upsetbit upsetbit commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Expands the panel's analytics surface with nine user-confirmed additions, split between the Home dashboard and a new Insights page (hybrid layout).

Home

  • KPI deltas: every KPI (sessions, projects, models, tokens, est. spend, error rate) gains a ±% badge vs the immediately-preceding window of equal length. Tones: volume up = green, error rate up = red (inverted), est. spend always neutral. Skipped for last=all.
  • Activity trend card: sessions per day in the filtered window, stacked by agent (top 4 + other), collapsing to ISO weeks past 120 days.

New /insights page (same filter chrome as Home, shared via a new dashboard_filters.html partial)

  • Spend & tokens per day — est. spend columns + cumulative overlay line, tokens area chart; priced panel-side via internal/pricing
  • Model share over time — weekly share of sessions per model, normalized stacks
  • Punch card — weekday × local hour 7×24 grid (UTC rotated with weekday carry), heatmap color levels
  • Streaks & consistency — current/longest streak, % active days
  • Schedule profile — weekend share, outside-09–18h share, busiest weekday
  • Session duration — fixed-bucket histogram + median/p90/longest
  • Subagents — spawning sessions, children, max fan-out, per parent agent

Server — five new panel-only GetReport names (no proto schema change, no CLI/SQLite mirror): usage_by_day, punchcard, durations, duration_stats, subagents.

Charts — new deterministic charts.StackedColumns SVG helper (Normalize for share views, Overlay for cumulative lines), golden-tested like Area/Donut.

Testing

  • just ci green (tidy-check, gen-check, vet, lint, test-race, CLI integration, build), with the server analytics e2e running against a real Postgres 17
  • New e2e coverage for all five reports (bucket math, percentiles, punchcard cells, fan-out grouping)
  • New unit tests: punchcard TZ rotation with day carry, streak edges, duration bucket ordering, spend pricing fallbacks, weekly cutover, KPI delta semantics
  • Render tests drive the real handlers + templates for both pages
  • Full local stack verification (throwaway Postgres + MinIO, seeded data): both pages render every card with correct values

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

upsetbit and others added 16 commits June 9, 2026 22:27
New panel-only GetReport names (no CLI/SQLite mirror): usage_by_day,
punchcard, durations, duration_stats, subagents. All reuse buildWhere
and the stringly runReport contract; durations share one clamped
EPOCH-span subquery, subagents group fan-out by the parent's agent
while window filters apply to the children.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
charts.StackedColumns renders per-label columns with one stacked
segment per series, palette-matched to PaletteColor for HTML legends.
Normalize turns it into a share-of-total view; Overlay draws a line on
its own max-scale with an end marker (cumulative spend). Deterministic
output, golden-tested like Area/Donut.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…artial

parseDashboardWindow, dashboardReportRequest, and
buildDashboardActiveFilters move to handlers_filters.go; the filter
drawer + active-chips markup moves to a shared dashboard_filters.html
partial parameterized by PageTitle/FilterAction. No behavior change —
prepares the Insights page to reuse the same filter chrome.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New /insights route behind the same session gate, sharing the home
filter chrome. Cards: spend & tokens per day (priced panel-side, with
cumulative overlay and ISO-week bucketing past 120 days), weekly model
share (top-4 + other, normalized), weekday × local-hour punch card
(UTC rotation with day carry, heatmap color levels), streak/consistency
and schedule-profile KPIs, session-duration histogram with percentile
stats, and subagent fan-out. last=all clamps daily-resolution charts to
trailing 365d so the zero-filled day span stays bounded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every KPI gains a ±% badge against the immediately-preceding window of
equal length (5 extra RPCs in the existing fan-out; skipped for
last=all). Movement tones: up is good for volume KPIs, bad for the
error rate, and always neutral for est. spend. buildUsage now returns
numeric cost so deltas and labels share one source. New Activity trend
card stacks sessions per day (ISO weeks past 120 days) by agent via the
windowed heatmap report, clamped to trailing 365d for last=all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Server: the five panel-only GetReport names and their shapes. Panel:
GET /insights route, the Insights screen spec (cards, states, UTC/DST
caveats), the Home activity-trend card and KPI delta badges, the
StackedColumns chart helper, and the punch card as an HTML-grid
component.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Embed frappe-charts.min.umd.js (v1.6.2, MIT, ~18 KB gzip) via the
existing assets embed.FS and load it (plus charts-init.js) from
base.html. The library self-injects its CSS; no separate stylesheet.
Vendoring a prebuilt UMD file is not a build step — same posture as
htmx/alpine.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add --chart-1..8 to tokens.css for the dark, light, and system-light
themes, replacing the monochromatic blue->gray donut ramp. charts-init.js
reads these so a theme swap recolors every chart and its legend dots.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the server-side SVG Donut/Area/StackedColumns helpers and their
golden tests in favor of charts.Spec, a JSON-serializable chart spec
rendered client-side by Frappe Charts. spec_test.go asserts the JSON
shape (script-close escaping, has-data, omitempty) in place of golden SVG.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite buildModelUsage/buildHourChart/buildActivityTrend (home) and
buildSpendTrend/buildModelShare (insights) to produce charts.Spec instead
of template.HTML SVG; legend rows carry a palette index. Model-share is
pre-normalized to 100% in Go (Frappe has no percentage-stacked mode); the
spend cumulative overlay is dropped (no secondary axis) — the running
total stays in the card subtitle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add charts-init.js (parses each card's JSON island, resolves the palette,
renders with animation + hover tooltips, re-renders on htmx swap / theme
flip) and charts.css (re-skins Frappe's axis/gridline/tooltip chrome with
the design tokens, hides its built-in legend). Templates emit a
[data-chart] container + JSON island per card with palette-indexed legend
dots. Remove the now-dead .area-chart/.donut/.trend-chart svg rules.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update INTENT, architecture/panel.md, the panel design
brief/components/screens, agents.md, the panel-rendering skill, and both
panel-ui-reviewer configs to describe Frappe Charts fed a Go-built JSON
spec. Note the explicit carve-out that vendoring a prebuilt UMD via
embed.FS is not a build step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Trim the insights/dashboard comments to the repo's sparse style: drop
narration of self-evident code and compress multi-line docstrings to one
line, keeping only terse rationale. No behaviour change. gen/ regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-analytics

# Conflicts:
#	docs/panel/screens.md
#	internal/panel/charts/donut.go
#	internal/panel/handlers_dashboard.go
Frappe Charts paints axis and grid lines with inline style attributes
(style="stroke: #dadada"), which outrank any stylesheet selector, so
the existing token-based override never applied and charts rendered
light-gray lines on the dark theme. Re-skin them with !important and a
new --chart-grid token, quieter than --divider on both themes. Lighten
the tooltip shadow while there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r dots)

xAxisMode 'tick' drops the full-height vertical gridline per x label,
shortenYAxisNumbers compacts the y scale (800000000 -> 800M), and line
charts get smaller dots, hidden entirely on dense series (>24 points)
where they read as a string of beads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@upsetbit upsetbit merged commit eacc801 into master Jun 12, 2026
5 checks passed
@upsetbit upsetbit deleted the feat/panel-insights-analytics branch June 15, 2026 01:56
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.

1 participant