Files
stack/docs/webui/PHASE-P-STRUCTURE.md
T
shaggy (mosaic-dev box)andClaude Opus 4.8 a45f53071a
ci/woodpecker/pr/ci Pipeline failed
docs(webui): add Phase P structure & migration map
First-pass structural reference for the Vite SPA migration (apps/web): dual-app
tree during migration, shared lib/ networking layer, origin-relative/same-origin
serving model, build scripts, the P1-P6 increment map, and the #1145 P5 blocker.
Living doc — details to be fleshed out by follow-up.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ESFAnh2t9HmLwng8oW95St
2026-08-10 14:34:57 -05:00

6.8 KiB
Raw Blame History

WebUI Phase P — File / Folder Structure & Migration Map

Status: living document — first pass. Structure and increment status are verified against next as of merge 8c27024d. Details (per-surface component inventories, exact route tables, test matrices) are still being fleshed out; extend the stub sections below rather than rewriting the verified structure.

1. What Phase P is

Phase P migrates the Mosaic web UI (apps/web) from the legacy Next.js App Router app to a Vite + React Router single-page app (SPA) that the Gateway serves same-origin on :14242. The RFC splits the work into six increments (P1P6); the P1 PR title records this as "increment 1/6".

The migration is deliberately incremental and non-destructive: the new SPA is built up beside the existing Next app, sharing one apps/web/src/lib networking/auth layer, until the final cutover (P5) removes the Next tree. At every point in between, both app trees exist in the same package — this is intentional, not drift.

2. Current tree on next (dual-app, transitional)

apps/web/
├── next.config.ts                 # legacy Next.js config          (removed at P5)
├── vite.config.ts                 # SPA build + DEV proxy config    (canonical from P5)
├── package.json                   # dev/build default to NEXT today; :vite variants opt in
└── src/
    ├── main.tsx                   # ── SPA entry (Vite)
    ├── routes.tsx                 # ── SPA React Router route table
    ├── spa/                       # ── NEW SPA surfaces
    │   ├── guards.tsx             #    guest / authenticated route guards
    │   ├── pages/                 #    login, register, sso-callback (P2); chat + error boundary (P3)
    │   └── chat/                  #    P3 typed chat: use-chat-connection, commands-panel,
    │                              #    session-panel, message-transcript, tool-call-list, composer
    │
    ├── lib/                       # ── SHARED by BOTH trees (origin-relative networking + auth)
    │   ├── api.ts                 #    fetch wrapper — relative /api/...
    │   ├── socket.ts              #    Socket.IO singleton — relative /chat
    │   ├── auth-client.ts         #    BetterAuth client — relative /api/auth/...
    │   ├── auth-redirect.ts       #    post-auth redirect resolution (protocol-relative rejected)
    │   ├── chat-contract.ts       #    P3 typed chat wire contract (runtime-guarded)
    │   ├── sso.ts · types.ts · cn.ts
    │
    ├── app/                       # ══ LEGACY Next.js App Router (removed at P5)
    │   ├── (auth)/{login,register}/
    │   ├── (dashboard)/{admin,chat,projects,projects/[id],settings,tasks}/
    │   ├── auth/provider/[provider]/
    │   └── layout.tsx · page.tsx · globals.css
    │
    ├── components/                # ══ LEGACY Next component library (auth, chat, layout,
    │                              #    projects, settings, tasks, ui) — ported into spa/ across P3/P4
    └── providers/                 # ══ theme-provider (legacy; SPA equivalent under providers)

Legend: ── new SPA (keep), ══ legacy Next (removed at P5), shared lib/ in the middle.

3. Networking / serving model (why it's same-origin)

  • The SPA speaks origin-relative paths only: /api/..., /api/auth/..., /chat. No NEXT_PUBLIC_* / VITE_* origin var, no hard-coded http://localhost:14242 under apps/web/src.
  • Dev: vite.config.ts runs a dev-only proxy that forwards those paths to the Gateway (so the SPA on its dev port and the Gateway on :14242 behave as one origin).
  • Prod (target): the SPA is same-origin with the Gateway — the Gateway serves the built static bundle and the API/WS on :14242, so no proxy and no CORS. (The Gateway does not serve the web dist yet — adding that is the core of P5; see §5.)

4. Build scripts (apps/web/package.json)

Script Today Notes
dev next dev legacy dev server
dev:vite vite SPA dev server (+ dev proxy)
build node ../../scripts/build-web.mjs currently a Next build
build:vite vite build SPA production build → dist/
lint / typecheck / test eslint src / tsc --noEmit / vitest run tree-agnostic

At P5 the :vite variants become the defaults (dev→vite, build→vite build) and the Next build path is retired.

5. Increment map (P1P6)

# Increment Branch Status
P1 Vite + React Router skeleton beside Next (entry, router, guards, vitest) feat/webui-p1-vite-skeleton merged — PR #1143
P2 SPA data layer + same-origin auth (login/register/SSO pages, guards, relative api/socket/auth-client) feat/webui-p2-data-auth merged — PR #1144
P3 Typed SPA chat (spa/chat/*, chat-contract.ts, chat page + error boundary) feat/webui-p3-chat 🚧 in progress (unmerged)
P4 Port projects / tasks / settings / admin dashboard surfaces into the SPA tbd not started
P5 Cutover: Gateway serves the Vite dist on :14242; flip dev/build to vite; remove the legacy Next app/ tree + next.config.ts tbd not started
P6 CI / images (trails): build the SPA in CI, ship images tbd trails

Each increment follows the same delivery pipeline: brief traceable to the RFC → author → independent integrator verification (build+test+typecheck+lint) → independent code + security review (author ≠ reviewer) → author remediates → branch + PR to nextindependent merge-gate merges. Author self-reports are not trusted; every gate is re-derived independently.

6. Known dependency / blocker

  • Issue #1145 — Gateway dist boot is broken (DI failure on a defaulted constructor param); the Gateway currently runs dev-mode only. This is a hard precondition for P5: the Gateway cannot serve the SPA dist on :14242 until dist boot works. P3/P4 remain on the dev-proxy topology meanwhile.

7. Not part of Phase P (disambiguation)

docs/plans/2026-08-09-webui-fleet-claude-bridge.md and docs/scratchpads/webui-fleet-bridge-plan.md describe a separate WebUI ↔ fleet/Claude bridge effort. They are not the Phase P SPA migration and should not be conflated with the increments above.

8. Where the detail lives (extend these)

  • Per-increment working notes: docs/scratchpads/webui-p*-*.md (e.g. webui-p2-data-auth.md).
  • Stub — to flesh out: per-surface component inventory (which components/* port to which spa/*), the full SPA route table, the P5 cutover checklist, and the P6 CI/image plan.