Files
stack/docs/scratchpads/webui-p2-data-auth.md
T

8.1 KiB

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

  • Loaded mission protocol, active MVP manifest/scratchpad, top-level tasks, PRD, relevant frontend/auth/testing/type/review guides, and matching skills.
  • Resolved host paths to the Distrobox-mapped repo and brief.
  • Confirmed branch feat/webui-p2-data-auth, stacked at P1 commit 068d0f9b.
  • Source and Gateway mount inspection complete.
  • RED tests observed.
  • Implementation complete.
  • Independent review complete and findings remediated.
  • Verification gates complete.
  • Local implementation commit created: 46d68e1f.

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 <Outlet />; 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 565ms.
  • apps/web: pnpm build — PASS: ✓ Compiled successfully in 4.6s; 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.
  • All six required gates above were repeated successfully after implementation commit 46d68e1f, proving the exact committed source tree.

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.