wiki-vault/Sources/Dev/dispatch-ui-modernization.md

7.6 KiB

created path project tags type
2026-07-16 Sources/Dev dispatch-ui-modernization
dispatch
python
claude-code
project-plan

Goal

Modernize the petal-dispatch web client and close the session-continuity gaps that force manual refreshes. The current client is a single ~2,881-line static index.html with CDN scripts and no build step; it has outgrown that shape. This plan re-platforms it onto a proper build-step stack and, on that new foundation, delivers reconnect-on-refocus, position and session-state persistence, an installable PWA, conductor-message push notifications, server-synced settings profiles, a refreshed visual design, updated iconography, and android parity where it makes sense.

All work happens on a long-lived branch, validated on the split surface (split.herbylab.dev / LXC ingress) first, and promoted to the fused surface (dispatch.herbylab.dev) only at cutover. The current static page stays the live emergency-hotfix surface until the flip.

Locked Decisions

  • Re-platform, not reskin. The no-build-step constraint that governed prior dispatch plans is lifted for this work. A build step is accepted; the page has grown too long to keep extending inline. Group 3 is a re-platform.
  • Stack spike gates everything. Phase 0 is a short spike to choose the stack, prove it builds, and prove it deploys through the split ingress/executor path. Its output gates all later phases. No feature work starts until the stack is chosen and deploying.
  • Split-first, fused-at-cutover. Every phase builds and validates on the split. The fused surface is untouched until a deliberate cutover, honoring the fused never-restart rule until then.
  • Live stays hotfix-able during the build. While the re-platform lives on the branch, live is still the old static index.html, edited surgically as today. Emergency changes remain available throughout the build.
  • Cutover changes hotfix ergonomics. Once live is the built stack, an emergency change becomes edit-source then rebuild then deploy. The old static page is kept parked as an instant-rollback target for a period after cutover to de-risk this.
  • Settings are server-side and synced. Profiles live server-side, keyed to the authenticated identity from the edge (Authentik on fused, CF Access on split). Because there is effectively one user, definitions sync across devices by default. Named, saveable, switchable profiles are the requirement.
  • Push is conductor-messages only. Web push wakes the user on Lovebug/conductor replies. Worker events and asks are out of push scope for this plan.
  • PWA is foundational. The web manifest and service worker underpin the homescreen app icon and push, and aid reconnect resilience. It lands early so icon and push can hang off it.
  • Android mirrors information, not implementation. Android is native Kotlin/Compose. It consumes the same settings backend, does native FCM push, and matches icon and theme. It does not port the web UI. Android mockups are produced alongside web mockups.

Open Items

  • Active-profile pointer scope. Profile definitions always sync. Undecided: whether switching the active profile on one device also flips it on other devices, or stays local per-device. Decide at build time.
  • Stack choice. Output of Phase 0. Bounded by: must produce assets deployable through the split ingress path, must keep SSE streaming chat working, and must stay light at runtime.
  • Settings bucket contents. Confirmed seeds beyond color and font size: message density and spacing, code-block theme, timestamps toggle, thinking-animation toggle, notification sound. Finalize the list when the settings phase is built.
  • Visual direction. No design references queued. Start from a plain "modern" direction, produce a small set of mockups for web and android, and iterate from reaction. Icon examples will be supplied by Herby at execution.
  • Settings persistence store. Which backend store holds the profiles. Likely the existing Postgres. Confirm during the settings phase.
  • Mobile long-message handling. How to present very long conductor messages on a phone. Candidate treatments: collapse and expand, capped height with internal scroll, a show-more affordance, jump-to-latest. Resolve during the modernization and mobile phase.

Build Phases

Phase 0 — Stack spike (gate)

Choose the re-platform stack, stand up the build, and prove it deploys through the split ingress/executor path serving live SSE chat. Deliverable is a deploying skeleton of the chat surface on the branch, plus the chosen stack documented. Gates all later phases.

Phase 1 — Continuity and persistence

Reconnect and re-snapshot the stream on refocus so the manual refresh is no longer needed. Persist and restore scroll position. Persist the session-info pills across refresh, namely the five-hour rate status and the context-window value. Persist the composer draft across refresh and device switch. The one carve-out: the reconnect fix may be peeled out as a small standalone patch against the current static page if the day-to-day pain justifies it before the re-platform lands.

Phase 2 — PWA foundation

Add the web manifest and service worker. Make the client installable to the homescreen. Establish the base that push and reconnect resilience build on.

Phase 3 — Settings profiles

Server-side profile store keyed to the authenticated identity, with endpoints to list, save, and activate. Named, switchable profiles covering color and theme, font size, and the confirmed settings bucket. Synced across devices by default.

Phase 4 — Visual modernization

Mock-driven redesign from a "modern" starting direction. Produce web and android mockups, get reaction, commit a direction, then implement on the new stack. Absorbs the theming tokens that feed settings. Includes mobile long-message handling.

Phase 5 — Iconography and branding

Evolve the thinking visuals and chat bubbles from the current 53-badge and Herbie-car baseline. Add a real app icon through the PWA manifest and apple-touch surfaces, distinct from the existing favicon. Fold in Herby's queued icon examples.

Phase 6 — Push notifications

Web push for conductor-message replies. Standing infra: VAPID keys, a push-subscription store, and a backend sender. Depends on the PWA foundation.

Phase 7 — Android parity

Mirror where it makes sense. Android consumes the same settings API, does native FCM push, and matches icon and theme. Same information, native presentation. Produced as child threads under the android node.

Notes

  • Phase order is spike-first by decision; within the feature phases, PWA precedes push because push depends on it, and settings precede or parallel the visual work because the visual work produces the theming tokens settings expose.
  • Deploy discipline: build and validate on split, promote to fused at cutover, keep the old static page parked as rollback.
  • Backend changes for settings and push route through the ingress and executor split, not just the fused path. The fused settings and push activation will need a chosen restart window, consistent with the fused never-restart posture.
  • Baseline the redesign inherits: the render upgrade already shipped markdown-it, highlight.js, json and mermaid fence widgets, per-block and per-message copy, and a theme accent system. Attachments Phase 1 shipped clipboard image paste to the conductor turn. This plan builds on that surface, it does not redo it.
  • Execution routes to workers against an isolated worktree on the branch so the live-served checkout is not disturbed mid-build.
  • Android surface is native Kotlin/Compose; the PWA and service-worker items do not apply there and are web-only.