Skip to content

feat(ui): Stage 1 demo mode — UI runs with no backend#220

Merged
luokerenx4 merged 1 commit into
masterfrom
feat/ui-demo-stage1
May 27, 2026
Merged

feat(ui): Stage 1 demo mode — UI runs with no backend#220
luokerenx4 merged 1 commit into
masterfrom
feat/ui-demo-stage1

Conversation

@luokerenx4
Copy link
Copy Markdown
Contributor

Summary

OpenAlice's web UI now runs with no backend when launched in demo mode. MSW v2 intercepts /api/* fetch + SSE so the UI bootstraps cleanly without Alice / UTA running. Auto-authed, PTY terminal stub'd, minimum-viable fixtures for the 5 non-trivial domains (auth / trading / workspaces / events SSE / chat SSE); the long tail of ~130 endpoints falls through a catchAll handler that returns 200 {} and console.warns the unmocked path so Stage 2 can walk the log and flesh out handlers as they actually break.

Continues the cost-curve-inversion line from #216 (Electron split, ~1G saved). Next axis: a cloud Claude Code session can now iterate on UI without standing up Alice + UTA. Also the structural prereq for the future marketing demo site (Stage 2, deferred).

Plan: /Users/ame/.claude/plans/merry-cooking-origami.md

What changed

Area Change
New: ui/src/demo/ MSW worker + 17 handler files + 4 fixture files + DemoTerminalStub.tsx + README. Dynamic-imported in main.tsx only when import.meta.env.VITE_DEMO_MODE is truthy → Rollup tree-shakes the whole subtree in prod builds.
New: ui/public/mockServiceWorker.js Generated by pnpm -F open-alice-ui msw:init. Committed (deterministic, version-pinned).
New: ui/.env.demo VITE_DEMO_MODE=true. .gitignore exception added since .env* is broadly gitignored.
New: ui/src/vite-env.d.ts import.meta.env types — referencing vite/client and declaring VITE_DEMO_MODE.
Edit: ui/src/main.tsx +4 lines: conditional await import('./demo') before createRoot.
Edit: ui/src/components/workspace/Terminal.tsx +2 lines: import DemoTerminalStub and early-return when env flag is on. Both the guard and the import are dead-code-eliminated in production.
Edit: ui/package.json +1 devDep (msw@^2.14.6), +3 scripts (dev:demo, build:demo, msw:init).
Edit: root package.json Adds scoped pnpm override msw>path-to-regexp: ^6.3.0. MSW v2 expects v6 path-syntax; root's security-pinned v8 override broke MSW's matcher. v6.3.0 is also patched for CVE-2024-45296.

Verification — end-to-end in browser

Ran pnpm -F open-alice-ui dev:demo with no backend running. Navigated via Playwright through:

  • /inbox (initial) — auto-authed, no login screen
  • /portfolio — demo UTA $10k equity, empty positions
  • /news — empty list
  • /workspaces/demo-ws — demo workspace + git/files panels render
  • /workspaces/demo-ws/s/demo-sessionDemo mode — terminal disabled stub renders, zero WebSocket attempts to /api/workspaces/pty (the key safety check)
  • /settings — settings page loads

Result: 0 console errors across the entire walk. 2 catchAll warns surfaced (PUT /api/config/snapshot, PUT /api/config/compaction) — these are the Stage 2 backlog signals working as designed.

Production bundle accounting

pnpm -F open-alice-ui build (no demo flag) → ui/dist/assets/index-*.js:

