Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a45f53071a |
@@ -0,0 +1,115 @@
|
|||||||
|
# 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 (P1–P6)**; 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 (P1–P6)
|
||||||
|
|
||||||
|
| # | 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 `next` → **independent** 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.
|
||||||
Reference in New Issue
Block a user