Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.

feat(kora): KR-HB-PANEL — heartbeat dashboard frontend shell (stub)#103

Merged
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-HB-PANEL
May 22, 2026
Merged

feat(kora): KR-HB-PANEL — heartbeat dashboard frontend shell (stub)#103
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-HB-PANEL

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

Operator-facing dashboard for the SaaS backends Joshua's work depends on: Vercel / Sentry / Doppler / Supabase / Fly. Stub-then-real pattern proven across 12+ prior CC#2 panel buckets. Real polling lands in the KR-FEAT-HEARTBEAT follow-on after KR-D-DAEMON ST2 ships the heartbeat scheduler.

Branch base: `feature/phase2-upgrades` (NOT main) per bucket §0. Bucket spec: `kora_docs/17_cc_bucket_prompts/KR-HB-PANEL_heartbeat_dashboard_stub.md` (commit `afdbb48`).

§2 K-DG verifications (grep'd vs bucket assumptions)

Bucket §2 said Reality (grep'd)
Panels under `web/src/pages/admin/` `web/src/pages/` — matches bucket §3(b)'s "wherever HEALTH-PANEL lives" clause
API client under `web/src/api/` `web/src/lib/api.ts` — matches every other CC#2 panel
Panels-manifest file doesn't exist; routing lives in App.tsx
Dashboard v2 just shipped confirmed — adds heartbeat card as the 5th in row 2

No spec-vs-reality issues that needed STOP-ASK — bucket's §2 K-DG block had minor convention drift but the bucket's other clauses point to the actual conventions (`/pages/`, `/lib/api.ts`). Built per the actual layout.

FE test framework — flagged

Bucket §4 asks for a frontend component test, but the project has zero FE-test infrastructure (no `test` script in `package.json`, no `*.test.tsx` files anywhere in `web/`). Setting one up (vitest + @testing-library/react + jsdom) is a substantial scope addition that's not in the bucket. Skipped per established CC#2 pattern across 12+ prior buckets (backend tests + tsc + vite + manual smoke). Worth a separate `infra/web-test-setup` bucket if PM wants to close this debt; happy to take it.

Backend

`GET /api/heartbeat/services` in `kora_cli/web_server.py` — hardcoded sample of the 5 services matching bucket §3 stub verbatim:

  • 4 healthy: `vercel` / `doppler` / `supabase` / `fly`
  • 1 degraded: `sentry` (with `unresolved_issues: 12`)
  • `stub: true` flag drives the FE banner

Frontend

`pages/HeartbeatPanel.tsx`:

  • Aggregate summary strip — total + per-status counts + generated-at relative
  • Per-service row — status icon + uppercase name + status pill + latency_ms + last-checked-relative; expandable detail panel renders the service-specific `details` dict as key/value pairs
  • STUB banner (yellow/orange) when `stub: true` with the `KR-FEAT-HEARTBEAT` flip-in note
  • Defensive empty-state for `services: []`

`lib/api.ts` — `HeartbeatStatus` type alias + `HeartbeatService` + `HeartbeatServicesResponse` interfaces + `getHeartbeatServices` client.

`App.tsx` — `/heartbeat` route + nav entry (`Heart` icon) between `/health-rollup` and `/boot-status`. Operator scans physical-health-of-services next to operational-state-of-Kora.

`DashboardPage.tsx` — new `Heartbeat` card on row 2. Grid bumped from `lg:grid-cols-4` → `lg:grid-cols-5` (the 5th card). Card body aggregates total + per-status pills; headline tone tracks the worst status (unhealthy → destructive, degraded → warning, else foreground) so operator scans the dashboard for "is anything wrong" and gets a colour cue without squinting at chips. `ALL_SOURCES` extended → footer count adds 1 stubbed source (the new heartbeat endpoint).

Test plan

  • `tests/kora_cli/test_web_server_heartbeat.py` — 8/8 green, covers all 6 §4 scenarios plus extras:
    • All-5-canonical-services pin
    • Sentry-is-degraded contract guard (the dashboard "1 degraded" aggregate depends on this)
    • Other-four-healthy counterpart
    • Per-service details-key shape spot-check (catches a future stub edit that drops a documented detail key)
    • Cron-regression sanity
  • Full admin-panel suite: 159/159 green across 15 test files (was 151/151 + 8 new = 159; bucket §4 target was 152/152, exceeded by extra coverage)
  • `npx tsc -b` on `web/` — clean
  • `npx vite build` on `web/` — clean
  • FE component tests — skipped per absent infra; flagged above
  • Manual smoke: navigate to `/heartbeat`, verify the 5 service rows render with sentry showing the orange "degraded" pill + 12 unresolved issues in the expandable detail; verify STUB banner shows; verify dashboard `/` shows the new Heartbeat card on row 2 with the headline number in warning-yellow tone (since 1 service is degraded); click the card and confirm navigation to `/heartbeat`

Flip-over plan

When KR-FEAT-HEARTBEAT ships the Python HeartbeatPoller (post-KR-D-DAEMON ST2), swap `get_heartbeat_services` body to project from the live poller state and drop the `stub` flag. Page UI is unchanged; the STUB banner auto-stops rendering once `stub:false` flows through. Dashboard card headline tone keeps tracking worst-status from real data.

🤖 Generated with Claude Code

Operator-facing dashboard for the SaaS backends Joshua's work depends
on: Vercel / Sentry / Doppler / Supabase / Fly. Stub-then-real pattern
proven across 12+ prior CC#2 panel buckets (CHARTER, COST, HEALTH,
etc.). Real polling lands in the KR-FEAT-HEARTBEAT follow-on after
KR-D-DAEMON ST2 ships the heartbeat scheduler.

Branch base: feature/phase2-upgrades (NOT main) per bucket §0.

§2 K-DG verifications (grep'd vs bucket assumptions):
  * Panel location: web/src/pages/ (NOT web/src/pages/admin/ as
    bucket §2 hinted) — matches bucket §3(b)'s "wherever HEALTH-PANEL
    lives" clause, which is web/src/pages/HealthRollupPage.tsx.
  * API client: web/src/lib/api.ts (NOT web/src/api/ as bucket §2
    hinted) — matches every other CC#2 panel.
  * No "panels manifest" file exists; routing lives in App.tsx.
  * Dashboard v2 just merged (PR #95 4d1bc11... actually e76cf12) —
    new card added to row 2 grid.

FE test framework: bucket §4 asks for one but the project has zero
FE-test infrastructure (no test runner in package.json, no .test.*
files). Skipped per established CC#2 pattern across 12+ prior
buckets (backend tests + tsc + vite + manual smoke). PR body
documents the gap.

Backend:
  * GET /api/heartbeat/services in kora_cli/web_server.py. Hardcoded
    sample of 5 services matching bucket §3 stub verbatim: 4 healthy
    (vercel/doppler/supabase/fly) + 1 degraded (sentry, 12 unresolved
    issues). stub: True flag drives the FE banner.

Frontend:
  * pages/HeartbeatPanel.tsx —
    - Aggregate summary strip: total + per-status counts +
      generated-at relative
    - Per-service row: status icon + uppercase name + status pill +
      latency_ms + last-checked-relative; expandable detail panel
      shows the service-specific details dict as key/value pairs +
      the absolute last_check_at timestamp
    - STUB banner (yellow/orange) renders when stub: true with the
      KR-FEAT-HEARTBEAT flip-in note
    - Empty state for services: [] (defensive — stub always has 5
      but the real poller might temporarily return [])
  * api.ts — HeartbeatStatus type + HeartbeatService +
    HeartbeatServicesResponse interfaces + getHeartbeatServices
    client.
  * App.tsx — /heartbeat route + nav entry (Heart icon) between
    /health-rollup and /boot-status. Operator scans the
    physical-health-of-services next to operational-state-of-Kora.
  * DashboardPage.tsx — new Heartbeat card on row 2. Grid bumped
    from lg:grid-cols-4 to lg:grid-cols-5 (the 5th card). Card body
    aggregates total + per-status pills; headline tone tracks the
    worst status (unhealthy → destructive, degraded → warning, else
    foreground) so operator scans the dashboard for "is anything
    wrong" and gets a colour cue without squinting at chips.
    ALL_SOURCES extended → footer count = 12 sources / 1 stubbed
    today (the stub flag adds 1 to stubbed; other sources unchanged).

Tests: tests/kora_cli/test_web_server_heartbeat.py — 8 tests
covering all 6 §4 scenarios plus extras:
  * All-5-canonical-services pin (sentry/vercel/doppler/supabase/fly)
  * Sentry-is-degraded contract guard (the dashboard "1 degraded"
    aggregate depends on this stub assertion)
  * Other-four-healthy counterpart guard
  * Per-service details-key shape spot-check (catches a future stub
    edit that drops a documented detail key)
  * Cron-regression sanity

159/159 across 15 admin-panel test files (was 151/151 before, +8
new). tsc -b + vite build clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant