high priority low complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

Tapping the 'View profile' button in MentorInfoPopup navigates to the peer mentor detail screen with the correct mentor ID passed as route parameter
Back button from the peer mentor detail screen returns the user to MapViewScreen with all previously applied filters intact (availability, specialisation selections preserved in BLoC state)
Map viewport position (zoom level, center coordinates) is preserved after returning from detail screen
The deep-link button has Semantics widget with label exactly matching 'View profile of [mentor name]' where [mentor name] is the actual mentor's display name
The Semantics widget on the button has role set to SemanticsRole.button
Navigation uses StatefulShellRoute or equivalent pattern so map tab state is not discarded
No duplicate navigation pushes occur if the user taps the button multiple times rapidly (debounce or disable-on-tap guard)
If the mentor detail screen fails to load (network error), the user remains on the map with a snackbar error message rather than a blank screen

Technical Requirements

frameworks
Flutter
BLoC
apis
Supabase REST API (peer mentor profile fetch by ID)
data models
PeerMentor
MentorProfile
performance requirements
Navigation push must complete within 300ms on mid-range devices
Map state restoration on back must not trigger a full map reload
security requirements
Mentor ID passed via route must be validated as a non-empty UUID before navigation to prevent injection via deep-links
Route parameters must not expose sensitive mentor data (only ID)
ui components
MentorInfoPopup (241-mentor-info-popup)
Peer mentor detail screen route
AppButton or equivalent with Semantics wrapper

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Use GoRouter's push (not go) so the back stack is preserved. Store map filter state in the BLoC, not in widget local state, so it survives route pushes. Wrap the button widget in a Semantics widget: Semantics(label: 'View profile of ${mentor.displayName}', button: true, child: ...). Disable the button immediately on tap using a BooleanCubit or onTap guard flag and re-enable only if navigation is cancelled.

Do not pass the full mentor object through the route; only pass the ID and let the detail screen fetch its own data.

Testing Requirements

Write widget tests verifying that tapping the popup button triggers the correct GoRouter/Navigator push with the mentor's ID. Write a BLoC unit test confirming filter state is unchanged after a simulated navigation round-trip. Write a Flutter integration test (flutter_test) using a mock navigator observer to assert route push arguments. Test the semantics tree with tester.getSemantics() to confirm label and role.

Test rapid double-tap does not push route twice.

Component
Mentor Info Popup Card
ui low
Epic Risks (3)
high impact high prob technical

Flutter's map canvas (flutter_map) does not natively support semantic focus traversal for screen readers, meaning map markers may be entirely invisible to VoiceOver/TalkBack users. If the accessible list fallback is not treated as a first-class view, screen reader users will have no access to the feature.

Mitigation & Contingency

Mitigation: From sprint 1, treat mentor-list-fallback as a fully featured primary view, not an afterthought. Implement and test it in parallel with the map canvas. Make the view-toggle-button keyboard focusable and announced on every screen state. Conduct VoiceOver testing on device before submitting each PR touching UI components.

Contingency: If map canvas accessibility cannot be achieved for marker focus traversal, make the view-toggle-button the default focus target on screen load for VoiceOver users (detected via screen-reader-detection-service) so they are immediately directed to the list fallback without needing to discover the toggle.

medium impact medium prob technical

The mentor-info-popup must occupy no more than 40% of visible map area on small screens. On devices with screen heights under 667px (iPhone SE), overlapping with the filter panel or obscuring most of the map could severely degrade usability.

Mitigation & Contingency

Mitigation: Implement the popup as a bottom sheet capped at 40% of screen height with a ScrollView for overflow content. Test on iPhone SE (375x667pt) and the smallest commonly used Android form factor in the device lab. Define max-height as a percentage constant in location-privacy-config or design tokens.

Contingency: If the popup cannot fit all required fields within 40% height on smallest targets, truncate assigned contact count and certification badge to icons-only in the compact view, with a 'View Profile' button always visible at the bottom of the popup regardless of scroll position.

medium impact medium prob integration

Filter state must remain perfectly synchronised between the map view and the list fallback. If the filter panel emits state that is not consumed identically by both views, coordinators switching between views will see inconsistent mentor sets, eroding trust in the feature.

Mitigation & Contingency

Mitigation: Store active filter criteria in a single shared Riverpod provider owned by the map-view-screen and consumed by both map-marker-widget (via mentor-location-service) and mentor-list-fallback. Write integration tests that apply a filter, switch views, and assert identical mentor counts in both views.

Contingency: If filter sync proves brittle, simplify to a single filter state object passed explicitly as a constructor argument to both views on each rebuild, eliminating indirect state sharing.