# WebUI Phase P — P2 Data + Auth Scratchpad **Task ID:** WEBUI-P2 **Tracking ref:** stacked on PR #1143 (`feat/webui-p1-vite-skeleton`); no separate issue specified in the author brief **Branch:** `feat/webui-p2-data-auth` **Started:** 2026-08-09 **Role:** P2 author worker (must not modify `docs/TASKS.md`) ## Original tasking > Read `/home/jwoltje/briefs/P2-brief.md` and execute it fully in `/home/jwoltje/src/stack-p1` on branch `feat/webui-p2-data-auth`. Run every listed verification gate, commit locally only, and do not push. Container path mapping: - Brief: `/home/jwoltje/distrobox-homes/mosaic-dev/briefs/P2-brief.md` - Repo: `/home/jwoltje/distrobox-homes/mosaic-dev/src/stack-p1` ## Objective Make the P1 Vite SPA authenticate against the Mosaic Gateway by same-origin relative paths, replace guest-route placeholders with real login/register/SSO callback pages, and enforce guest/authenticated route guards without modifying the parallel Next app tree except for unavoidable shared-library import fixes. ## Scope and invariants - All SPA HTTP and Socket.IO access remains origin-relative (`/api/...`, `/api/auth/...`, `/chat`). - No `NEXT_PUBLIC_*`, `VITE_*` origin setting, or hard-coded `http://localhost:14242` under `apps/web/src/`. - Verify the Gateway BetterAuth mount path from source before choosing auth-client configuration. - Delete the legacy static SSO-provider discovery module and test; runtime `/api/sso/providers` is canonical. - Preserve the Next build while adding React Router guest pages and session guards. - Never push; stage named files only; do not touch the modified `.mosaic/orchestrator/session.lock`. ## Plan 1. Inspect P1 SPA structure, shared libraries, legacy Next auth pages/components, Gateway auth mount, and current test setup. 2. Add/adjust tests first for relative API behavior, auth-client origin configuration, relative Socket.IO singleton behavior, and all guard session states; run focused tests and capture expected RED failures. 3. Implement shared-library relative networking and remove the legacy SSO-provider module/imports. 4. Port login, register, and provider callback pages to React Router and wire routes. 5. Implement session-aware guest/auth guards and satisfy focused tests. 6. Run focused tests, all brief verification gates, invariant searches, and an independent code/security review; remediate and re-run affected gates. 7. Update this scratchpad with evidence, stage named files only, and commit locally. ## Testing strategy - TDD is required because this increment changes authentication/session behavior. - Primary situational evidence: jsdom router guard state tests plus guest-page/auth-flow contract tests already present or added as needed. - Baseline gates: web tests, Vite build, Next build, typecheck, lint, and root format check exactly as listed in the brief. - Browser automation is not required by the brief for P2; if used, it will be headless only. ## Budget No explicit user token cap was provided. Working soft cap: **30K tokens**, derived from a multi-file auth/frontend increment with tests, dual builds, review, and remediation. Keep implementation within the brief; no unrelated refactors or dependencies. ## Progress / evidence - [x] Loaded mission protocol, active MVP manifest/scratchpad, top-level tasks, PRD, relevant frontend/auth/testing/type/review guides, and matching skills. - [x] Resolved host paths to the Distrobox-mapped repo and brief. - [x] Confirmed branch `feat/webui-p2-data-auth`, stacked at P1 commit `068d0f9b`. - [x] Source and Gateway mount inspection complete. - [x] RED tests observed. - [x] Implementation complete. - [x] Independent review complete and findings remediated. - [x] Verification gates complete. - [ ] Local commit created. ### Source decisions - Gateway source mounts BetterAuth at `/api/auth/` in `apps/gateway/src/auth/auth.controller.ts`; `packages/auth/src/auth.ts` configures `basePath: '/api/auth'`. - BetterAuth 1.5.5 defaults its browser client to `/api/auth` when `baseURL` is omitted. `src/lib/auth-client.ts` therefore omits `baseURL`, preserving same-origin behavior without encoding any gateway origin. - The only `src/app/` edit is the transitional Next provider redirect page. Deleting `src/lib/sso-providers.ts` required that mechanical consumer migration; it now uses the same runtime `/api/sso/providers` discovery and callback sanitizer as the SPA. - GuestGuard pending behavior intentionally follows the approved brief: if no session object exists (including pending), render ``; only a present session redirects to `/chat`. AuthGuard alone renders the specified pending treatment. ### TDD evidence - Initial focused run: 9 expected failures, proving absolute API/auth/socket origins, P1 guest placeholders, and missing guard redirects/loading behavior. - After implementation: focused contract suite 15/15 passed. - Security remediation RED: `%2F%0A%2F%2Fevil.example` reached `signIn.oauth2` as an external-normalizing callback target before the fix. - Security remediation GREEN: shared `resolveAuthCallbackURL` unit suite 9/9 plus SPA callback regression 1/1 passed; both SPA and Next consumers use the shared helper. ### Independent review - Primary Codex wrappers could not run because `jq` is absent; direct Codex fallback then failed authentication with HTTP 401. No review result was claimed from those attempts. - Independent Claude Sonnet code review found no implementation-scope blocker, one pending-state UX suggestion, and one pre-existing `api.ts` type-assertion suggestion. The pending-state suggestion was rejected because it contradicts the brief's explicit GuestGuard contract; the API cleanup is outside P2's preserve-contract scope. - Independent Claude Sonnet security review found a high-severity control-character open redirect in the callback prefix check shared by the newly ported SPA logic and transitional Next consumer. - Remediation centralized WHATWG URL parsing plus exact current-origin comparison in `src/lib/auth-redirect.ts`, returns only path/search/hash, and added the RED-first regression above. - Fresh code re-review: `approve`, 0 blockers, 0 should-fix findings. - Fresh security re-review: `low`, 0 critical/high/medium/low findings. ### Documentation checklist disposition - `docs/PRD.md` exists and P2 aligns to FR-8 / AC-7 authentication requirements. - No Gateway endpoint, DTO, permission, or API schema changed; existing `/api/auth/*` and `/api/sso/providers` contracts are consumed unchanged, so OpenAPI/API-index updates are not applicable. - Route paths were already present in the P1 route table; P2 replaces placeholders without changing site-map navigation, so `docs/SITEMAP.md` is unchanged. - User/admin auth behavior is parity with the still-live Next implementation, not a new workflow. Implementation decisions, failure behavior, testing, and migration compatibility are documented here; no publishing action is in scope. - Documentation remains in-repo; no generated publishing output was created. ### Final verification evidence Run fresh after remediation from the locations required by the brief: - `apps/web: pnpm test` — PASS: `Test Files 9 passed (9)`; `Tests 27 passed (27)`. - `apps/web: pnpm build:vite` — PASS: `✓ 113 modules transformed`; `✓ built in 712ms`. - `apps/web: pnpm build` — PASS: `✓ Compiled successfully in 4.4s`; 10/10 static pages generated; dynamic provider/project routes retained. - `apps/web: pnpm typecheck` — PASS: `tsc --noEmit` exited 0. - `apps/web: pnpm lint` — PASS: `eslint src` exited 0. - Root `pnpm format:check` — PASS: `All matched files use Prettier code style!`. - Invariant scan — PASS: no `NEXT_PUBLIC_*`, `VITE_*`, `GATEWAY_URL`, `http://localhost:14242`, or `sso-providers` references under `apps/web/src`. - `git diff --check` — PASS. ## Risks / blockers - `.mosaic/orchestrator/session.lock` is modified by the active harness and must remain unstaged. - P2 changes shared `src/lib/` modules consumed by both Vite and Next, so the Next build is a required compatibility gate.