feat(ui): Phase 25 — operator admin dashboard (Dioxus + Bootstrap 5.3.3, shared with _ui_wasm) #10

Open
opened 2026-05-06 17:47:10 +00:00 by mik-tf · 2 comments
Owner

Why

hero_assistance has a customer-facing SPA (_ui_wasm) but no operator-facing admin dashboard. Every Hero service ships an admin dashboard with Logs / Stats / Domain / Admin / Docs tabs + system-stats sidebar (per hero_ui_dashboard skill).

Decision: build the dashboard in Dioxus 0.7 + dioxus-bootstrap-css rather than canonical Askama+Unpoly. File D-22 documenting the deviation. Justified because:

  • dioxus-bootstrap-css already vendors Bootstrap 5.3.3 with typed components
  • _ui_wasm already has /rpc proxy, theme handling (Phase 16a assist:// URI scheme), SSE wiring (D-20)
  • Shared component library between customer SPA and operator dashboard halves the code
  • Signal-driven reactivity replaces Unpoly polling more cleanly
  • Visual output identical to canonical Askama dashboard (Bootstrap 5.3.3 is the source of truth)

Cost: hero_assistance is the only Hero service with a Dioxus admin dashboard. Future maintainers see D-22 first.

Order: Phase 25 first, then 24. Phase 25 has zero dependency on hero_proc lifecycle work; can be built and validated against any running hero_assistance_server. Derisks the deviation early.

What

A. Dashboard structure (per hero_ui_dashboard skill)

Three zones: navbar (brand + clock + refresh + theme toggle + status dot) / sidebar (live system stats with sparklines) / content area (tab bar + per-tab content).

B. Tabs

Domain tabs (with badge counts):

  • Tickets — list, filter by status/project/assignee, search, bulk close/archive
  • Users — enrolled users, magic-link audit log, role/group management
  • Projects — project list (single project per server typically, but UI surfaces it)
  • Comments — recent activity, search, threading view

Utility tabs:

  • Logshero_log integration; filter by level/source/time range; live tail
  • Stats — bigger summary cards + time-series memory/CPU/connections
  • Admin — Shutdown, Stop All, Clean Old Tickets, Reset DB (dev-only), Demo Data
  • Docs/openrpc.json rendered at runtime per hero_ui_dashboard_admin skill (left: method browser grouped by capability; right: full method documentation with curl example, params, errors, side effects). All 91 methods auto-render from Phase 23 OpenRPC spec.

C. Sidebar widgets

  • Memory gauge + sparkline
  • CPU gauge + sparkline
  • Mycelium peer count, RX/TX bandwidth, sparkline
  • Tickets open / in-progress / resolved counts (color-coded)
  • Comments total / today / live counter

D. Auth

UDS / localhost-only binding. No login forms. Whitelist via hero_ui_whitelists pattern with ADMIN_SECRETS from hero_proc secrets (Phase 24 dependency for full integration; static config OK for Phase 25 standalone validation).

E. Routing — decide in step 1

  • Option A: extend _ui_wasm with /admin/* routes (single SPA, two view modes)
  • Option B: new _admin_ui_wasm crate (sibling, shared _ui_wasm_components library extracted)

Pick based on extracted-component-library complexity vs single-binary footprint.

F. Connection status widget

Per hero_ui_connection_status — green pulse / red disconnected / amber backend-down with text labels in degraded states.

Acceptance

  • cargo build --release succeeds for the dashboard crate
  • dx build --release produces a working WASM bundle
  • All 8 tabs render (4 domain + 4 utility)
  • Sidebar widgets update via signals (no flicker, no polling jitter)
  • Docs tab auto-renders all 91 methods from /openrpc.json with: name, summary, description, params, curl example, response example, error codes, x-hero-intent metadata
  • Admin tab "Shutdown" calls hero_proc to stop the service (gracefully)
  • Theme toggle works (data-bs-theme dark/light)
  • Connection-status widget reports backend health correctly
  • Visually consistent with reference Hero dashboards (compare to hero_proc_ui screenshots)
  • D-22 written and committed
  • All 225 native tests still pass

Files to touch

  • New: crates/hero_assistance_admin_ui_wasm/ OR new routes in _ui_wasm (Option A vs B)
  • New: decisions/D-22-dioxus-admin-dashboard.md
  • New: tests/baselines/admin-{tickets,users,logs,stats,admin,docs}.png (visual regression)
  • Update: crates/hero_assistance_ui/src/main.rs — admin dashboard dist serving
  • Update: Cargo.toml workspace members + default-members

Out of scope

  • hero_proc lifecycle (Phase 24)
  • Island/postMessage protocols (Phase 26)
  • hero_demo registration (Phase 27)

References

  • Skill hero_ui_dashboard — canonical dashboard pattern (1187-line spec)
  • Skill hero_ui_dashboard_admin — admin section + OpenRPC docs renderer
  • Skill hero_ui_connection_status
  • Skill hero_ui_theme
  • Skill hero_ui_whitelists
  • Skill hero_log
  • Reference impls: hero_proc_ui (canonical), hero_books_ui, hero_db_ui
## Why hero_assistance has a customer-facing SPA (`_ui_wasm`) but no operator-facing admin dashboard. Every Hero service ships an admin dashboard with Logs / Stats / Domain / Admin / Docs tabs + system-stats sidebar (per `hero_ui_dashboard` skill). Decision: build the dashboard in **Dioxus 0.7 + dioxus-bootstrap-css** rather than canonical Askama+Unpoly. File **D-22** documenting the deviation. Justified because: - `dioxus-bootstrap-css` already vendors Bootstrap 5.3.3 with typed components - `_ui_wasm` already has `/rpc` proxy, theme handling (Phase 16a `assist://` URI scheme), SSE wiring (D-20) - Shared component library between customer SPA and operator dashboard halves the code - Signal-driven reactivity replaces Unpoly polling more cleanly - Visual output identical to canonical Askama dashboard (Bootstrap 5.3.3 is the source of truth) Cost: hero_assistance is the only Hero service with a Dioxus admin dashboard. Future maintainers see D-22 first. **Order: Phase 25 first, then 24.** Phase 25 has zero dependency on hero_proc lifecycle work; can be built and validated against any running `hero_assistance_server`. Derisks the deviation early. ## What ### A. Dashboard structure (per `hero_ui_dashboard` skill) Three zones: navbar (brand + clock + refresh + theme toggle + status dot) / sidebar (live system stats with sparklines) / content area (tab bar + per-tab content). ### B. Tabs Domain tabs (with badge counts): - **Tickets** — list, filter by status/project/assignee, search, bulk close/archive - **Users** — enrolled users, magic-link audit log, role/group management - **Projects** — project list (single project per server typically, but UI surfaces it) - **Comments** — recent activity, search, threading view Utility tabs: - **Logs** — `hero_log` integration; filter by level/source/time range; live tail - **Stats** — bigger summary cards + time-series memory/CPU/connections - **Admin** — Shutdown, Stop All, Clean Old Tickets, Reset DB (dev-only), Demo Data - **Docs** — `/openrpc.json` rendered at runtime per `hero_ui_dashboard_admin` skill (left: method browser grouped by capability; right: full method documentation with curl example, params, errors, side effects). All 91 methods auto-render from Phase 23 OpenRPC spec. ### C. Sidebar widgets - **Memory** gauge + sparkline - **CPU** gauge + sparkline - **Mycelium** peer count, RX/TX bandwidth, sparkline - **Tickets** open / in-progress / resolved counts (color-coded) - **Comments** total / today / live counter ### D. Auth UDS / localhost-only binding. **No login forms.** Whitelist via `hero_ui_whitelists` pattern with `ADMIN_SECRETS` from hero_proc secrets (Phase 24 dependency for full integration; static config OK for Phase 25 standalone validation). ### E. Routing — decide in step 1 - **Option A**: extend `_ui_wasm` with `/admin/*` routes (single SPA, two view modes) - **Option B**: new `_admin_ui_wasm` crate (sibling, shared `_ui_wasm_components` library extracted) Pick based on extracted-component-library complexity vs single-binary footprint. ### F. Connection status widget Per `hero_ui_connection_status` — green pulse / red disconnected / amber backend-down with text labels in degraded states. ## Acceptance - [ ] `cargo build --release` succeeds for the dashboard crate - [ ] `dx build --release` produces a working WASM bundle - [ ] All 8 tabs render (4 domain + 4 utility) - [ ] Sidebar widgets update via signals (no flicker, no polling jitter) - [ ] Docs tab auto-renders all 91 methods from `/openrpc.json` with: name, summary, description, params, curl example, response example, error codes, x-hero-intent metadata - [ ] Admin tab "Shutdown" calls hero_proc to stop the service (gracefully) - [ ] Theme toggle works (data-bs-theme dark/light) - [ ] Connection-status widget reports backend health correctly - [ ] Visually consistent with reference Hero dashboards (compare to hero_proc_ui screenshots) - [ ] D-22 written and committed - [ ] All 225 native tests still pass ## Files to touch - New: `crates/hero_assistance_admin_ui_wasm/` OR new routes in `_ui_wasm` (Option A vs B) - New: `decisions/D-22-dioxus-admin-dashboard.md` - New: `tests/baselines/admin-{tickets,users,logs,stats,admin,docs}.png` (visual regression) - Update: `crates/hero_assistance_ui/src/main.rs` — admin dashboard dist serving - Update: `Cargo.toml` workspace members + default-members ## Out of scope - hero_proc lifecycle (Phase 24) - Island/postMessage protocols (Phase 26) - hero_demo registration (Phase 27) ## References - Skill `hero_ui_dashboard` — canonical dashboard pattern (1187-line spec) - Skill `hero_ui_dashboard_admin` — admin section + OpenRPC docs renderer - Skill `hero_ui_connection_status` - Skill `hero_ui_theme` - Skill `hero_ui_whitelists` - Skill `hero_log` - Reference impls: `hero_proc_ui` (canonical), `hero_books_ui`, `hero_db_ui`
Author
Owner

Session 39 progress — Phase 25 infrastructure landed (Stages 1-3)

Three commits this session:

  • a0381fa — file #13 Phase 27-prep (orthogonal to Phase 25; release-infra audit found 6 tags / 0 Releases) and integrate into roadmap (order: 25 -> 24 -> 26 -> 27-prep -> 27)
  • 73d58c4Stage 1: scaffold _admin_ui_wasm + _ui_wasm_components crates (additive; clean compile)
  • 6f7ef00Stages 2 + 3: clean /admin from _ui_wasm (-657 LoC; deleted Phase-9a hero_collab IndexPage + Layout artifacts) + wire _ui server with --admin-dist <path> flag + admin handlers + byte-passthrough /openrpc.json proxy + file D-22

What landed

  • hero_assistance_ui_wasm_components — target-agnostic shared lib. Phase 25 surface: ThemePreference enum + BsTheme mapping helper + 2 unit tests. Joins default-members so its tests run in the kickstart baseline. Future shared widgets (ConnectionStatus, Shell wrapper, base-path-aware RPC client wrapper for Phase 26 island integration) extend this crate without touching either SPA.
  • hero_assistance_admin_ui_wasm — Dioxus 0.7 WASM SPA crate, sibling to _ui_wasm. App + Router + Dashboard skeleton + NotFound. BootstrapHead (Bundled CSS + icons) + ThemeProvider wired. Tab content lands next session.
  • _ui server wiring--admin-dist <path> CLI flag; AppState.admin_dist_dir; admin_index_page handler (serves <admin-dist>/index.html for /admin, /admin/, and /admin/{*path} so admin Dioxus router can dispatch client-side; 404 with helpful message when unset); admin_dist_assets handler (parallel to customer /assets/*, ordered before catch-all); openrpc_proxy byte-passthrough handler.
  • D-22 filed (locked) — documents the renderer-only deviation from canonical Hero Askama+Unpoly admin (visual output identical via Bootstrap 5.3.3 + dioxus-bootstrap-css). Crate topology, B.5 findings, counter-arguments rejected.

B.5 adversarial review caught 2 load-bearing issues (both type-locked from day one)

  1. Open-enum tolerance on x-hero-intent — fields MUST be modelled as Option<String> + #[serde(flatten)] extra: serde_json::Map<String, Value>, NEVER closed Rust enums. D-21 declares schema fields are open (consumers must tolerate unknown values per info.x-hero-intent-schema). Pattern-matching on a closed Rust enum would panic on future router-defined values.
  2. Byte-passthrough /openrpc.json proxy — implemented as a mirror of the existing rpc_proxy (raw HTTP over UDS, slice on \r\n\r\n, return body bytes verbatim). Does NOT parse-and-re-serialise — that would defeat the FNV-1a-64 cache key hero_router computes on the agentic-calling side (D-21 byte-stable invariant).

Test posture

  • 226 native passing (was 225, +1 net from _ui_wasm_components lib's 2 unit tests)
  • 32 _ui_wasm lib unchanged
  • 14 ignored, 1 known transient flake (phase10_multi_project_merged_stream_tags_by_project_id, passes in isolation per s12)
  • 0 net failed; cargo check clean across all 9 workspace crates

What's left for Phase 25 part 2 (next session)

  1. Docs tab first — apply B.5 finding #1 type shape; auto-render 91 methods from /openrpc.json; unit test feeding "side_effect_class": "future-unknown-value" to verify open-enum tolerance.
  2. Stats tab + sidebar widgets — both consume /health + system stats; reactive memo-based, no polling jitter.
  3. Logs tabhero_log integration; SSE live tail.
  4. Admin tab — Shutdown / Stop All / Reset DB / Demo Data via hero_proc RPCs; Modal confirmations.
  5. Domain tabs (Tickets / Users / Projects / Comments) — call existing Phase 15c-validated _server RPCs.
  6. PolishConnectionStatus widget per hero_ui_connection_status; IP whitelist via hero_ui_whitelists + ADMIN_SECRETS; visual baselines (admin-tickets-*.png etc.) replacing the orphaned Phase-9a admin captures.
  7. Regression test_ui_openrpc_proxy_byte_passthrough mirroring phase23_http_openrpc_returns_spec_over_uds_rpc_sock but through _ui to catch any future drift to a parse-based proxy.
  8. Cleanup — delete orphaned templates/index.html + templates/base.html (Phase 9a hero_collab admin chrome with no askama struct referencing them).

Estimated ~1 session for Phase 25 part 2 + polish.

See decisions/D-22-dioxus-admin-dashboard.md for the full deviation rationale and sessions/39.yml for the per-commit manifest.

## Session 39 progress — Phase 25 infrastructure landed (Stages 1-3) Three commits this session: - `a0381fa` — file [#13 Phase 27-prep](https://forge.ourworld.tf/lhumina_code/hero_assistance/issues/13) (orthogonal to Phase 25; release-infra audit found 6 tags / 0 Releases) and integrate into roadmap (order: 25 -> 24 -> 26 -> 27-prep -> 27) - `73d58c4` — **Stage 1**: scaffold `_admin_ui_wasm` + `_ui_wasm_components` crates (additive; clean compile) - `6f7ef00` — **Stages 2 + 3**: clean `/admin` from `_ui_wasm` (-657 LoC; deleted Phase-9a hero_collab `IndexPage` + `Layout` artifacts) + wire `_ui` server with `--admin-dist <path>` flag + admin handlers + byte-passthrough `/openrpc.json` proxy + file [D-22](../decisions/D-22-dioxus-admin-dashboard.md) ### What landed - **`hero_assistance_ui_wasm_components`** — target-agnostic shared lib. Phase 25 surface: `ThemePreference` enum + `BsTheme` mapping helper + 2 unit tests. Joins `default-members` so its tests run in the kickstart baseline. Future shared widgets (`ConnectionStatus`, `Shell` wrapper, base-path-aware RPC client wrapper for Phase 26 island integration) extend this crate without touching either SPA. - **`hero_assistance_admin_ui_wasm`** — Dioxus 0.7 WASM SPA crate, sibling to `_ui_wasm`. App + Router + Dashboard skeleton + NotFound. `BootstrapHead` (Bundled CSS + icons) + `ThemeProvider` wired. Tab content lands next session. - **`_ui` server wiring** — `--admin-dist <path>` CLI flag; `AppState.admin_dist_dir`; `admin_index_page` handler (serves `<admin-dist>/index.html` for `/admin`, `/admin/`, and `/admin/{*path}` so admin Dioxus router can dispatch client-side; 404 with helpful message when unset); `admin_dist_assets` handler (parallel to customer `/assets/*`, ordered before catch-all); `openrpc_proxy` byte-passthrough handler. - **D-22 filed (locked)** — documents the renderer-only deviation from canonical Hero Askama+Unpoly admin (visual output identical via Bootstrap 5.3.3 + dioxus-bootstrap-css). Crate topology, B.5 findings, counter-arguments rejected. ### B.5 adversarial review caught 2 load-bearing issues (both type-locked from day one) 1. **Open-enum tolerance on `x-hero-intent`** — fields MUST be modelled as `Option<String>` + `#[serde(flatten)] extra: serde_json::Map<String, Value>`, NEVER closed Rust enums. D-21 declares schema fields are open (consumers must tolerate unknown values per `info.x-hero-intent-schema`). Pattern-matching on a closed Rust enum would panic on future router-defined values. 2. **Byte-passthrough `/openrpc.json` proxy** — implemented as a mirror of the existing `rpc_proxy` (raw HTTP over UDS, slice on `\r\n\r\n`, return body bytes verbatim). Does NOT parse-and-re-serialise — that would defeat the FNV-1a-64 cache key hero_router computes on the agentic-calling side (D-21 byte-stable invariant). ### Test posture - 226 native passing (was 225, +1 net from `_ui_wasm_components` lib's 2 unit tests) - 32 `_ui_wasm` lib unchanged - 14 ignored, 1 known transient flake (`phase10_multi_project_merged_stream_tags_by_project_id`, passes in isolation per s12) - 0 net failed; cargo check clean across all 9 workspace crates ### What's left for Phase 25 part 2 (next session) 1. **Docs tab first** — apply B.5 finding #1 type shape; auto-render 91 methods from `/openrpc.json`; unit test feeding `"side_effect_class": "future-unknown-value"` to verify open-enum tolerance. 2. **Stats tab + sidebar widgets** — both consume `/health` + system stats; reactive memo-based, no polling jitter. 3. **Logs tab** — `hero_log` integration; SSE live tail. 4. **Admin tab** — Shutdown / Stop All / Reset DB / Demo Data via hero_proc RPCs; Modal confirmations. 5. **Domain tabs** (Tickets / Users / Projects / Comments) — call existing Phase 15c-validated `_server` RPCs. 6. **Polish** — `ConnectionStatus` widget per `hero_ui_connection_status`; IP whitelist via `hero_ui_whitelists` + `ADMIN_SECRETS`; visual baselines (`admin-tickets-*.png` etc.) replacing the orphaned Phase-9a admin captures. 7. **Regression test** — `_ui_openrpc_proxy_byte_passthrough` mirroring `phase23_http_openrpc_returns_spec_over_uds_rpc_sock` but through `_ui` to catch any future drift to a parse-based proxy. 8. **Cleanup** — delete orphaned `templates/index.html` + `templates/base.html` (Phase 9a hero_collab admin chrome with no askama struct referencing them). Estimated ~1 session for Phase 25 part 2 + polish. See `decisions/D-22-dioxus-admin-dashboard.md` for the full deviation rationale and `sessions/39.yml` for the per-commit manifest.
Author
Owner

Phase 25 closed — part 2c landed s42

Part 2c shipped 3 of 5 originally-planned items; B.5 deferred 2.

Landed (s42)

  • Canonical hash deep-link routes per hero_ui_routes skill — Route::DashboardTab { tab: String } matches /admin/#/<tab> for all 8 tabs (logs/stats/admin/docs/tickets/users/projects/comments). Tab::route_segment() / Tab::from_route_segment() round-trip pinned by 4 host-side tests. Signal-based active_tab retired — URL is the single source of truth, use_navigator() push on tab click, browser refresh / deep-link share / back-forward all just work. placeholder.rs deleted.
  • Projects domain tab via workspace.list (D-04 single-project per server). Mirrors the Tickets/Users/Comments shape with full Workspace metadata (id, name, description, avatar_url, created_at, updated_at).
  • Visual-baseline toolingcapture-spa-baselines.sh --surface admin + make admin-dist + make baseline-admin + make visual-diff-admin. Operator-side capture deferred (Phase 18c pattern: script lands separately from PNGs). Stale Phase-9a /admin route removed from capture-baselines.sh + Makefile VISUAL_PAGES; orphaned admin-{1920,768,375}.png deleted.

Deferred (B.5)

  • IP whitelist → Phase 24 (#9). UDS-only ui.sock + hero_ui_whitelists skill's no-fallback principle make any env-loaded form axiom-growth that Phase 24 deletes. The canonical admin_secrets.rs drops in verbatim once hero_proc lifecycle is in place.
  • L-08 step 1 → post-customer. Cross-cutting tracing::* refactor; scope balloon. L-08 already documents the 2-step closure path.

Pending operator-side

  • make admin-dist && make baseline-admin against a live stack captures the 21 admin SPA visual baselines. Mirrors the Phase 18c (s28) pattern. Manual operator-only — visual-diff-admin is not on any CI gate today.

Test posture

  • 248 native passing (unchanged — no _server changes)
  • 16 admin SPA host-side (was 12; +4 phase25c route-segment round-trip / lowercase / case-insensitive / none-for-unknown)
  • 14 ignored / 0 net failed

Acceptance

  • cargo build --release succeeds for the dashboard crate
  • dx build --release produces a working WASM bundle (verified s42)
  • All 8 tabs render (4 domain + 4 utility) — Projects landed s42
  • Sidebar widgets update via signals
  • Docs tab auto-renders all 91 methods from /openrpc.json
  • Admin tab Shutdown / Stop All / Clean / Reset DB / Demo Data — gated server-side by require_admin_role (D-23, s41)
  • Theme toggle works (data-bs-theme dark/light)
  • Connection-status widget (s41)
  • D-22 written and committed (s39)
  • All native tests still pass (225 → 248; +23 net across the part-2 sub-phases)
  • Visual baselines (operator-side, deferred per Phase 18c pattern)
  • IP whitelist (deferred to Phase 24 per s42 B.5)

Closing as engineering-complete with the two B.5-deferred items tracked downstream. Phase 24 (#9) is NEXT — picks up the IP whitelist as a free byproduct.

## Phase 25 closed — part 2c landed s42 Part 2c shipped 3 of 5 originally-planned items; B.5 deferred 2. ### Landed (s42) - **Canonical hash deep-link routes** per `hero_ui_routes` skill — `Route::DashboardTab { tab: String }` matches `/admin/#/<tab>` for all 8 tabs (logs/stats/admin/docs/tickets/users/projects/comments). `Tab::route_segment()` / `Tab::from_route_segment()` round-trip pinned by 4 host-side tests. Signal-based `active_tab` retired — URL is the single source of truth, `use_navigator()` push on tab click, browser refresh / deep-link share / back-forward all just work. `placeholder.rs` deleted. - **Projects domain tab** via `workspace.list` (D-04 single-project per server). Mirrors the Tickets/Users/Comments shape with full Workspace metadata (id, name, description, avatar_url, created_at, updated_at). - **Visual-baseline tooling** — `capture-spa-baselines.sh --surface admin` + `make admin-dist` + `make baseline-admin` + `make visual-diff-admin`. Operator-side capture deferred (Phase 18c pattern: script lands separately from PNGs). Stale Phase-9a `/admin` route removed from `capture-baselines.sh` + `Makefile VISUAL_PAGES`; orphaned `admin-{1920,768,375}.png` deleted. ### Deferred (B.5) - **IP whitelist → Phase 24** ([#9](https://forge.ourworld.tf/lhumina_code/hero_assistance/issues/9)). UDS-only ui.sock + `hero_ui_whitelists` skill's no-fallback principle make any env-loaded form axiom-growth that Phase 24 deletes. The canonical `admin_secrets.rs` drops in verbatim once hero_proc lifecycle is in place. - **L-08 step 1 → post-customer.** Cross-cutting `tracing::*` refactor; scope balloon. L-08 already documents the 2-step closure path. ### Pending operator-side - `make admin-dist && make baseline-admin` against a live stack captures the 21 admin SPA visual baselines. Mirrors the Phase 18c (s28) pattern. Manual operator-only — `visual-diff-admin` is not on any CI gate today. ### Test posture - 248 native passing (unchanged — no `_server` changes) - 16 admin SPA host-side (was 12; +4 phase25c route-segment round-trip / lowercase / case-insensitive / none-for-unknown) - 14 ignored / 0 net failed ### Acceptance - [x] `cargo build --release` succeeds for the dashboard crate - [x] `dx build --release` produces a working WASM bundle (verified s42) - [x] All 8 tabs render (4 domain + 4 utility) — Projects landed s42 - [x] Sidebar widgets update via signals - [x] Docs tab auto-renders all 91 methods from `/openrpc.json` - [x] Admin tab Shutdown / Stop All / Clean / Reset DB / Demo Data — gated server-side by `require_admin_role` (D-23, s41) - [x] Theme toggle works (data-bs-theme dark/light) - [x] Connection-status widget (s41) - [x] D-22 written and committed (s39) - [x] All native tests still pass (225 → 248; +23 net across the part-2 sub-phases) - [ ] Visual baselines (operator-side, deferred per Phase 18c pattern) - [ ] IP whitelist (deferred to Phase 24 per s42 B.5) **Closing as engineering-complete with the two B.5-deferred items tracked downstream.** Phase 24 ([#9](https://forge.ourworld.tf/lhumina_code/hero_assistance/issues/9)) is NEXT — picks up the IP whitelist as a free byproduct.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_assistance#10
No description provided.