Frontend & UI Review + Improvement Plan
Document: FRONTEND_UI_IMPROVEMENT_PLAN.md
Scope: miz-oki-command-center-ui/ (Command Center UI — the primary operator frontend), with reference notes on apps/web/ and the # MIZ OKI 3.5/ marketing site
Date: August 5, 2026
Status: Review complete — plan proposed, not yet executed
Claim label: All figures below are measured results from the repository at the time of review unless labeled otherwise.
Table of Contents
- Executive Summary
- What Was Reviewed
- Current-State Architecture
- Backend Wiring Assessment
- Best-Practices Conformance Scorecard
- Key Findings (Ranked by Severity)
- Target Architecture
- Improvement Plan — Phases 0–5
- UX / Ease-of-Use Redesign
- Expansion Opportunities
- Risk Register & Rollout Strategy
- Success Metrics
- Appendix A — Measured Inventory
1. Executive Summary
The Command Center UI is a very large, feature-rich Next.js application (155 pages, 210 API routes, 243 components, 65 hooks, 135 lib modules) that is genuinely well-wired into the backend fleet: it has a real BFF (backend-for-frontend) layer of Next.js API routes that proxy to Cloud Run services with OIDC authentication, SSE streaming, Zustand global state, React Query, and OpenTelemetry instrumentation. This is far beyond a typical dashboard scaffold.
However, the app has accumulated significant structural and quality debt that undermines its strengths:
| Dimension | Grade | One-line verdict |
|---|---|---|
| Backend wiring | B+ | Real BFF + OIDC proxying + SSE, but 391 hardcoded run.app URLs bypass the config layer |
| Architecture | C+ | Modular but bloated: 16 app/boss* route directories (7 archived variants shipped in the bundle), duplicate providers |
| Type safety | D | strict: false, ignoreBuildErrors: true — the compiler is present but disarmed (baseline ~556 known errors per repo records) |
| Linting | D | Good custom rules (navigation safety) but ignoreDuringBuilds: true neutralizes them in CI |
| Testing | F | Zero test files in the UI package; Jest is installed but unconfigured and unused |
| Rendering strategy | C | dynamic = 'force-dynamic' globally + 311 client components — almost no server-rendering benefit is realized |
| UX / navigation | C+ | Powerful but overwhelming: ~87 top-level route groups with no progressive disclosure, no global command palette on all pages, inconsistent loading/empty/error states |
| Dependencies | C | Modern core (Next 15.5.21, React 19), but heavy/duplicated graph libs and AI SDKs shipped to the client |
Bottom line: the plumbing is real and mostly good; the airframe needs consolidation. The plan below is sequenced so that the safety net comes first (types, lint, tests, CI gates), consolidation second (dead route removal, single API client, config-driven URLs), and UX/expansion third — because refactoring 155 pages without tests or type checking is how regressions ship silently. This ordering matters more than any individual item.
2. What Was Reviewed
2.1 Frontend surfaces in the monorepo
| Surface | Path | Stack | Role |
|---|---|---|---|
| Command Center UI (primary) | miz-oki-command-center-ui/ |
Next.js 15.5.21, React 19 (locked 19.2.7), TypeScript 5, Tailwind, Zustand, React Query, Radix UI | Operator console for the entire cell fleet, Boss Agent, KG, campaigns |
| Secondary web app | apps/web/ |
Next.js 16.2.11, React 19.2.3 | Smaller app; frontend-guard.yml CI currently targets it (repo docs flag retiring it) |
| Marketing site | # MIZ OKI 3.5/ |
Flask + static HTML/CSS/JS | Public site — canon-locked, human-approval deploys only; explicitly out of scope for changes |
| Chrome extension | chrome-boss-agent-extension/ |
Manifest V3, vanilla JS | Boss Agent browser access — out of scope |
| VS Code extension | vscode-boss-agent-extension/ |
TypeScript | Boss Agent IDE access — out of scope |
This plan targets the Command Center UI. The marketing site is governed by the design-canon lock and must not be touched by this effort.
2.2 Measured inventory (Command Center UI)
| Metric | Count | Notes |
|---|---|---|
Pages (page.tsx) |
155 | Across ~87 top-level app/ route groups |
API routes (route.ts) |
210 | The BFF layer |
| Components | 243 | components/ |
| Hooks | 65 | hooks/ |
| Lib modules | 135 | lib/ — API clients, auth, telemetry, utils |
| Store files | 10 | Zustand slices + provider |
Client components ('use client') |
311 | The overwhelming majority of the UI |
Hardcoded run.app URL references |
391 | Scattered across pages, components, hooks, lib |
app/boss* route directories |
16 | Of which 7 are archived variants still shipped |
| Test files | 0 | Jest deps installed, no config, no tests |
| Known TypeScript errors (repo baseline) | ~556 | Per CLAUDE.md delta-tsc records; builds pass because errors are ignored |
3. Current-State Architecture
3.1 System context
flowchart LR
subgraph Browser
UI[Command Center UI<br/>Next.js 15 / React 19<br/>311 client components]
end
subgraph "Next.js server (Cloud Run: miz-oki-command-center-ui)"
BFF[210 API routes<br/>BFF / OIDC proxy layer]
MW[middleware.ts<br/>Supabase session refresh]
OTEL[instrumentation.ts<br/>OpenTelemetry]
end
subgraph "Cloud Run backend fleet (us-central1)"
BOSS[boss-agent-adk<br/>1,137+ MCP tools]
MOA[miz-oki-moa-controller]
MOE[miz-oki-moe-router]
CELLS[36 cells<br/>cell01..cell32 + ORACLE 33-36]
GOV[10 service-* governance services]
end
subgraph "Data plane"
FS[(Firestore<br/>28+ collections)]
BQ[(BigQuery)]
NEO[(Neo4j KG)]
SB[(Supabase Auth)]
FB[(Firebase)]
end
UI -->|fetch /api/*| BFF
UI -.->|"391 hardcoded run.app URLs (bypass ⚠️)"| CELLS
UI <-->|SSE / Socket.io| BFF
BFF -->|OIDC identity tokens| BOSS
BFF -->|OIDC| MOA & MOE
BFF -->|"same-origin /api/orchestration proxy"| CELLS
BOSS --> FS & BQ & NEO
MW --> SB
BFF --> FB
The critical wiring flaw is the dotted line: since the Phase-8 IAM lockdown (see CLAUDE.md MIZ-FIN-2026-005), browser code cannot mint Cloud Run OIDC tokens, so every one of the 391 direct *.run.app references in client code is either (a) hitting one of the shrinking set of intended-public services, (b) silently failing with 403, or (c) working only until that service gets IAM-locked. The repo's own records confirm this failure class ("Browser callers cannot mint Cloud Run OIDC — health/widgets against IAM-locked services need a same-origin nodejs proxy"). The BFF pattern already exists (app/api/orchestration/[svc]/[...path]) — it just isn't used consistently.
3.2 Frontend internal architecture (as-is)
flowchart TD
subgraph "app/ — 87 top-level route groups, 155 pages"
LAYOUT["layout.tsx<br/>force-dynamic ⚠️<br/>headers()-based auth-route check"]
PAGES[Feature pages<br/>dashboard, boss, agents, kg,<br/>campaigns, cells, channels ...]
DEAD["16 app/boss* dirs<br/>7 archived variants still shipped ⚠️"]
API[210 API routes]
end
subgraph "State & data"
STORE[Zustand store<br/>10 files: slices for agents,<br/>kernels, realtime, ui, workflows]
RQ[React Query<br/>QueryClientProvider]
SSE[useSSE / useMultiSSE<br/>global stream in providers.tsx]
POLL["setInterval polling in providers.tsx<br/>1m / 2m / 5m ⚠️ redundant with SSE"]
end
subgraph "lib/ — 135 modules"
CLIENTS["Multiple overlapping API clients ⚠️<br/>api-service.ts, cloud-run-client.ts,<br/>a2a-client.ts, boss-*-client(s), ..."]
AUTHZ[supabase/server.ts + client.ts<br/>firebase-client.ts, jwt.ts]
TEL[telemetry.ts withToolSpan]
SAFE[safe-navigation.ts toSafeUrl]
end
LAYOUT --> PAGES
PAGES --> STORE & RQ
PAGES -->|"direct fetch/axios in components ⚠️"| API
STORE --> SSE
STORE --> POLL
PAGES --> CLIENTS
CLIENTS --> API
Notable as-is properties:
- Two provider files exist (
app/providers.tsxandcomponents/providers.tsxreferenced fromapp/layout.tsx) — a duplication that makes it unclear which provider tree is authoritative. providers.tsxruns threesetIntervalpolls (kernels 1m, workflows 2m, agents 5m) and opens a global SSE stream — double-fetching the same classes of data.export const dynamic = 'force-dynamic'in the root layout disables static optimization for the entire app, because the layout callsheaders()for auth-route detection — a check that belongs inmiddleware.ts(which already exists).- State is split three ways (Zustand, React Query, ad-hoc
useState+fetchin components) with no documented rule for which owns what.
4. Backend Wiring Assessment
4.1 What is genuinely good
| Strength | Evidence |
|---|---|
| Real BFF layer | 210 API routes proxy browser calls server-side; app/api/orchestration/[svc]/[...path] provides a generic OIDC proxy for locked services |
| OIDC-aware server fetches | lib/service-auth.ts / authedFetch pattern (added during the Phase-8 IAM waves) mints identity tokens server-side |
| Streaming support | SSE routes (app/api/stream, app/api/streaming), useSSE/useMultiSSE hooks, Socket.io client — real-time is a first-class citizen |
| Observability | instrumentation.ts boots OpenTelemetry; withToolSpan/withCellSpan wrap operations; OTel collector sidecar deploy config exists |
| Auth done twice, both correctly | Supabase SSR (@supabase/ssr, cookie sessions, middleware refresh, /auth/callback) plus Firebase for Firestore-backed features |
| Navigation safety | toSafeUrl() + custom ESLint no-restricted-syntax rules to prevent [object Object] URL bugs |
| Config centralization exists | lib/cloud-run-client.ts exposes CLOUD_RUN_CONFIG — the right idea, inconsistently adopted |
4.2 Where the wiring is broken or fragile
| # | Issue | Measured evidence | Consequence |
|---|---|---|---|
| W1 | 391 hardcoded *.run.app URLs in UI source |
grep across app/, components/, hooks/, lib/ |
Client-side calls to IAM-locked services fail with 403/CORS; URL changes require mass edits; no env separation |
| W2 | In-memory state in API routes | app/api/boss/chat/route.ts keeps conversationMemory in a module-level Map |
Cloud Run scales to N instances / scales to zero → conversations silently lost or split between instances |
| W3 | Direct fetch/axios inside components |
Widespread pattern alongside React Query | No caching, no dedup, no retry policy, inconsistent error handling |
| W4 | Polling + SSE duplication | providers.tsx intervals vs global SSE stream |
Wasted backend load; two sources of truth for the same entities |
| W5 | Known-broken route fixed only recently | Repo records: /api/boss/srdal/trace was "a pre-existing broken fetch (served by neither name)"; SSE endpoint 404 until dfab1d8b |
Symptom of no integration tests — broken wiring ships and lingers |
| W6 | Stale service registries in UI code | Cell registry naming issues (cell16/cell18 class) documented in repo records | Health widgets can show false outages |
4.3 Verdict
Wiring quality is bimodal: the server-side BFF/OIDC/streaming layer is production-grade; the client-side consumption of it is undisciplined. The fix is not new infrastructure — it is funneling all data access through one typed client that only talks to the BFF, and deleting the 391 bypasses.
5. Best-Practices Conformance Scorecard
Assessed against current Next.js 15 / React 19 guidance (App Router, Server Components, streaming, typed APIs) and general frontend engineering practice.
| Practice | State in repo | Conforms? |
|---|---|---|
| App Router structure | Yes — full app/ directory |
✅ |
| React Server Components used meaningfully | No — 311/~340 components are client; root layout forces dynamic | ❌ |
loading.tsx / not-found.tsx / global-error.tsx conventions |
Only app/error.tsx exists; the other three are missing at root |
❌ |
Route groups (group) for organization |
Not used — 87 flat top-level dirs | ❌ |
TypeScript strict |
strict: false, target: es2015 |
❌ |
| Type-checked builds | typescript.ignoreBuildErrors: true |
❌ |
| Lint-gated builds | eslint.ignoreDuringBuilds: true |
❌ |
| Automated tests (unit/integration/E2E) | None (0 files) | ❌ |
| CI quality gate for the UI | frontend-guard.yml targets apps/web, not this app; next build is the only gate and it ignores errors |
❌ |
| Data fetching via a caching layer | React Query installed; usage inconsistent (W3) | ⚠️ |
| Centralized, env-driven service config | Exists (CLOUD_RUN_CONFIG) but bypassed 391 times |
⚠️ |
| Accessibility (a11y) discipline | Radix primitives help; no eslint-plugin-jsx-a11y config, no audits | ⚠️ |
| Bundle hygiene | Heavy libs (4 graph libs: cytoscape, d3, react-force-graph, reactflow; AI SDKs; langchain) in client deps; no bundle analysis in CI | ❌ |
| Error/telemetry reporting | OTel server-side ✅; no client error boundary reporting (e.g., no Sentry-class capture) | ⚠️ |
| Design system / tokens | Tailwind + Radix + class-variance-authority — foundation exists, no documented token system or Storybook |
⚠️ |
| Dead code hygiene | 7 archived boss variants shipped in the production bundle |
❌ |
Score: 2 ✅ / 6 ⚠️ / 9 ❌. The app is modern in framework version but not in framework usage.
6. Key Findings (Ranked by Severity)
🔴 Critical
F1 — The safety net is disarmed.
strict: false + ignoreBuildErrors + ignoreDuringBuilds + zero tests means the only thing standing between a bad change and production is a successful next build. The repo's own history proves the cost: the UI carried a ~556-error TypeScript baseline, a broken SSE endpoint, and a fetch served by no route — all shipped under green CI. Every other improvement in this plan is unsafe to execute until this is fixed.
F2 — 391 hardcoded backend URLs in a fleet that is being IAM-locked.
The platform is actively removing public access from services (Phase-8 waves, 47 services flipped to ingress=all + IAM). Browser code cannot mint OIDC tokens. Every hardcoded client-side run.app call is a latent 403.
F3 — Stateful API routes on stateless infrastructure.
The in-memory conversationMemory Map in app/api/boss/chat/route.ts (and any similar module-level state) loses data on scale-down and splits sessions across instances. The file's own comment says "replace with Redis/DB in production" — it is in production.
🟠 High
F4 — Dead weight shipped to users. 7 archived app/boss-* variants, duplicated provider trees, and 4 overlapping graph-visualization libraries inflate build time, bundle size, and cognitive load. 155 pages is likely 2–3× the number of pages operators actually use.
F5 — Server-rendering benefits thrown away. force-dynamic on the root layout + near-universal 'use client' means Next.js is being used as an SPA host with extra steps. The auth-route check that forces this belongs in middleware.
F6 — No state-ownership rules. Zustand slices, React Query, SSE stream, polling intervals, and component-local fetches all manage overlapping data. This produces stale-data bugs and makes every new feature a judgment call.
🟡 Medium
F7 — Missing UX conventions. No root loading.tsx/not-found.tsx/global-error.tsx; loading/empty/error states are hand-rolled per page and inconsistent; no skeleton system.
F8 — Navigation overload. ~87 top-level route groups surface in an app with a sidebar that must enumerate them. There is no progressive disclosure, no per-role landing experience, and command-palette (cmdk is installed!) is not wired as the universal navigator.
F9 — Dependency risk. pydantic (a Python package) is listed in package.json dependencies; react-json-view is React-18-era; AI SDKs (openai, @anthropic-ai/sdk, langchain) in the client dependency graph invite accidental client-side key usage.
7. Target Architecture
7.1 Data-flow after the plan
flowchart LR
subgraph Browser
RSC[Server Components<br/>initial data, static shells]
CC[Client components<br/>interactivity only]
HOOKS[Typed hooks<br/>useQuery / useMutation]
end
subgraph "Next.js server"
GW["lib/api/gateway.ts<br/>ONE typed client<br/>(zod-validated, env-driven)"]
BFFX[Consolidated BFF routes<br/>~120 after dedup]
KV[(Redis / Firestore<br/>session + conversation state)]
end
subgraph Backend
FLEET[Cloud Run fleet<br/>OIDC-locked]
end
RSC --> GW
CC --> HOOKS --> BFFX
BFFX --> GW
GW -->|OIDC, retries, tracing| FLEET
BFFX --> KV
style GW fill:#0a5,stroke:#333,color:#fff
Rules encoded by this architecture (enforced by ESLint, not convention):
- Zero
run.appstrings outsidelib/config/services.ts. One env-driven registry; a lint rule bans the literal elsewhere. - Browser code talks only to same-origin
/api/*. The BFF is the only path to the fleet. - Server state lives in React Query; UI state lives in Zustand; nothing lives in module scope.
- SSE invalidates React Query caches instead of polling — one source of truth, real-time by default.
7.2 Route information architecture (target)
flowchart TD
ROOT["/ — Role-aware home"]
ROOT --> OPS["(operations)/<br/>dashboard, cells, health, deployments"]
ROOT --> AGENTS["(agents)/<br/>boss, agent-ide, moa-moe, launcher"]
ROOT --> INTEL["(intelligence)/<br/>kg, causal, oracle-intent, analytics"]
ROOT --> MKTG["(marketing)/<br/>campaigns, channels, creatives, attribution"]
ROOT --> ADMIN["(admin)/<br/>settings, auth, api-keys, audit"]
ROOT --> CMDK[["⌘K command palette<br/>universal navigation + actions"]]
style CMDK fill:#7c3aed,color:#fff
87 flat directories become 5 route groups + a command palette. Archived variants are deleted (they remain in git history). Every page inside a group inherits the group's layout, breadcrumbs, and loading/error conventions.
8. Improvement Plan — Phases 0–5
Sequenced by dependency: each phase makes the next one safe. No calendar estimates; effort is characterized by invasiveness.
Phase 0 — Safety net (low-invasiveness, highest leverage)
| # | Action | Detail |
|---|---|---|
| 0.1 | Type-check gate with a ratchet | Keep ignoreBuildErrors for now, but add a CI job running tsc --noEmit against a checked-in baseline (the delta-tsc pattern already used in this repo for the SRDAL migration). Any new error fails CI. Baseline shrinks over time. |
| 0.2 | Lint gate with a ratchet | Same pattern for ESLint; add eslint-plugin-jsx-a11y and a no-restricted-syntax rule banning run.app literals outside the config module. |
| 0.3 | Test harness | Configure Vitest + React Testing Library (fast, ESM-native — supersede the unused Jest deps) and Playwright for E2E. Seed with: (a) smoke tests for the 10 most-used pages, (b) contract tests for the 20 most-critical BFF routes, (c) one E2E: login → dashboard → boss chat round-trip. |
| 0.4 | CI wiring | Point frontend-guard.yml (or a new workflow) at miz-oki-command-center-ui with: typecheck-ratchet, lint-ratchet, unit tests, build. |
| 0.5 | Root convention files | Add app/loading.tsx, app/not-found.tsx, app/global-error.tsx (with client error reporting in the global boundary). |
Exit gate: CI red on any new type/lint error; ≥30 tests passing; conventions present.
Phase 1 — Wiring correctness (medium invasiveness)
| # | Action | Detail |
|---|---|---|
| 1.1 | Service registry module | lib/config/services.ts: every backend URL from env vars with typed accessors; dev/staging/prod parity. |
| 1.2 | Eliminate the 391 hardcoded URLs | Mechanical migration in slices of ~40, each slice verified by the Phase-0 smoke tests. Client-side call sites route through the BFF (/api/orchestration/[svc]/... where a dedicated route doesn't exist). |
| 1.3 | Externalize API-route state | Move conversationMemory (and any module-level Maps found by an audit for new Map( at module scope in app/api/) to Firestore (already a platform dependency) or Memorystore. |
| 1.4 | One gateway client | lib/api/gateway.ts wrapping authedFetch with zod response validation, retry/backoff, and withToolSpan tracing. Deprecate api-service.ts / cloud-run-client.ts / per-feature clients by re-exporting through the gateway, then delete. |
| 1.5 | SSE→Query invalidation | Replace providers.tsx polling intervals with SSE-event-driven queryClient.invalidateQueries calls. |
Exit gate: grep -r "run.app" app/ components/ hooks/ lib/ --include='*.ts*' returns only lib/config/services.ts; chat memory survives instance restarts (verified by test).
Phase 2 — Consolidation & dead-code removal (medium-high invasiveness)
| # | Action | Detail |
|---|---|---|
| 2.1 | Delete archived routes | Remove the 7 app/boss-*archived* variants + boss-versions-archived-react (git history preserves them). Add 307 redirect shims only for any route with measured traffic. |
| 2.2 | Merge boss surfaces | Consolidate remaining boss* directories into one (agents)/boss area with tabs — repo history shows this consolidation pattern already worked for /boss-srdal → /boss-srpvdal. |
| 2.3 | Single provider tree | Merge app/providers.tsx and components/providers.tsx; document the provider order. |
| 2.4 | Route groups | Reorganize app/ into the 5 groups from §7.2. Next.js route groups don't change URLs, so this is a file-move refactor guarded by the smoke tests + a redirect map for any URL that does change. |
| 2.5 | Dependency prune | Remove pydantic (Python package in npm deps), react-json-view (replace with a maintained JSON viewer), pick one graph library per use case (recommend keeping reactflow for DAG editing + cytoscape for large KG rendering; drop react-force-graph, jsplumb), move AI SDKs out of client-reachable code paths, dedupe @types/react 18 vs React 19. |
| 2.6 | BFF route dedup | Audit the 210 API routes for orphans (no caller in app//components//hooks/) — the same 0-importer methodology used in the repo's SRDAL cleanup — and delete or consolidate. Target ~120. |
Exit gate: page count reduced ≥25%; bundle size reduced (measured via @next/bundle-analyzer added in this phase); no route 404s in the E2E crawl.
Phase 3 — Rendering & performance (high invasiveness, incremental)
| # | Action | Detail |
|---|---|---|
| 3.1 | Move auth-route detection to middleware | Delete the headers() call from app/layout.tsx; drop the global force-dynamic. |
| 3.2 | Server-first pages | Convert page shells to Server Components with Suspense streaming; keep interactivity in leaf client components. Start with the top-10 pages by traffic. |
| 3.3 | loading.tsx per group + skeleton system |
One skeleton component library; every route group gets streaming loading states. |
| 3.4 | Code-split heavy visualizations | next/dynamic for cytoscape/reactflow/chart-heavy panels with skeleton fallbacks. |
| 3.5 | TypeScript strictening | Flip strict: true with the ratchet baseline absorbing existing errors; raise target to es2022; burn down the ~556 baseline opportunistically per touched file. |
Exit gate: Lighthouse performance ≥85 on dashboard and boss chat (from a measured pre-phase baseline); TS baseline reduced ≥50%.
Phase 4 — UX overhaul (see §9)
Phase 5 — Expansion (see §10)
9. UX / Ease-of-Use Redesign
9.1 Problems observed
- No progressive disclosure — a new operator faces ~87 nav destinations with equal visual weight.
- No universal search/actions —
cmdkis installed but not surfaced as a global ⌘K palette across pages. - Inconsistent feedback — loading, empty, and error states differ per page; some pages render blank while fetching.
- No role-aware entry — an analyst, a media buyer, and a platform operator all land on the same home.
- Real-time is invisible — SSE data updates silently; there's no connection-status affordance or "live" indicators.
9.2 Redesign pillars
flowchart LR
P1["1. Command Palette<br/>⌘K everywhere:<br/>navigate, run MCP tools,<br/>ask Boss"] --> UX((Operator<br/>Experience))
P2["2. Role-aware Home<br/>3 presets: Operator,<br/>Analyst, Media Buyer"] --> UX
P3["3. Unified feedback<br/>skeletons, empty states,<br/>error boundaries, toasts —<br/>one component kit"] --> UX
P4["4. Live-status system<br/>SSE connection badge,<br/>freshness timestamps,<br/>optimistic mutations"] --> UX
P5["5. Design tokens +<br/>component docs<br/>(Storybook or Ladle)"] --> UX
Concrete deliverables:
| Deliverable | Description |
|---|---|
| Global ⌘K palette | Fuzzy navigation over all routes + "Ask Boss" free-text handoff + recent items. Single highest-leverage ease-of-use win; cmdk already in deps. |
| Home dashboard presets | Three saved layouts (Operator / Analyst / Media Buyer) selectable at first login, persisted in Zustand + Supabase profile. |
| Feedback kit | <PageSkeleton/>, <EmptyState/>, <ErrorState retry/>, <LiveBadge/> used by every page — enforced by review checklist. |
| Navigation shell v2 | Sidebar shows the 5 groups (collapsed by default) + pinned favorites; breadcrumbs from route groups; mobile sheet retained. |
| Boss chat as a persistent dock | The Boss Agent (the platform's superpower) becomes a slide-over available on every page, not a destination — with page-context automatically attached to prompts. |
| A11y pass | jsx-a11y lint + keyboard traversal audit of the top-20 pages + focus management in dialogs (Radix gives most of this free). |
10. Expansion Opportunities
Ordered by value-to-effort once the foundation phases are done:
| # | Expansion | Why |
|---|---|---|
| E1 | ORACLE/Intent surfaces | Cells 33–36 are live with 8 intent_* tools and hourly scoring; the UI has no first-class pages for intent cohorts, transitions, consent stats, or incrementality reports. This is shipped backend capability with no operator window. |
| E2 | Governance console | The 10 service-* governance services (passports, DEL scores, approvals, authorizations, audit replay) currently have no unified UI. A "Decision Inbox" (pending approvals with one-click approve/reject + full DecisionProof rendering) directly serves the platform's two-key autonomy model. |
| E3 | Fleet health board | Replace scattered health widgets with one board driven by the control-plane truth (Ready + latestReady==latestCreated), encoding the repo's hard-won failure-class rules (403=locked-healthy, 404=no-route, 503=real, timeout=cold-start). |
| E4 | Notification center | SSE-driven inbox for guardrail breaches, drift alerts, deploy events — currently these land only in logs. |
| E5 | Saved views & shareable state | URL-serialized filters for analytics pages so operators can share exact views. |
| E6 | Mobile/tablet operator mode | The nav shell is responsive but data-dense pages are not; a read-only mobile mode for health + approvals covers the on-call use case. |
11. Risk Register & Rollout Strategy
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Refactor regressions on untested pages | High (pre-Phase-0) | High | Phase ordering — no consolidation before the test harness exists; smoke tests per migration slice |
| URL/route changes breaking bookmarks & external links | Medium | Medium | Redirect shims (the repo's proven 307 dual-accept pattern); crawl-based 404 check in CI |
| Hardcoded-URL migration breaking a niche page | Medium | Low-Med | Migrate in ~40-URL slices; each slice behind a PR with its own smoke run |
| Strict-mode flip flooding CI with failures | Certain (if unratcheted) | Medium | Baseline ratchet: existing errors grandfathered, new errors blocked |
| Bundle/regression from dependency swaps | Low | Medium | @next/bundle-analyzer in CI from Phase 2; size budget check |
| Team velocity dip during consolidation | Medium | Medium | Phases 1–3 are incremental and per-slice mergeable; no long-lived branch |
Rollout: every phase lands as a series of small PRs on main behind the CI gates from Phase 0. No big-bang branch. The dashboard and boss-chat pages get canary attention (manual verification) on every consolidation PR since they are the highest-traffic surfaces.
12. Success Metrics
| Metric | Baseline (measured) | Target |
|---|---|---|
Hardcoded run.app refs in UI source |
391 | 0 (outside config module) |
| Test files | 0 | ≥150 unit/contract + ≥10 E2E flows |
| TypeScript errors (baseline) | ~556 | ≤250 after Phase 3; trending to 0 |
| CI quality gates on this app | build only (errors ignored) | typecheck + lint + tests + bundle budget |
Top-level app/ route dirs |
~87 | ≤40 within 5 route groups |
app/boss* directories |
16 | ≤3 |
| Pages shipped | 155 | ≤115 |
| Client components share | 311 (~92%) | ≤60% of components |
| Root convention files | 1 of 4 | 4 of 4 |
| Lighthouse perf (dashboard) | unmeasured — capture in Phase 0 | ≥85 |
| Time-to-first-meaningful-action for a new operator | unmeasured | ≤2 clicks or 1 ⌘K query to any core surface |
Appendix A — Measured Inventory
All values measured directly from the working tree on the review date.
miz-oki-command-center-ui/
├── app/ 155 page.tsx · 210 route.ts · ~87 top-level dirs
│ ├── boss* 16 directories (7 archived variants)
│ ├── error.tsx ✅ present
│ ├── loading.tsx ❌ missing not-found.tsx ❌ missing global-error.tsx ❌ missing
├── components/ 243 files (incl. duplicate providers.tsx vs app/providers.tsx)
├── hooks/ 65 files (useSSE, useMultiSSE, useBossAgentChat, useCellStatus, ...)
├── lib/ 135 files (api-service, cloud-run-client, a2a-client, supabase/,
│ firebase-client, telemetry, safe-navigation, edge-inference/, ...)
├── store/ 10 files (Zustand slices: agents, kernels, realtime, ui, workflows)
├── middleware.ts ✅ Supabase session refresh
├── instrumentation.ts ✅ OpenTelemetry boot
├── next.config.mjs ⚠️ eslint.ignoreDuringBuilds + typescript.ignoreBuildErrors
├── tsconfig.json ⚠️ strict:false · target:es2015 · skipLibCheck:true
├── .eslintrc.json ✅ navigation-safety rules (neutralized in builds)
└── tests ❌ none (jest deps installed, unconfigured)
Key versions (package-lock.json):
next 15.5.21 · react 19.2.7 · typescript 5.x · node engine unpinned (env: v22.14.0)
Cross-cutting measurements:
'use client' occurrences ........ 311
hardcoded *.run.app references ... 391
known TS error baseline .......... ~556 (per repo delta-tsc records)
Related repo documents
docs/reports/FRONTEND_UI_GAP_ANALYSIS_2026-07-23.md— earlier gap analysis (superseded by this plan's inventory)docs/reports/FRONTEND_INTEGRATION_GUIDE.md— BFF/integration referencedocs/reports/FRONTEND_MOCK_FIXES.md— prior mock-data cleanup recordCLAUDE.md— platform source of truth (IAM lockdown waves, SRDAL→SRPVDAL route migrations, delta-tsc baseline practice, design-canon lock on the marketing site)
End of plan. This document proposes changes only; no application code was modified as part of this review.