grep -l "mockServiceWorker|VITE_DEMO_MODE|setupWorker" ui/dist/assets/*.js   # zero matches
grep -lE "Demo mode|DemoTerminalStub" ui/dist/assets/*.js                    # zero matches
grep -oE "[a-zA-Z]*msw[a-zA-Z]*" ui/dist/assets/*.js | sort -u
# → "lmsw", "smsw", "tlimswitch" (substring noise only — no MSW library)

Main chunk 2.84MB / 845KB gzip — identical magnitude vs master (the chunk-size warning is pre-existing).

Install size delta

Profile Size
Full install (this branch) 1.2G
pnpm install --filter='!@traderalice/desktop' (cloud sessions) ~750M
Net change vs master +~13M (MSW + its tree under .pnpm)

The "UI-only install" sub-target hit a pnpm limitation: with --frozen-lockfile, pnpm populates .pnpm/ from the full lockfile regardless of --filter. Getting below 750M would require lockfile sharding — deferred.

Test plan

  • pnpm -F open-alice-ui tsc -b clean
  • pnpm -F open-alice-ui dev:demo + Playwright walkthrough (0 errors)
  • pnpm -F open-alice-ui build — no msw / VITE_DEMO_MODE / DemoTerminalStub refs in prod bundle
  • Terminal stub renders; zero pty WebSocket attempts
  • catchAll handler surfaces unmocked endpoints as console.warn (= Stage 2 backlog)
  • Manual: try pnpm dev (full stack) to confirm production path still works unchanged — deferred to reviewer (this is the non-demo path, untouched by this PR)

Out of scope (Stage 2)

Rich scenario fixtures, scripted SSE timelines, WebSocket PTY replay (waits for MSW v2 WS GA), in-memory mutation persistence, persistent "Demo Mode" UI banner, marketing-quality copy. The current PR lays the structural foundation; Stage 2 walks the [demo] unmocked … console.warn log to fill in coverage.

Boundary touch

None — no trading / auth / broker / migrations code modified.

🤖 Generated with Claude Code

MSW v2 intercepts /api/* fetch + SSE so the UI bootstraps cleanly with no
Alice/UTA running. Auto-authed, PTY terminal stub'd, minimum-viable fixtures
for the 5 non-trivial domains (auth, trading, workspaces, events SSE, chat
SSE); the long tail of ~130 endpoints falls through a catchAll handler that
returns 200 {} and console.warns the unmocked path so Stage 2 can walk the
log and flesh out per-endpoint handlers.

Colocated under ui/src/demo/ behind import.meta.env.VITE_DEMO_MODE — Rollup
tree-shakes the entire subtree (and the Terminal.tsx stub branch) out of
production bundles. Verified: prod bundle grep for msw/VITE_DEMO_MODE/
DemoTerminalStub returns zero matches.

Files of note:
- ui/src/demo/handlers/catchAll.ts uses a RegExp literal (not '/api/*'
  glob) to dodge a path-to-regexp v8 incompatibility inside MSW v2's
  string-pattern matcher
- Root pnpm.overrides adds scoped 'msw>path-to-regexp@^6.3.0' so MSW gets
  the v6-syntax-compatible (and CVE-patched) version, while everyone else
  stays on the security-pinned v8 override
- ui/src/components/workspace/Terminal.tsx gets a one-line early-return
  guard that renders DemoTerminalStub when demo mode is on — verified
  zero WebSocket attempts to /api/workspaces/pty when a session pane opens

Verified end-to-end in browser (Playwright):
- npx tsc -b in ui/ clean
- pnpm -F open-alice-ui dev:demo + navigate to /inbox, /portfolio, /news,
  /workspaces/demo-ws, /workspaces/demo-ws/s/demo-session, /settings: 0
  console errors throughout, demo terminal stub renders correctly
- 2 catchAll warns surfaced (PUT /api/config/snapshot, PUT
  /api/config/compaction) — Stage 2 backlog
- pnpm -F open-alice-ui build (no demo flag): 2.8MB main chunk, zero msw
  references, zero VITE_DEMO_MODE references, zero DemoTerminalStub

Out of scope (Stage 2): rich fixtures, scripted SSE timelines, PTY replay,
in-memory mutation persistence, demo-mode banner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@luokerenx4 luokerenx4 merged commit ba94328 into master May 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant