high priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

AssignmentStatusIndicator is a StatelessWidget that accepts a required AssignmentStatus enum (open, pending, completed) and an optional String? orgLabel
Open status renders with amber background and dark-on-amber text achieving WCAG 2.2 AA contrast ratio ≥4.5:1 in both light and dark theme
Pending status renders with blue background and white/dark text achieving WCAG 2.2 AA contrast ratio ≥4.5:1 in both light and dark theme
Completed status renders with green background and dark/white text achieving WCAG 2.2 AA contrast ratio ≥4.5:1 in both light and dark theme
When orgLabel is provided, the badge displays orgLabel text instead of the default status name; colour logic is determined solely by AssignmentStatus enum value
When orgLabel is null, the badge displays a default English label: 'Open', 'Pending', or 'Completed'
Badge uses design token colours (not hardcoded hex values) for background and text, referencing the token system established in the project
Widget has a fixed compact size appropriate for inline use within list cards and detail headers (height ≤28dp, horizontal padding 8dp)
Widget renders correctly at Flutter's default text scale (1.0) and at 2.0 text scale without layout overflow
Widget does not depend on any BLoC or Riverpod provider — it is a pure presentation primitive

Technical Requirements

frameworks
Flutter StatelessWidget
Flutter design token system (project token constants)
data models
AssignmentStatus enum (open, pending, completed)
performance requirements
Widget build method has no conditional futures or async work — it is synchronous and O(1)
Widget is const-constructible when orgLabel is not provided
ui components
Container with BoxDecoration for badge background and border-radius
Text widget for label
Semantics widget (added in task-012)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Define AssignmentStatus as an enum with a method or extension that returns the (backgroundColor, textColor) token pair — this keeps the colour logic close to the type definition and makes it easy to add new statuses later. Use the project's existing design token constants (e.g. AppColors.statusAmber, AppColors.statusBlue) rather than Theme.of(context) colour slots, because status colours are semantic and should not invert on dark mode. To achieve WCAG AA on both light and dark backgrounds, use slightly different amber/blue/green shades for each mode — pass the current Brightness from Theme.of(context).brightness into the token lookup.

Keep the widget const-constructible for performance: mark the constructor const and make orgLabel a named parameter with default null. Do not add Semantics in this task — that is handled in task-012.

Testing Requirements

Widget tests using flutter_test and WidgetTester: (1) for each of the three statuses, pump the widget and verify the correct background color token is applied, (2) verify that when orgLabel='Åpen oppfølging' is passed, the badge shows that text rather than 'Open', (3) verify colour contrast ratios programmatically by extracting background/foreground color pairs and computing the WCAG contrast ratio formula — assert ≥4.5:1 for all three statuses in both ThemeData.light() and ThemeData.dark(), (4) verify no RenderFlex overflow at textScaleFactor 2.0, (5) verify widget is pure (no provider lookup, no setState). Use goldenFileComparator for visual regression if the project has golden test infrastructure.

Component
Assignment Status Indicator
ui low
Epic Risks (3)
high impact medium prob security

Blindeforbundet's encryption key retrieval mechanism may not be finalised at implementation time, or session key availability via Supabase RLS may be inconsistent, causing decryption failures that expose masked placeholders to users and degrade the experience.

Mitigation & Contingency

Mitigation: Agree with Blindeforbundet on key storage and retrieval contract before implementation starts. Prototype key retrieval in a spike against the staging Supabase instance and validate the full decrypt/verify cycle with real test data before committing to the implementation.

Contingency: Implement a fallback that shows a 'field temporarily unavailable' state with a retry affordance. Log decryption failures server-side for audit. Escalate to Blindeforbundet stakeholders to unblock key management before the service tier epic begins.

medium impact medium prob technical

NHF contacts may belong to up to 5 chapters, each governed by separate RLS policies. A coordinator's chapter scope may not cover all affiliations, causing partial profile reads or silent data omissions that are difficult to detect in tests.

Mitigation & Contingency

Mitigation: Map all RLS policy combinations for multi-chapter contacts early. Write integration tests that create contacts with 5 affiliations and query them from coordinators with varying chapter scopes. Use Supabase's RLS test utilities to verify row visibility per role.

Contingency: Add an explicit 'affiliation partially visible' state in the repository response model so the UI can communicate scope limitations to the coordinator rather than silently showing incomplete data.

low impact medium prob scope

Organisation-specific validation rules (e.g., NHF chapter limit, Blindeforbundet encrypted field edit flow) may expand in scope during implementation as edge cases are discovered, causing the validator to grow beyond the planned complexity.

Mitigation & Contingency

Mitigation: Define the complete validation rule set with product and org stakeholders before coding begins. Document each rule with its source organisation and acceptance test. Use a rule registry pattern so new rules can be added without modifying core validator logic.

Contingency: Timebox validator enhancements to 2 hours per additional rule. Defer non-blocking rules to a follow-on maintenance task rather than blocking the epic delivery.