critical priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

All interactive mode card touch targets measure at least 44×44 dp (verify via Flutter layout inspector and widget tests using tester.getSize())
Every text element and icon passes WCAG 2.2 AA contrast ratio: ≥4.5:1 for normal text, ≥3:1 for large text and UI components, validated against the project design tokens
Each mode card wraps its content in a Semantics widget with label, hint, and button role so screen readers announce both the mode name and its purpose in a single focused element
Focus traversal order matches visual top-to-bottom, left-to-right layout; no focus traps exist and all focusable elements are reachable via keyboard/switch access
TalkBack (Android) announces each card correctly when focused and double-tapped; VoiceOver (iOS) reads label + hint without extra noise
No accessibility issues flagged by Flutter's built-in semantics debugger (SemanticsDebugger) or the accessibility_checker package
Screen does not rely solely on colour to convey the distinction between the two modes — iconography or text labels must differentiate them
All design token colour values used on this screen produce passing contrast ratios; if any token fails, a token override is added and documented

Technical Requirements

frameworks
Flutter
flutter_test
performance requirements
Semantics tree rebuild must not cause frame drops — use const Semantics widgets where possible
Screen must render within 16 ms per frame on mid-range devices
security requirements
No personally identifiable information is exposed through accessibility labels or hints
ui components
Semantics (Flutter core) — wrap each mode card with label, hint, button role, and onTap
MergeSemantics — merge child semantics into a single announcement where appropriate
ExcludeSemantics — hide purely decorative icons from the accessibility tree
Design token colour values from the project token system (colors, typography, spacing)
SizedBox / ConstrainedBox — enforce 44×44 dp minimum touch target dimensions
FocusTraversalGroup — control traversal order explicitly if default order is incorrect

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Start by auditing the existing Proxy Mode Selector widget tree using Flutter DevTools' Accessibility inspector — identify every element missing a Semantics node. Add Semantics widgets bottom-up so parent merges work correctly. Use MergeSemantics around card content so TalkBack announces the full card as one item rather than each child separately. For contrast: pull colour values from design tokens and run them through a contrast checker; if any token fails AA, introduce a semantic colour override rather than hardcoding hex values.

Touch target enforcement: wrap tap areas in a GestureDetector or InkWell and use ConstrainedBox(constraints: BoxConstraints(minWidth: 44, minHeight: 44)) — never assume the visual card size matches the hit area. Ensure focus order: place mode cards in a Column and use FocusTraversalGroup with ReadingOrderTraversalPolicy. Finally, use ExcludeSemantics on decorative dividers and background images.

Testing Requirements

Write widget tests using flutter_test that: (1) assert tester.getSize() ≥ Size(44, 44) for every tappable widget; (2) pump the screen and call tester.getSemantics() to verify label, hint, and role values; (3) use SemanticsHandle to confirm no missing labels. Manually test with TalkBack on an Android device and VoiceOver on iOS, following WCAG 2.2 Success Criteria 1.1.1, 1.3.1, 1.4.3, 2.1.1, 2.4.3, and 2.5.3. Document manual test results in a checklist committed alongside the code. Run the accessibility_checker package in CI if available.

Component
Proxy Mode Selector Screen
ui low
Epic Risks (2)
medium impact medium prob technical

NHF coordinators may manage dozens of peer mentors across multiple chapters. If the multi-select list renders all contacts in a single unsorted ListView, performance degrades with 50+ items, and coordinators cannot efficiently locate a specific mentor, increasing the probability of selection errors and wrong-person proxy registrations.

Mitigation & Contingency

Mitigation: Use a SliverList with itemExtent for fixed-height rows to enable O(1) scroll position calculation. Implement the search filter using a debounce utility operating on an in-memory list (no extra API calls). Sort the contact list alphabetically by default. Add chapter-filter chips above the list for NHF's multi-chapter coordinators.

Contingency: If performance issues arise in testing with real data sets, introduce pagination with a 'load more' trigger at the bottom of the list and cache rendered rows using Flutter's AutomaticKeepAliveClientMixin.

high impact medium prob security

NHF has a complex 12-national-association / 9-region / 1,400-chapter hierarchy. It is ambiguous whether a coordinator can proxy-register for peer mentors outside their immediately assigned chapter. If the contact list is not correctly scoped by RLS, coordinators might see — and register on behalf of — peer mentors they do not manage, creating fraudulent activity records that skew Bufdir statistics.

Mitigation & Contingency

Mitigation: The Proxy Contact List Provider must query only peer mentors linked to the coordinator's own chapter scope via RLS. Add an explicit Supabase query test asserting that a coordinator from chapter A cannot retrieve peer mentors from chapter B. Display each mentor's chapter affiliation in the list row so coordinators can visually verify scope.

Contingency: If RLS scope is found to be too permissive in testing, apply a server-side coordinator_id filter as a secondary guard on the query. Block the feature release until the scope test passes consistently.