Skip to content

feat(dashboard): operational dashboard with reporting views and alerts - #5

Merged
nickgreengithub merged 1 commit into
mainfrom
feat/dashboard
Aug 16, 2026
Merged

nickgreengithub merged 1 commit into
mainfrom
feat/dashboard

Conversation

@nickgreengithub

Copy link
Copy Markdown
Owner

The Assessment 3 reporting surface — /dashboard.

Panels: health strip · rule-based alerts · operational totals (requests, unique clients, feed polls, items served, latency, error rate) · requests per feed · feed status table · requests per endpoint · requests per client · response codes · stored content · recent activity. Window selector (15m/1h/24h/7d) and a live/paused toggle.

Design notes

  • lib/dashboard.ts collects everything in one pass, shared by the route handler and the page — one point in time, so no two panels can disagree.
  • First snapshot renders on the server; the client polls from there. No loading state, no empty first paint.
  • The only useEffect subscribes to a timer; the window switch fetches from the click handler where it belongs.
  • Bars are CSS, not a chart library — one-dimensional comparisons don't justify a bundle and a canvas screen readers can't read.

Two bugs caught by actually opening the page

  1. Dashboard polling was being logged, so within a minute /api/dashboard was the busiest endpoint and was inflating its own totals. Monitoring paths are now excluded from the request log.
  2. The page didn't scroll — this shell scrolls the view body, and I'd omitted the wrapper every other long page uses.

Verified in-browser (both themes) and via API: 12 generated requests report as exactly 12, with 2 distinct clients.

🤖 Generated with Claude Code

The reporting surface for Assessment 3. /api/stats and /api/count were built
in Assessment 2 and had no consumer; this gives the measurements somewhere to
be read.

Structure:

- lib/dashboard.ts collects everything in one pass, shared by the API route
  and the page. The alternative — the browser calling /api/health, /api/count
  and /api/stats and stitching them together — is three round trips that must
  agree with each other, which is three chances to render a panel that
  contradicts the panel beside it.
- The page renders the first snapshot on the server, so the view arrives
  populated rather than empty-then-filled, and there is no loading state to
  design. The client component then polls every ten seconds.
- The only effect subscribes to a timer. Changing the reporting window fetches
  from the click handler, because it is a user action, not a render concern.

Views: health strip, rule-based alerts, operational totals, requests per feed,
a feed status table, requests per endpoint and per client, response codes,
stored content, and recent activity.

Alerts have two levels rather than one. A warning says something is drifting;
a critical says someone has to act. A single threshold only ever tells you
once it is already too late.

Two problems found by looking at the running page rather than by reasoning
about it:

- The dashboard polls /api/dashboard every ten seconds, and those polls were
  being logged. Within a minute it was the busiest endpoint on the server,
  pushing real traffic out of the recent-activity list and inflating the
  totals it was itself displaying. Monitoring endpoints are now excluded from
  the request log, the same treatment /api/metrics already had.
- The page did not scroll. This shell keeps the header and footer fixed and
  scrolls the view body, so content needs the view-body scroll-area wrapper
  that every other long page uses.

Verified in the browser at both light and dark themes, and against the API:
after the fix, twelve generated requests report as exactly twelve.

Co-Authored-By: Claude <noreply@anthropic.com>
@nickgreengithub
nickgreengithub merged commit 87fe5e1 into main Aug 16, 2026
2 checks passed
@nickgreengithub
nickgreengithub deleted the feat/dashboard branch August 16, 2026 22:54
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