critical priority medium complexity infrastructure pending infrastructure specialist Tier 1

Acceptance Criteria

A `NavigationRouteConfig` class exposes a `GoRouter get router` getter (or factory) consumed by `MaterialApp.router`
The router uses `StatefulShellRoute.indexedStack` with exactly five `StatefulShellBranch` instances: Home, Contacts, Add, Work, Notifications
Each branch's root `GoRoute` uses the corresponding constant from `RouteConstants`
Every branch's shell page widget wraps its content in `PopScope(canPop: false, onPopInvoked: _handlePop)` — swipe-back is unconditionally suppressed
`_handlePop` either navigates programmatically to the previous route or is a no-op (no OS default back gesture is allowed through)
All sub-routes are declared as children of their respective branch root `GoRoute`
The router is provided via a Riverpod `Provider<GoRouter>` so downstream widgets can access it without `context` threading
Deep-link URLs resolve correctly — navigating to `/contacts/detail/123` activates the Contacts tab and pushes the detail screen
Switching between tabs preserves the sub-route state of each branch (IndexedStack behavior confirmed)
No implicit `Navigator` pop path bypasses `PopScope` — verified by manual test on iOS swipe gesture and Android back button
WCAG 2.2 AA: navigation between tabs does not move focus unexpectedly; focus is placed on the first interactive element of the new tab

Technical Requirements

frameworks
Flutter
GoRouter (go_router package)
Riverpod
data models
RouteMetadata
RouteConstants
performance requirements
IndexedStack keeps all five tab widgets alive — acceptable memory trade-off for state preservation; document this decision
Router initialization must complete before first frame — use `GoRouter` with `debugLogDiagnostics: false` in production
security requirements
Router must not expose admin-only routes to peer mentor or coordinator roles at the `GoRoute` definition level — use `redirect` guards
Route guards must check auth state synchronously to avoid flash-of-unauthorized-content
ui components
PopScope wrapper widget
StatefulShellRoute shell scaffold (bottom navigation bar integration)
BottomNavigationBar or NavigationBar (5 tabs)

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use `StatefulShellRoute.indexedStack` — not `StatefulShellRoute` with a custom navigator — to avoid state loss on tab switch. Each `StatefulShellBranch` should set `navigatorKey` to a branch-specific `GlobalKey` stored in `NavigationRouteConfig` to enable imperative navigation per branch. For `PopScope`, use `onPopInvokedWithResult` (Flutter 3.22+) to handle the `bool didPop` parameter correctly. The `canPop: false` on the root of each branch is the accessibility requirement from the workshops — users with motor impairments rely on explicit back buttons, not swipe gestures.

Implement a `redirect` callback on sensitive routes to check Riverpod auth state; use `ref.read` inside the redirect since the router exists outside the widget tree. Avoid nesting `GoRouter` instances — one router for the whole app. Register the router as `@riverpod GoRouter router(RouterRef ref)` so it can observe auth changes and trigger redirects.

Testing Requirements

Integration tests using `flutter_test` and `GoRouter`'s test utilities: (1) Confirm all five branches are navigable by name using `router.go(RouteConstants.homePath)` etc. (2) Confirm `PopScope` blocks swipe-back — simulate `Navigator.maybePop` and assert it returns `false`. (3) Confirm tab switching preserves sub-route: push a detail screen on Home tab, switch to Contacts, return to Home — detail screen must still be visible. (4) Confirm deep-link `/work/task/42` activates Work tab and pushes the task detail screen.

(5) Widget test: render the shell and verify five `BottomNavigationBar` items are present. Target: all five branches covered, swipe suppression verified on both platforms.

Component
Navigation Route Configuration
infrastructure medium
Epic Risks (2)
high impact medium prob technical

StatefulShellRoute branch navigator state can interact unexpectedly with GoRouter's imperative navigation (go, push, replace), causing state snapshots to desync from actual route stacks. This could manifest as a user returning to a tab and seeing a different screen than expected, breaking the core motor-fatigue promise.

Mitigation & Contingency

Mitigation: Write integration tests that simulate cross-tab navigation with nested pushes before any UI layer is built. Pin go_router to a tested minor version and review the StatefulShellRoute changelog before upgrading.

Contingency: If branch navigator state consistently desyncs, fall back to a manual stack snapshot strategy using a custom NavigatorObserver that records and replays navigation events independently of StatefulShellRoute internals.

medium impact medium prob technical

Persisted navigation stacks in shared_preferences can become stale or corrupt if route paths are renamed during development, causing app crashes or infinite redirect loops on cold start for users who have an old snapshot.

Mitigation & Contingency

Mitigation: Version the persisted schema with a format key. On app start, validate that all stored route paths exist in the current route config before restoring; silently discard invalid entries rather than crashing.

Contingency: Implement a safe-mode cold start that skips state restoration after a detected crash (via a dirty-launch flag written at startup and cleared on successful first frame), falling back to the default root tab.