critical priority low complexity infrastructure pending frontend specialist Tier 0

Acceptance Criteria

Dart abstract class AccessibleThemeBuilder is defined with methods buildLightTheme(OrgBrandingConfig config) → ThemeBuildResult and buildDarkTheme(OrgBrandingConfig config) → ThemeBuildResult
OrgBrandingConfig is an immutable data class (using const constructors or freezed) with fields: orgId (OrgIdentifier enum), primaryColor (Color), secondaryColor (Color), logoAssetPath (String), and optional overrides
OrgIdentifier enum has exactly four values: nhf, blindeforbundet, hlf, barnekreftforeningen
ThemeBuildResult is an immutable data class containing lightTheme (ThemeData) and darkTheme (ThemeData)
BrandingOverrideRequest is an immutable data class allowing partial overrides of OrgBrandingConfig fields
All public classes and methods have Dart doc comments explaining their purpose and parameters
The interface compiles without errors (verified by npm run build equivalent: dart analyze --fatal-infos)
No concrete implementations are included in this task — only abstract interface and data classes
All four organizations' default OrgBrandingConfig instances can be constructed without error

Technical Requirements

frameworks
Flutter
Dart
data models
OrgBrandingConfig
ThemeBuildResult
BrandingOverrideRequest
OrgIdentifier
performance requirements
Data class construction must be O(1) — no async operations in constructors
ThemeData generation must complete synchronously
security requirements
No hardcoded credentials or API keys in branding configuration
Asset paths must be validated against pubspec.yaml declared assets at runtime in debug mode

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Integration Task

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

Implementation Notes

Place all interface and data class definitions in lib/src/theme/accessible_theme_builder.dart. Use Dart's abstract interface class keyword (Dart 3.0+) for AccessibleThemeBuilder to prevent mixin abuse. For immutability, use const constructors throughout — avoid freezed unless it is already a project dependency, to minimize new dependencies. Define OrgIdentifier as an enum with a name property and optional defaultConfig() factory for convenience.

Keep ThemeBuildResult simple: two ThemeData fields, no additional logic. The BrandingOverrideRequest should mirror OrgBrandingConfig but with all fields nullable to allow partial overrides via a merge method. Export all types from a single lib/src/theme/theme.dart barrel file.

Testing Requirements

Unit tests for data class construction: verify that OrgBrandingConfig can be constructed for all four OrgIdentifier values, that copyWith() produces correct partial overrides on BrandingOverrideRequest, and that equality checks work correctly (two configs with same values are equal). Use dart test (not flutter test) since no widget rendering is needed. Verify dart analyze --fatal-infos passes with zero issues. Target 100% coverage of all data class constructors and factory methods.

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.