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
Merged
Conversation
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>
This was referenced May 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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)
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:
Frontend
`pages/HeartbeatPanel.tsx`:
`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
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