US02-05: Build the Static Application Shell #58

Merged
domverse merged 1 commits from us/US02-05-build-the-static-application-shell into main 2026-08-09 20:09:15 +02:00
Owner

Adds the reusable browser shell primitives Phase B views build on.

What

  • frontend/js/store.js — observable store (get/set/subscribe)
  • frontend/js/events.js — job activity adapter: SSE preferred, polling fallback, sharing the event seq as cursor so a transport switch never drops or repeats an event
  • frontend/js/api.jscancellable() (AbortController) + job endpoints; aborted requests reject with code cancelled
  • photo_pipeline/api/routes/jobs.py — SSE now emits default message events with the type in the JSON payload instead of event: <type>, so a browser EventSource consumes the open-ended type set (state:*, claimed, …) via onmessage without enumerating it. event: done sentinel and resumable id: cursors unchanged.

Acceptance

  • Separate static index.html/CSS/modular JS ✓ (pre-existing, extended)
  • Shared API client, store, router, error handling, cancellation, SSE/polling adapters ✓
  • Routes restore view + filters after reload ✓ (hash router; explicit reload test added)
  • HTML fallback never intercepts /api/v1 ✓ (test asserts JSON-only)

Tests

  • frontend/js/tests/ in-browser unit suite (15 assertions: api errors + cancellation, store transitions, routing, SSE→polling fallback) — no JS toolchain; served over the app's static mount, driven by playwright
  • tests/e2e/test_frontend_shell.py — unit suite + asset loading, deep-link + reload restore, JSON-only /api/v1, clean console/network
  • jobs-api and review-ui regression suites green

🤖 Generated with Claude Code

Adds the reusable browser shell primitives Phase B views build on. ## What - `frontend/js/store.js` — observable store (get/set/subscribe) - `frontend/js/events.js` — job activity adapter: SSE preferred, polling fallback, sharing the event `seq` as cursor so a transport switch never drops or repeats an event - `frontend/js/api.js` — `cancellable()` (AbortController) + job endpoints; aborted requests reject with code `cancelled` - `photo_pipeline/api/routes/jobs.py` — SSE now emits default `message` events with the type in the JSON payload instead of `event: <type>`, so a browser `EventSource` consumes the open-ended type set (`state:*`, `claimed`, …) via `onmessage` without enumerating it. `event: done` sentinel and resumable `id:` cursors unchanged. ## Acceptance - Separate static `index.html`/CSS/modular JS ✓ (pre-existing, extended) - Shared API client, store, router, error handling, cancellation, SSE/polling adapters ✓ - Routes restore view + filters after reload ✓ (hash router; explicit reload test added) - HTML fallback never intercepts `/api/v1` ✓ (test asserts JSON-only) ## Tests - `frontend/js/tests/` in-browser unit suite (15 assertions: api errors + cancellation, store transitions, routing, SSE→polling fallback) — no JS toolchain; served over the app's static mount, driven by playwright - `tests/e2e/test_frontend_shell.py` — unit suite + asset loading, deep-link + reload restore, JSON-only `/api/v1`, clean console/network - jobs-api and review-ui regression suites green 🤖 Generated with [Claude Code](https://claude.com/claude-code)
domverse added 1 commit 2026-08-06 15:48:35 +02:00
Add the reusable browser shell primitives Phase B views build on:

- store.js: observable store (get/set/subscribe)
- events.js: job activity adapter — SSE preferred, polling fallback,
  sharing the event `seq` as cursor so a transport switch drops nothing
- api.js: cancellable() (AbortController) + job endpoints; aborted
  requests reject with code "cancelled"

Make the SSE stream generically consumable: emit default `message`
events with the type in the JSON payload instead of `event: <type>`, so
a browser EventSource receives the open-ended type set (state:*,
claimed, …) via onmessage without enumerating it. The `event: done`
sentinel and resumable `id:` cursors are unchanged.

Tests: frontend/js/tests/ in-browser unit suite (api errors +
cancellation, store transitions, routing, SSE→polling fallback) served
over the app's static mount and driven by tests/e2e/test_frontend_shell.py,
which also asserts asset loading, deep-link + reload restore, JSON-only
/api/v1, and a clean console/network. Reuses the installed playwright —
no JS toolchain added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
domverse merged commit 344a41ca70 into main 2026-08-09 20:09:15 +02:00
Sign in to join this conversation.