high priority medium complexity integration pending integration specialist Tier 5

Acceptance Criteria

OrgBrandingConfig is defined for all four organisations (NHF, Blindeforbundet, HLF, Barnekreftforeningen) with at minimum primaryColor, onPrimaryColor, and logoAssetKey fields
BrandingOverrideRequest wraps an OrgBrandingConfig and is submitted to TokenAccessibilityEnforcer.validate() before any token mutation occurs
TokenAccessibilityEnforcer returns a sealed Result<ValidatedBranding, BrandingValidationError> — the pipeline never proceeds on the error branch
BrandingValidationError is a typed class with a violationType enum (contrastFailure, touchTargetViolation, invalidAssetKey) and a human-readable message identifying the specific token that failed
A primary brand color with contrast ratio < 4.5:1 against its on-color is rejected with contrastFailure — verified with a unit test using a known low-contrast color pair
A valid override produces a ThemeBuildResult where ColorScheme.primary equals the org brand color for both light and dark variants
Switching between organisations (e.g., NHF → HLF) replaces the full branding config and re-runs the entire validation pipeline
Logo asset paths are validated against the Flutter asset manifest before acceptance — referencing a non-existent asset key returns invalidAssetKey error
Fallback to the default (unbranded) token palette occurs automatically when validation fails — no blank screen or crash

Technical Requirements

frameworks
Flutter
Material 3
Riverpod
apis
TokenAccessibilityEnforcer (internal)
Flutter AssetBundle API (for logo validation)
DesignTokenProvider (internal)
data models
accessibility_preferences
performance requirements
Branding validation must complete synchronously — asset key lookup via AssetBundle is the only permitted async step, debounced to one call per organisation switch
security requirements
OrgBrandingConfig must never be sourced from a remote API response without server-side signing — branding overrides applied only from app-bundled or Supabase-authenticated config
Organisation isolation: BrandingConfig for org A must never influence the theme when the authenticated user belongs to org B — enforced via JWT org claim check before config application
Supabase RLS must ensure branding config rows are readable only by users within the owning organisation
ui components
MaterialApp theme consumer
Logo widget (SvgPicture or Image.asset)

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Integration Task

Handles integration between different epics or system components. Requires coordination across multiple development streams.

Implementation Notes

Model BrandingOverrideRequest as an immutable value class and TokenAccessibilityEnforcer as a pure function class (no state). Use a sealed class Result pattern (Dart 3 sealed classes) for the validation return type to force callers to handle both branches at compile time. The four organisation brand colors (NHF red #D4202A, Blindeforbundet dark blue #003366, HLF green #007A5E, Barnekreftforeningen gold #F5A623 — confirm exact values with design) should be defined as constants in a BrandPalette class and tested against their on-colors. Keep the override pipeline separate from the base theme builder — it is an optional decoration layer, not a core dependency, to support orgs that use the default palette.

Testing Requirements

Unit tests: (1) valid NHF config passes validation and produces correct primary color in scheme, (2) low-contrast Blindeforbundet config returns BrandingValidationError with contrastFailure type, (3) invalid logo asset key returns invalidAssetKey error, (4) fallback palette is applied when validation fails, (5) switching from NHF to HLF config produces a fully different ThemeBuildResult. Integration test: mount a minimal app, inject each of the four org configs sequentially, and assert MaterialApp primary color matches expected brand color after each switch. No golden tests required at this layer — color correctness is asserted programmatically. 90% coverage on the override pipeline class.

Component
Accessible Theme Builder
infrastructure medium
Epic Risks (2)
high impact low prob scope

One or more of the four partner organisations may supply brand primary colors that cannot be paired with any standard foreground at 4.5:1 contrast (for example, a mid-range hue that is too light for dark text and too dark for white text). Rejecting these colors programmatically could cause a political dispute with the organisation and delay the feature.

Mitigation & Contingency

Mitigation: Before implementation begins, run all four organisations' existing brand primary colors through the contrast-ratio-validator against both white (#FFFFFF) and a near-black (#1A1A1A). Share the results with each organisation's contact person ahead of the theme builder sprint so any problematic colors can be adjusted collaboratively with advance notice.

Contingency: If an organisation insists on a non-compliant brand color, produce a compliant near-match (lightened or darkened along the hue's luminance axis) and present both options with contrast ratio evidence. Document the adjusted token in the manifest with an explicit note that the original brand color was non-compliant, and obtain written sign-off from the organisation.

medium impact medium prob scope

Flutter's ThemeData contains over 30 component theme properties. If the theme-builder only addresses the most common ones (Button, InputDecoration, Card) and leaves others at Flutter defaults, downstream feature teams may unknowingly use default-themed widgets that do not meet sizing or contrast requirements.

Mitigation & Contingency

Mitigation: Produce a full inventory of all ThemeData component theme properties and map each to either a token-driven override or an explicit pass-through decision documented in the theme builder code. Prioritise the inventory by frequency of use in the existing codebase (identified via Grep). Include a check in the CI lint runner that flags widgets using Flutter default component themes not covered by the theme builder.

Contingency: If the full inventory scope exceeds the sprint budget, ship with the highest-frequency components covered and add a tracked backlog item for each uncovered component theme, pairing with a temporary lint suppression comment that includes the backlog reference.