critical priority medium complexity frontend pending frontend specialist Tier 7

Acceptance Criteria

On BLoC emitting LoginSuccess, the app navigates to the coordinator home screen when role is 'coordinator'
On BLoC emitting LoginSuccess, the app navigates to the peer mentor home screen when role is 'peer_mentor'
On BLoC emitting LoginSuccess, the app navigates to the org admin home screen when role is 'org_admin'
Navigation uses GoRouter named routes — no imperative Navigator.push calls
The login screen is removed from the navigation stack on success (GoRouter.go, not push), so back button does not return to login
No intermediate flicker or blank screen between login and destination screen
If the role resolved from the session is unrecognised or missing, navigate to a no-access screen with an appropriate message
Navigation is triggered exactly once per success event (no duplicate navigations on BLoC rebuild)
The routing logic reads role from the authenticated session/user metadata, not from a local variable that could be stale
Deep-linking compliance: if a deep link was pending before login, navigate to it after successful authentication with the correct role guard

Technical Requirements

frameworks
Flutter
BLoC
GoRouter
flutter_bloc
apis
Supabase Auth (user metadata / JWT claims for role)
data models
LoginSuccessState (contains AuthSession/UserRole)
UserRole enum (coordinator, peer_mentor, org_admin)
performance requirements
Route resolution completes synchronously from session data — no additional async round-trips at navigation time
Transition to destination screen renders first frame within one frame of navigation call (~16ms)
security requirements
User role must be read from the JWT claims or Supabase user metadata — never from client-supplied input
Unrecognised roles must route to no-access screen, never silently fall through to a privileged screen
ui components
GoRouter named route configuration (coordinator-home, peer-mentor-home, org-admin-home, no-access)
BlocListener for one-time navigation side effect

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

Use BlocListener (not BlocBuilder) for navigation side effects — this ensures navigation fires exactly once as a side effect of state change, not on every rebuild. Define a _navigateForRole(BuildContext context, UserRole role) private method in LoginScreen that calls context.go(RouteNames.forRole(role)). The RouteNames.forRole() mapping should live in a central router constants file, not inline. Extract role from the LoginSuccess state's AuthSession.user.userMetadata['role'] field (set by Supabase on sign-in).

Guard against null/missing role by defaulting to the no-access route. For deep-link support, store any pending redirect in GoRouter's redirect logic using a notifier pattern — the redirect resolves after auth state changes. The StatefulShellRoute used for tab navigation should only be entered after role is confirmed — do not enter it and then check role inside.

Testing Requirements

Widget/integration tests (flutter_test): (1) Mock BLoC emits LoginSuccess with coordinator role → verify GoRouter navigated to coordinator-home route; (2) peer_mentor role → peer-mentor-home route; (3) org_admin role → org-admin-home route; (4) unknown role → no-access route; (5) verify LoginScreen is not in the navigation stack after success (use GoRouter.routerDelegate.currentConfiguration); (6) verify BlocListener only triggers navigation once even if the BLoC state is rebuilt. Use MockGoRouter or GoRouter test helpers. No golden tests required for this task.

Component
Login Screen
ui low
Epic Risks (3)
high impact medium prob scope

Automated accessibility checks (e.g., flutter_accessibility_service) may pass while manual VoiceOver/TalkBack testing reveals focus-order issues, missing semantic roles, or live region announcements that fire too early or not at all. Discovering these late risks delaying the MVP release.

Mitigation & Contingency

Mitigation: Conduct manual VoiceOver and TalkBack testing on physical devices at the end of every sprint, not only at release. Define accessibility acceptance criteria per component and include them in the DoD. Use Semantics widgets explicitly rather than relying on implicit semantics from Flutter's default widgets for all interactive elements.

Contingency: Maintain a prioritized accessibility bug backlog separate from the main backlog. If critical VoiceOver issues are found close to release, create an explicit accessibility hotfix sprint before TestFlight distribution to Blindeforbundet testers.

medium impact medium prob technical

Keyboard height varies significantly between iOS and Android, between device sizes (iPhone SE vs iPad), and with third-party keyboards. The KeyboardAwareLayout may not correctly adjust scroll offset in all combinations, causing input fields to remain hidden behind the keyboard on certain device/keyboard configurations.

Mitigation & Contingency

Mitigation: Test on a matrix of devices including iPhone SE (small viewport), a mid-size Android phone, and a tablet. Implement the layout using MediaQuery.viewInsets.bottom rather than a fixed padding value to correctly respond to any keyboard height. Include edge cases for floating keyboards on iPads.

Contingency: If device-specific issues are found after release, implement a bottom-padding fallback using BottomPadding inset and allow users to manually scroll. Log affected device/OS combinations for targeted fixes.

high impact low prob dependency

If the design token system's colour palette is updated without re-running contrast validation, form field labels, error messages, or placeholder text could fall below the WCAG 2.2 AA 4.5:1 ratio, causing a compliance regression.

Mitigation & Contingency

Mitigation: Integrate a contrast ratio validator (e.g., a CI lint step using the contrast-ratio-validator component) that checks all colour pairs used in the login form on every pull request. Document which token pairs are used for labels, errors, and backgrounds in the login form.

Contingency: If a contrast regression is detected post-merge, hot-patch the affected design token value. Do not ship a TestFlight build with known WCAG AA failures to Blindeforbundet testers.