fix(theme): persist one canonical preference
CI and Deploy / test (pull_request) Failing after 4m32s
CI and Deploy / deploy (pull_request) Has been skipped

This commit is contained in:
cesnimda
2026-08-15 13:11:44 +02:00
parent bd5362c8c2
commit 896746319b
5 changed files with 64 additions and 31 deletions
@@ -1,6 +1,6 @@
# UX-002 deterministic theme state
Updated: 2026-08-09
Updated: 2026-08-15
Status: `IMPLEMENTED — NOT VERIFIED`. Automated, build and local browser checks pass. Production and authenticated multi-user browser checks remain.
@@ -12,19 +12,20 @@ Theme changes also keyed `CssVarsProvider` and captured `themeMode` in the route
## Implemented contract
- Preference resolution is explicit user key, then anonymous preference for a user without a saved choice, then the documented `System` default.
- `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.
- Auth user-key changes have a dedicated event. It updates theme state without re-running authentication requests or creating an event loop.
- Relevant `storage` events update another tab without writing back. Unrelated storage events are ignored.
- 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 user/anonymous/System resolution before client application paint.
- 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 suite: 6/6.
- 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.
@@ -33,7 +34,7 @@ No backend, database, dependency, entitlement or production configuration change
## Remaining gates
- Authenticated User A/User B scoped preference switching was proven at the storage/event unit boundary but not with two live browser accounts because no isolated API authentication environment was running.
- 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.
@@ -42,8 +43,8 @@ No backend, database, dependency, entitlement or production configuration change
- Screenshots: `docs/audits/evidence/ux-002/`
- Commands/results: `docs/audits/verification-log.md` V-111V-113
- Tests: `job-tracker-ui/src/theme-state.test.tsx`
- Implementation commit: `11734ee`
- Initial implementation commit: `11734ee`; canonical-store/contrast correction: pending this change set.
## Rollback
Revert `11734ee`. No data migration is required; existing `themeMode:<user>` and `themeMode:anon` values remain compatible. Reversion restores the prior delayed-login theme and provider/router remount behavior.
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.