Sibling to the #243 release rehearsal. #243 is a k6 capacity/load baseline (protocol-level, no browser). This issue is the complementary UI verification track: a real browser exercising the SPA, sharing #243's Seed:Simulation fixture so screens are realistic (populated dashboards, reports, history, lifecycle states) instead of empty.
New infra: the repo has no Playwright today (web/ is Vitest + Testing Library only; no playwright.config, no e2e/). This is a new E2E layer atop the existing SPA unit-test infra (#105–#124).
Goal
Verify the SPA works — and stays usable under load — from a real user's browser, per persona, against a production-config app with realistic data.
Two modes
1. E2E smoke suite (functional correctness)
Playwright drives the key flow per persona against the seeded env:
- Owner/Admin: dashboard → reports → audit browse → one
/export.
- Manager: daily-entry submit → review → adjust/void; flock ops.
- Sales: customer → draft order → add lines → confirm → record payment.
- Worker: daily entry by grade; the flock-restricted worker sees only assigned flocks (403/hidden on the rest).
- ReadOnly: read-heavy browsing; server-side 403 on deep-links to
/audit//users (no route-level gate — the 403 is the assertion).
Cross-cutting: login + in-memory access token + silent refresh across the 15-min boundary; i18n render (es/tl) not broken; the PWA update prompt path.
2. Canary-under-load UX probe (real experience under stress)
1–2 Playwright browsers running concurrently with the k6 load (#243), measuring what k6 cannot: page-load, Core Web Vitals (LCP/INP/CLS), asset loading, and visual correctness while the backend is saturated. Reported alongside #243's server-side percentiles. This is the heavier/hybrid piece — schedule after the k6 baseline + E2E smoke land.
Shared fixture (the reason to plan with #243)
Both tracks consume #243's deliverables — build once:
SimulationDataSeeder (Seed:Simulation) — the 10-persona cast + parameterized history. History depth must populate the exact screens the E2E suite asserts (non-empty dashboards/reports).
tools/simulation/.sim-cast.json — runtime-generated cast credentials; Playwright logs in from the same file k6 uses (never hardcode; git-ignored).
- The sim compose overlay + deterministic reset recipe.
Structure / decisions
Deferred / non-goals
Visual-regression baselining and accessibility (axe) sweeps are natural follow-ons, not in this issue's first cut. The load generation itself stays k6 (#243) — Playwright is never the crowd.
Refs
Security regression additions — 2026-07-31
Two underlying defects now have dedicated implementation issues. Keep Playwright as the end-to-end regression layer, not the place where the fixes themselves are hidden.
Acceptance additions
Sibling to the #243 release rehearsal. #243 is a k6 capacity/load baseline (protocol-level, no browser). This issue is the complementary UI verification track: a real browser exercising the SPA, sharing #243's
Seed:Simulationfixture so screens are realistic (populated dashboards, reports, history, lifecycle states) instead of empty.New infra: the repo has no Playwright today (
web/is Vitest + Testing Library only; noplaywright.config, noe2e/). This is a new E2E layer atop the existing SPA unit-test infra (#105–#124).Goal
Verify the SPA works — and stays usable under load — from a real user's browser, per persona, against a production-config app with realistic data.
Two modes
1. E2E smoke suite (functional correctness)
Playwright drives the key flow per persona against the seeded env:
/export./audit//users(no route-level gate — the 403 is the assertion).Cross-cutting: login + in-memory access token + silent refresh across the 15-min boundary; i18n render (es/tl) not broken; the PWA update prompt path.
2. Canary-under-load UX probe (real experience under stress)
1–2 Playwright browsers running concurrently with the k6 load (#243), measuring what k6 cannot: page-load, Core Web Vitals (LCP/INP/CLS), asset loading, and visual correctness while the backend is saturated. Reported alongside #243's server-side percentiles. This is the heavier/hybrid piece — schedule after the k6 baseline + E2E smoke land.
Shared fixture (the reason to plan with #243)
Both tracks consume #243's deliverables — build once:
SimulationDataSeeder(Seed:Simulation) — the 10-persona cast + parameterized history. History depth must populate the exact screens the E2E suite asserts (non-empty dashboards/reports).tools/simulation/.sim-cast.json— runtime-generated cast credentials; Playwright logs in from the same file k6 uses (never hardcode; git-ignored).Structure / decisions
web/(@playwright/test, co-located with the SPA) vs a standalonetools/simulation/ui/project — part of this issue's plan.Deferred / non-goals
Visual-regression baselining and accessibility (axe) sweeps are natural follow-ons, not in this issue's first cut. The load generation itself stays k6 (#243) — Playwright is never the crowd.
Refs
Security regression additions — 2026-07-31
Two underlying defects now have dedicated implementation issues. Keep Playwright as the end-to-end regression layer, not the place where the fixes themselves are hidden.
Acceptance additions