# Mobile app

Expo Router uses the shared domain API with native navigation and scoped local state.

## Application structure [#application-structure]

`apps/mobile` uses Expo SDK 58, React Native and file-based Expo Router routes. Auth routes sit outside the protected tabs. Home, Todos and Profile demonstrate the shared API; Profile contains Sessions, passkeys, Organizations, notifications and optional subscriptions.

The native design layer centralizes colors, type, spacing and reusable controls. Hooks own mutations, auth transitions, dialogs and toasts. Keep route components focused on composition rather than duplicating transport policy.

`src/` follows the backend's feature shape ([ADR-0013](/docs/adr/0013-mobile-features-mirror-the-backend-shape)): routes in `src/app` only return a screen, each feature lives in one flat `src/features/<feature>/` folder (`<feature>.screen.tsx`, `<feature>.hooks.ts`, components and models), and cross-cutting code sits in `src/platform/` (rpc, auth session, i18n, feedback, theme). Screens and components read data only through hooks. `scripts/mobile-feature-boundaries.test.mjs` checks the direction rules in `pnpm test`.

## Backend and scope [#backend-and-scope]

`EXPO_PUBLIC_SERVER_URL` selects the backend, with localhost:3005 as the local fallback. A physical device needs a reachable laptop LAN address. Better Auth's Expo client owns credentials; request scope captures User, Session and Organization. Organization transitions cancel stale waits and hide stale query results, including an A-to-B-to-A transition.

RPC calls made in the same tick share one batch request (oRPC `BatchLinkPlugin`, answered by the Worker's `BatchHandlerPlugin`), so one session read and one database pool serve a screen's initial queries. A batch only joins calls captured under the same identity, revision and cookie; a scope change aborts it, and an `UNAUTHORIZED` sub-response inside the batch envelope signs the captured session out exactly like a whole-request 401.

Offline reading is scoped to the observed identity and Organization through `src/platform/offline/` (`openPrivateSnapshot` per feature, one cache folder purged on sign-out). Cached data is not authorization, and a late response from an old identity must not clear or overwrite the new one.

## Native capabilities [#native-capabilities]

RevenueCat requires its SDK in the native build and both billing gates. Push boot registers the platform adapter where available, with enrollment, foreground presentation and tap authorization kept separate. Widgets are opt-in through configuration and a feature flag. Biometric app lock protects local presentation, not server permission.

## Extend and verify [#extend-and-verify]

Use the shared API contracts, then expose behavior through a mobile hook and the existing design components. Test on a development build when adding native modules. TypeScript and Hermes export do not prove device permission dialogs, purchases, background push or store signing.

The Expo SDK compatibility matrix owns native versions. Do not bump native modules merely because npm has a newer release; rebuild the dev client when the native dependency set changes. See [libraries and upgrade policy](/docs/libraries).

## Key files [#key-files]

- [`apps/mobile/src/app/_layout.tsx`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/mobile/src/app/_layout.tsx)
- [`apps/mobile/src/features/todo/todo.screen.tsx`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/mobile/src/features/todo/todo.screen.tsx)
- [`apps/mobile/src/platform/rpc/orpc.ts`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/mobile/src/platform/rpc/orpc.ts)
- [`apps/mobile/src/platform/auth/organization-transition.ts`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/mobile/src/platform/auth/organization-transition.ts)
- [`apps/mobile/src/platform/offline/scoped-snapshot.ts`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/mobile/src/platform/offline/scoped-snapshot.ts)
- [`apps/mobile/src/design/tokens.ts`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/mobile/src/design/tokens.ts)
- [`apps/mobile/README.md`](https://github.com/CarlosZiegler/wundklare/blob/main/apps/mobile/README.md)

