Files
jobtrackingapp/docs/verification/ux-002-deterministic-theme-state.md
T
cesnimda a7c25499bb
CI and Deploy / test (pull_request) Successful in 4m54s
CI and Deploy / deploy (pull_request) Has been skipped
fix(a11y): close cross-app interaction gaps
2026-08-15 17:49:42 +02:00

4.2 KiB
Raw Blame History

UX-002 deterministic theme state

Updated: 2026-08-15

Status: IMPLEMENTED — NOT VERIFIED. Automated, build and local browser checks pass. Production and authenticated multi-user browser checks remain.

Confirmed root cause

The theme preference was keyed by the last authUserKey, but login completion emitted the general authentication event before /auth/me stored the new user key. Shell then stored that key with event emission disabled. Theme state therefore continued using the anonymous preference until a refresh, when the user key was already present and the page appeared to switch theme randomly. Logout had a similar asynchronous boundary.

Theme changes also keyed CssVarsProvider and captured themeMode in the router memo. A preference change remounted the provider and recreated the router, risking loss of in-page state even though the URL did not intentionally change. MUI also retained its own default local-storage mode, creating another potential source of truth.

Implemented contract

  • jobtracker.themeMode is the single browser preference. Login, logout and delayed /auth/me resolution cannot change it.
  • The first read migrates the former current-user/anonymous value into the canonical key, preserving existing choices.
  • Explicit Light and Dark ignore operating-system changes. Only System resolves through the current media query.
  • Canonical storage events update another tab without writing back. Auth and unrelated storage events are ignored.
  • MUI mode is changed in place through its color-scheme context with its private persistence disabled. The app/router tree is not keyed or recreated by theme changes.
  • A Next beforeInteractive bootstrap applies the same canonical/migration/System resolution before client application paint.
  • Semantic Alert variants use explicit theme severity surfaces and foreground tokens; dark warning/error/info/success text no longer inherits dark-on-dark defaults.
  • Settings tabs are scrollable at narrow widths; this removes the mobile overflow discovered during the required theme browser pass.

No backend, database, dependency, entitlement or production configuration changed.

Verification

  • Focused deterministic theme and confirmation suites: 8/8.
  • Full frontend: 48/48 suites and 172/172 tests.
  • Production frontend build/TypeScript and git diff --check: pass.
  • Browser: explicit Light persisted across Settings → Dashboard navigation and refresh; explicit Dark switched without navigation; System selected the browser's dark preference; a second tab inherited Dark and changing it to Light updated the first tab without reload.
  • Browser widths: 375, 768 and 1440; document width did not exceed the viewport after the tabs correction. Light 375/768 and Dark 1440 evidence is retained.
  • Browser console warnings/errors after the final interactive pass: none. Development HMR emitted transient module-update messages while source files were being edited; they were not present in the captured tab diagnostics and the clean production build passes.
  • Cross-application follow-up: every icon-only frontend control has an explicit accessible name; dark missing-job Alert contrast is measured from computed Chromium styles at WCAG AA 4.5:1 or better; public CV framing has no outer or inner overflow at 375px. Full frontend 54 suites/228 tests, build and Playwright 7/7 pass (V-170).

Remaining gates

  • Refresh/navigation and migration are automated; the revised canonical store still needs a real authenticated browser refresh pass before production verification.
  • A real operating-system preference-change event was tested at the resolver/provider boundary, not by changing the host OS during browser automation.
  • Production deployment/browser smoke is not authorized/configured.

Evidence

  • Screenshots: docs/audits/evidence/ux-002/
  • Commands/results: docs/audits/verification-log.md V-111V-113 and V-170
  • Tests: job-tracker-ui/src/theme-state.test.tsx
  • Initial implementation commit: 11734ee; canonical-store/contrast correction: pending this change set.

Rollback

Revert the canonical-store correction to restore account-scoped lookup. No destructive data migration is required; old themeMode:<user> values remain untouched and the canonical key can be removed independently.