---
name: flutter-gorouter-routing
description: Implements declarative Flutter navigation with GoRouter, screen-owned route identity, nested routes, auth redirects, and state-preserving shell branches. Use when adding routes, deep links, bottom navigation, route parameters, redirect logic, or navigation tests.
---

# Flutter Routing with GoRouter

## Define route identity on the screen

Every routable screen owns both constants:

```dart
static const String routeName = 'orderDetail';
static const String routeLocation = '/orders/:id';
```

- Reference these constants from the router and navigation calls; do not repeat loose path strings.
- Add a `locationFor(...)` helper when callers need a concrete parameterized location.
- Prefer named navigation with `pathParameters` when it removes manual path assembly.
- Validate every path or query parameter before constructing the destination screen.

## Assemble one declarative tree

1. Configure the Riverpod-provided `GoRouter` in `core/routing/app_router.dart`.
2. Compose routes feature by feature instead of building one unstructured list.
3. Use absolute paths for top-level routes and branch roots.
4. Use relative path segments such as `:id` for nested children.
5. Give every `GoRoute` a stable name for navigation, diagnostics, and screen analytics.

## Choose the navigation operation

- Use `context.go(...)` when changing location should replace the current matched stack.
- Use `context.push(...)` when presenting a detail or temporary flow on top of the current location.
- Use `navigationShell.goBranch(index)` to switch bottom-navigation branches.
- Pass `initialLocation: index == navigationShell.currentIndex` when tapping the active tab should reset that branch.
- Use `pop()` only when returning through an existing imperative stack is the intended behavior.

## Preserve tab state

- Use `StatefulShellRoute.indexedStack` for bottom navigation.
- Give each tab its own `StatefulShellBranch` and navigator key when nested navigation requires it.
- Render the provided `StatefulNavigationShell` inside a dedicated scaffold widget.
- Do not recreate or dispose inactive branches merely because another tab is selected.
- Put detail routes under the branch whose navigation history should own them.

## Redirect safely

1. Read authentication state from Riverpod and refresh router decisions when it changes.
2. Allow splash or loading state to settle before redirecting.
3. Send unauthenticated users to login while preserving an intended destination when required.
4. Send authenticated users away from login or onboarding only when the flow is complete.
5. Return `null` when no redirect is needed and guard against redirect loops.

## Deep-link and analytics rules

- Treat the URL as application state: a deep link must rebuild the same screen stack as in-app navigation.
- Keep native association files and platform intent configuration aligned with the route tree.
- Attach navigation observers to the root and any shell navigators that must emit screen events.
- Keep sensitive values out of query parameters.

## Test checklist

- Resolve every top-level and nested location from a cold start.
- Verify invalid or missing parameters reach a safe not-found or validation state.
- Test authenticated, unauthenticated, loading, and redirect-loop cases.
- Verify each tab preserves its nested stack and active-tab reset behavior.
- Test browser back and system back behavior separately where supported.
