Add WCAG 2.2 AA accessibility to Detail Bottom Sheet
epic-scenario-based-follow-up-prompts-scheduler-and-ui-task-015 — Audit and enhance the ScenarioPromptDetailBottomSheet for WCAG 2.2 AA compliance: focus trap within the sheet when open, correct modal semantics role, screen reader announcements for wellbeing flag badges, sufficient contrast for all text elements, and keyboard/switch-access traversal order matching visual layout.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 9 - 22 tasks
Can start after Tier 8 completes
Implementation Notes
Use FocusScope with a dedicated FocusScopeNode to trap focus. In the sheet's initState (or first-frame callback via WidgetsBinding.instance.addPostFrameCallback), call FocusScope.of(context).requestFocus(firstFocusNode). Wrap the DraggableScrollableSheet or modal container with Semantics(explicitChildNodes: true) and set scopesRoute: true and namesRoute: true so Flutter's routing semantics announces it as a dialog. For wellbeing flag chips, each chip widget must have its own Semantics node — do not rely on color alone (this also satisfies WCAG 1.4.1 Use of Color).
When the sheet is popped, call Navigator.pop and immediately restore focus to the originating card using a stored FocusNode reference passed into the sheet. Traversal order is controlled by FocusTraversalGroup with ReadingOrderTraversalPolicy. Reuse existing design tokens for all colors — do not add new color values.
Testing Requirements
Widget tests using flutter_test: (1) pump the bottom sheet, call tester.ensureSemantics(), and verify SemanticsNode tree includes a dialog-role node; (2) assert the first FocusNode inside the sheet receives focus after showModalBottomSheet resolves (use FocusManager.instance.primaryFocus); (3) verify that all wellbeing flag badges have non-empty Semantics labels; (4) simulate Tab key press and assert focus stays within the sheet (FocusTrap behavior). Manual test on device with TalkBack (Android) and VoiceOver (iOS) to confirm announcement order. Contrast ratios must be verified with an external tool (e.g., Colour Contrast Analyser) against design token hex values.
If the scheduler runs concurrently (e.g., two overlapping cron invocations due to edge function retry), duplicate prompts could be dispatched before the first run's history records are committed, breaking the deduplication guarantee.
Mitigation & Contingency
Mitigation: Use a Postgres advisory lock or unique constraint on (user_id, scenario_id, activity_ref) in the prompt history table to make concurrent writes idempotent; design the scheduler to check history inside a transaction.
Contingency: If concurrency issues persist in production, add a distributed lock via Supabase Edge Function concurrency limit (max_instances=1) for the evaluation function as a hard guard.
Coordinators may find scenario configuration unclear if trigger conditions are expressed as raw JSON or technical terminology, leading to misconfiguration and irrelevant prompts being sent to peer mentors.
Mitigation & Contingency
Mitigation: Design the ScenarioConfigurationScreen to display human-readable descriptions of each template's trigger condition (e.g., 'Send 3 days after first contact if wellbeing concern was flagged') rather than raw rule properties; validate with an HLF coordinator in a design review before implementation.
Contingency: If coordinators still misconfigure rules after launch, add a preview mode that shows a simulated prompt based on a test activity before the rule is enabled.