high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

All text on notification-preferences-screen, in-app-notification-banner, and scenario-notification-detail-view meets WCAG 2.2 SC 1.4.3: minimum 4.5:1 for normal text, 3:1 for large text (≥18pt regular or ≥14pt bold), verified with a colour contrast analyser against both light and dark themes
All interactive elements (toggles, buttons, tap targets) have a minimum touch target of 44×44 pt per WCAG 2.5.5; measured via the Flutter Inspector bounding boxes
The in-app-notification-banner auto-dismiss timer does not begin counting until the screen reader announces the banner content, respecting WCAG 2.2 SC 2.2.2
Focus order on all three screens is logical and follows the visual reading order; no focus traps exist; verified with VoiceOver (iOS) and TalkBack (Android) manual walkthroughs
Every interactive element has a non-empty, descriptive semanticLabel or Semantics node; no element announces only its widget type (e.g., 'button' without context)
All decorative images and icons that carry no informational value are marked excludeFromSemantics: true
All audit findings are documented in a structured checklist (component, WCAG criterion, finding, fix applied, status: pass/fail) committed to the repository
Zero WCAG 2.2 AA violations remain in the checklist at the end of this task; any deferred issues are logged with a rationale and owner
Fixes do not regress existing widget tests (all tests pass after changes)

Technical Requirements

frameworks
Flutter
Flutter Accessibility Inspector
performance requirements
Accessibility fixes must not introduce measurable frame-rate degradation; verify with Flutter DevTools Performance overlay before and after
ui components
Semantics widget (for custom semantic labels, excludeFromSemantics, liveRegion)
MergeSemantics (for compound widgets where child nodes should be announced as one)
ExcludeSemantics (for decorative elements)
Design-token colour system (must be used for all colour fixes to maintain consistency)

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Start with automated scanning (Flutter Inspector, Accessibility Scanner) to build the findings list, then manually verify with actual screen readers — automated tools miss focus-order and timing issues. For contrast fixes, always update design tokens (colours defined in the token system) rather than overriding colours inline; this ensures fixes propagate across all usages. For the in-app-notification-banner auto-dismiss timer, use a SemanticsService.announce() call when the banner appears and delay the dismiss timer start until after the announcement; this is the established pattern for live regions in Flutter. Touch target sizing: prefer adding padding inside the widget using SizedBox constraints rather than wrapping with GestureDetector to avoid hit-test layering issues.

The organisations using this app (NHF, Blindeforbundet, HLF) have users with severe visual and motor impairments — treat accessibility as a blocking requirement, not a nice-to-have.

Testing Requirements

Manual testing: walk through all three components with VoiceOver (iOS 17+) and TalkBack (Android 13+) using the swipe-based navigation. Use the Xcode Accessibility Inspector and Android Accessibility Scanner to flag contrast and label issues. Automated: add or update widget tests using tester.getSemantics() to assert semanticLabel values on all interactive elements for the three components. Run flutter test --coverage after fixes to confirm no regressions.

Document findings per component in a WCAG-audit-checklist.md file in the repository under docs/accessibility/.

Epic Risks (2)
medium impact medium prob technical

The in-app notification banner depends on a Supabase Realtime subscription to detect new notification records. If the subscription reconnects slowly after an app resume from background, or if Realtime delivery is delayed under high load, the banner may not appear within the 2-second acceptance criterion.

Mitigation & Contingency

Mitigation: Implement an explicit subscription reconnect handler on app foreground events using Flutter's AppLifecycleState.resumed hook, and add a polling fallback that queries for unread notifications once per app foreground event as a safety net against missed Realtime events.

Contingency: If Realtime proves unreliable in production, promote the polling fallback to the primary mechanism with a 30-second interval, accepting slight latency in exchange for reliability.

medium impact medium prob technical

Cold-start deep linking (app not running when push notification is tapped) requires deferred navigation after the Flutter engine and Supabase session are fully initialised. If the deep link is consumed before authentication completes, the router may navigate to a protected route without a valid session, causing an error or redirect loop.

Mitigation & Contingency

Mitigation: Implement a deferred navigation queue in scenario-deep-link-router that holds the parsed deep-link target until the auth session restoration lifecycle event fires, following the existing deep-link-handler pattern used in the BankID and Vipps authentication flows.

Contingency: If deferred navigation is not achievable within the epic's scope, fall back to navigating the user to the notification centre (which is always accessible post-login) where the relevant notification record is visible and tappable.