feat: govern accessible appearance overrides

This commit is contained in:
2026-08-20 10:50:55 +02:00
parent 0fae09ba3c
commit f11c675d11
14 changed files with 796 additions and 19 deletions
+19 -6
View File
@@ -22,22 +22,35 @@ inherits the result through semantic tokens without module-specific CSS.
child scope; otherwise a tenant lock suppresses a personal override. The
authenticated profile reports the effective palette, source, inherited
palette, and lock state.
- Tenant branding is a separate policy surface and must preserve contrast and
status semantics in both modes.
- Advanced personal overrides are a separately governed surface. The system
must opt in, a tenant may inherit or block that decision, and palette locks
always suppress overrides. Changing either policy requires
`admin:policies:write` in addition to the owning settings permission.
## Palette safety and scope
The Settings preview shows the chosen or inherited accent in every applicable
light/dark preview before Save. Presets are checked for WCAG AA contrast in the
theme contract. Arbitrary token overrides and branding import/export are not
inferred from this preference and require their own governed follow-up.
theme contract. When policy permits, the shared advanced editor can atomically
override accent, surface, and semantic status pairs for both modes. Every
foreground/background pair must meet WCAG AA contrast, and success,
information, warning, and danger colors must remain distinct. Invalid stored
documents fail closed and are not partially applied.
Import and export use the exact versioned JSON schema `schema_version: "1"`.
Both `light` and `dark` must contain every supported token exactly once as a
six-digit hex value. Import changes only the local draft; Save persists the
whole document. Removing overrides returns to palette and policy inheritance.
The system default is disabled so upgrades do not unexpectedly admit arbitrary
branding. Tenant `null` means inherit, `false` blocks, and `true` is accepted
only while the system permits overrides.
Do not introduce fixed foreground/background colors in a module merely to make
one mode look correct. Add or reuse a semantic Core token, then define both
light and dark values. Bitmap content and externally authored HTML are exempt,
but their surrounding controls must still use the shared tokens.
`npm run test:theme-contract` verifies root mode/palette behavior, preset
contrast, and representative
`npm run test:theme-contract` verifies root mode/palette behavior, preset and
custom-override validation/application, and representative
Campaign, Calendar, Files, and Mail token consumption. The check runs before a
production WebUI build.
+5 -4
View File
@@ -173,10 +173,11 @@ shared CSS tokens and persisted user preference selection.
- Modules must style new UI with these tokens and shared controls. Module-local
CSS may tune layout and spacing, but it must not introduce a separate
appearance system.
- Appearance controls live in user settings first. The user preference wins
over future tenant and system defaults unless a separately documented policy
lock is introduced. Tenant defaults and policy
enforcement can be added later without changing the token contract.
- Appearance controls live in user settings. A personal palette wins over
unlocked tenant and system defaults; system and tenant locks take precedence.
Advanced personal token overrides additionally require system opt-in and may
be narrowed by tenant policy. Their versioned import/export document is
validated and applied all-or-nothing in both light and dark modes.
- Visual preview in settings is illustrative; it must reflect token families,
not become a second theme implementation.