> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mobile-starter.amisi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Mobile navigation

> Understand the actual Expo Router groups, route constants, access gate, deep links, and unlock restoration.

The mobile app uses Expo Router files under `apps/mobile/app`. `apps/mobile/src/stacks/main.tsx` declares the root stack, while `apps/mobile/app/_layout.tsx` mounts providers, deep-link handling, `AccessGate`, and that stack.

## Route groups

| Group          | Files and behavior                                                                                                                                       |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `(app)`        | Contains `(tabs)` with `index`, `ai-tools`, `activity`, `profile`, and `insights`                                                                        |
| `(public)`     | Contains `welcome`, `sign-in`, `sign-up`, `forgot-password`, `verify-email`, `setup-pin`, and `setup-biometrics`                                         |
| `(onboarding)` | Contains `index` and `steps/welcome`, `steps/permissions`, and `steps/paywall`                                                                           |
| `(modal)`      | Contains `profile`, `change-pin`, `paywall`, `ai-chat`, `notification-center`, and `notification-permission`; the root presents this group as a modal    |
| `(unlock)`     | Contains the PIN and biometric unlock screen at `index`                                                                                                  |
| `(dev)`        | Contains the developer index, screen list, components, icons, and UI showcase routes; its layout redirects to `/` unless `flags.enableDebugMenu` is true |

The tab bar exposes home, AI tools, activity, and profile. The AI tools tab links directly to `/(modal)/ai-chat`. The `insights` file exists but its tab has `href: null`.

## Route constants

Import app route constants from the app-local path:

```ts theme={null}
import { router } from 'expo-router';

import { ROUTES } from '~/constants/routes';

router.replace(ROUTES.HOME);
```

`ROUTES` currently defines public setup/auth routes, unlock, developer routes, onboarding routes, home/AI tools/activity, and modal routes. `STACKS` defines root screen names used by `MainStack`.

<Warning>
  Keep constants synchronized with route files. `ROUTES.GENERATOR` points to
  `/(app)/(tabs)/generator`, but no `generator.tsx` exists.
  `ROUTES.ONBOARDING_PUSH_PERMISSION_PROMPT` points to
  `/(onboarding)/steps/notification-permission`, but the actual prompt is
  `ROUTES.NOTIFICATION_PERMISSION_MODAL` at `/(modal)/notification-permission`.
  The existing `insights` and tab `profile` routes do not have `ROUTES` entries.
</Warning>

## AccessGate order

`AccessGate` reads `useSegments()`, `usePathname()`, auth state, per-user security setup, app-local onboarding state, and security lock state. After auth finishes loading, it evaluates these gates in order:

1. An unauthenticated user may remain on public `welcome`, `sign-in`, `sign-up`, or `forgot-password`, in `(dev)`, or in `(unlock)`. Other routes redirect to `ROUTES.WELCOME`.
2. An authenticated user without verified email redirects to `ROUTES.VERIFY_EMAIL`.
3. A verified user without a PIN redirects to `ROUTES.SETUP_PIN`.
4. A user who has not completed biometric setup redirects to `ROUTES.SETUP_BIOMETRICS`. Skipping biometrics still marks setup complete.
5. An incomplete welcome step redirects to `ROUTES.ONBOARDING_WELCOME`.
6. An incomplete push explanation redirects to `ROUTES.ONBOARDING_PERMISSIONS`.
7. An incomplete system permission prompt redirects to `ROUTES.NOTIFICATION_PERMISSION_MODAL`.
8. Completed users are moved out of onboarding or the permission modal to `ROUTES.HOME`.
9. A lockable, locked session redirects to `ROUTES.UNLOCK`.
10. Unknown authenticated locations redirect to `ROUTES.HOME`; app, modal, dev, onboarding, unlock, and root locations are recognized.

Locking requires `flags.enableAppLock`, authentication, a user ID, completed PIN setup, and a route outside public, onboarding, and unlock groups. Foreground and background delays come from `amisiConfig.security`.

`flags.enableOnboarding` is not consulted by the current gate. The three app-local onboarding completion values always participate.

## Email-verification deep links

`AuthDeepLinkHandler` subscribes to React Native `Linking` URL events and calls `Linking.getInitialURL()` for cold starts. It accepts only URLs whose query has `mode=verifyEmail` and a non-empty `oobCode`.

It then calls `applyActionCode(oobCode)` and `reloadUser()`. A verified session navigates with `router.replace('/')`; otherwise it navigates to `ROUTES.VERIFY_EMAIL`. Parsing and application failures do not navigate.

Firebase email links are configured in `apps/mobile/app/_layout.tsx` from `EXPO_PUBLIC_FIREBASE_EMAIL_CONTINUE_URL` and optional `EXPO_PUBLIC_FIREBASE_AUTH_LINK_DOMAIN`.

## Lock and route restoration

`useAppLockManager` calls `lockUserSession(userId, pathname)` after foreground inactivity or a long-enough background interval. The store persists the pathname as that user's pending unlock route.

`AccessGate` also writes the current pathname before replacing a locked route with `ROUTES.UNLOCK`. The unlock screen calls `unlockUserSession(userId)` after a valid six-digit PIN or successful biometrics. On the next gate pass, `AccessGate` restores `lockState.pendingRoute`, consumes the persisted route, and falls back to `ROUTES.HOME` when no route exists.

The root `GestureHandlerRootView` calls `notifyAppInteraction` on every touch start so active touches reset the foreground inactivity timer.
