Build Certification Expiry Warning Banner widget
epic-peer-mentor-pause-management-foundation-task-010 — Implement the CertificationExpiryWarningBanner Flutter widget that displays a contextual warning when a peer mentor's certification is expiring within a configurable threshold (e.g., 30 days) or has already expired. Accept expiry date and status as parameters, apply correct design token colors, and support dismissal callbacks.
Acceptance Criteria
Technical Requirements
Implementation Notes
Compute the banner variant (hidden, warning, expired) in a static method or simple conditional at the top of the build method — avoid StatefulWidget unless dismissal state needs to be managed locally (which it should not be: dismissal state belongs in the parent/BLoC). For the color tokens, use the existing design token system (e.g., AppColors.warningBackground, AppColors.errorBackground) — check the design token definitions before adding new color names. The days-remaining calculation: final daysRemaining = expiryDate.difference(DateTime.now()).inDays; — note that this returns negative for past dates, so the expired check is daysRemaining <= 0. For the Semantics live region (important for VoiceOver/TalkBack used by Blindeforbundet users): wrap the visible banner in Semantics(liveRegion: true, label: '...') so screen readers announce it when it appears.
Export from the shared widgets barrel file alongside ExpectedReturnDatePicker.
Testing Requirements
Write flutter_test widget tests covering: (1) banner is invisible (SizedBox.shrink) when expiry is 31+ days away with default threshold, (2) warning banner renders correctly when expiry is within threshold (e.g., 15 days), (3) expired banner renders when expiryDate is in the past, (4) today's date is treated as expired, (5) dismiss button appears when onDismissed is provided, (6) dismiss button is absent when onDismissed is null, (7) tapping dismiss calls onDismissed callback, (8) Semantics tree includes correct label for screen readers. Add golden tests for expired and warning states. Test with warningThresholdDays values of 0, 1, and 30 to verify boundary conditions.
Supabase RLS policies for coordinator-scoped status queries may be difficult to express correctly, especially for peer mentors assigned to multiple coordinators or chapters, leading to data leakage or overly restrictive access blocking valid queries.
Mitigation & Contingency
Mitigation: Design RLS policies using security-definer RPCs rather than table-level policies for complex multi-coordinator scenarios. Write a comprehensive RLS test matrix covering all role and assignment permutations before marking complete.
Contingency: Fall back to application-level filtering in the repository layer with explicit coordinator_id parameter checks if RLS proves intractable, and document the trade-off for security review.
The HLF Dynamics portal API contract may be undocumented or subject to change, causing the DynamicsPortalClient to break during development or production rollout.
Mitigation & Contingency
Mitigation: Obtain the full Dynamics portal API specification and credentials early in the sprint. Build the client behind a well-defined interface so the HLF-specific implementation can be swapped without affecting upstream services.
Contingency: If the Dynamics API is unavailable or unstable, stub the client with a feature-flag-guarded no-op implementation so all other epics can proceed to completion independently.
Supabase Edge Functions used as the nightly scheduler host may have cold-start latency or execution time limits that prevent reliable nightly certification checks on large mentor rosters.
Mitigation & Contingency
Mitigation: Benchmark Edge Function execution time against the expected roster size. Design the expiry check to process in paginated batches to stay within execution limits. Use pg_cron with a direct database function as an alternative trigger if Edge Functions prove unreliable.
Contingency: Migrate the scheduler trigger to pg_cron invoking a Postgres function directly, removing the Edge Function dependency entirely for the scheduling layer.