# Delta Terminal — Mobile (Expo)

Standalone React Native app (Expo SDK 51) that talks to the same backend as
the web app. Feature parity for the trading terminal, screener, signals,
chart, reports, activity, settings, and admin — with a **drawer +
bottom-tab** navigation model and **JWT + biometric unlock**.

## Setup

```bash
cd mobile
bun install     # or npm install / pnpm install
bunx expo start
```

Point the app at your backend by setting `EXPO_PUBLIC_API_BASE_URL` and
`EXPO_PUBLIC_WS_URL`, or edit `app.json → expo.extra.apiBaseUrl` /
`wsUrl`. Defaults are `http://localhost:4000/api` and `ws://localhost:4000/ws`.

Full REST reference is served by the backend at `/api/docs` (Swagger UI).

## Architecture

- `src/App.tsx` — React Query + Auth providers, gesture root.
- `src/api/client.ts` — REST client + `BackendWs` singleton, SecureStore
  token, `/auth/refresh` for biometric-gated silent refresh.
- `src/auth/AuthProvider.tsx` — session state, biometric gate, sign in /
  register / sign out / unlock, `expo-local-authentication`.
- `src/navigation/RootNavigator.tsx` — auth-stack vs unlock vs
  drawer(bottom-tabs) based on session state.
- `src/hooks/useBackendStream.ts` — subscribes to WS events, seeds via REST,
  re-seeds on reconnect.
- `src/screens/*` — Dashboard, Screener, Signals, Chart, Reports, Activity,
  Settings, Admin.
- `src/components/ui.tsx` — Card / H1 / H2 / Muted / Body / Pill / Row /
  PrimaryButton primitives in the Emerald Prestige palette.
- `src/theme/index.ts` — colors, spacing, radii.

## Navigation shape

```
AuthStack: Login → Register
UnlockScreen (biometric gate, when session cached + biometrics enabled)
AppDrawer:
  ├── Home (Bottom Tabs)
  │     ├── Dashboard
  │     ├── Screener
  │     ├── Signals
  │     ├── Chart
  │     └── Reports
  ├── Activity
  ├── Settings
  └── Admin           (admins only)
```

## Auth flow

1. First launch → Login / Register writes JWT + refresh token into
   `expo-secure-store`.
2. On next launch, if biometric unlock is enabled in Settings, the app
   shows `UnlockScreen` and calls `LocalAuthentication.authenticateAsync`.
3. After success it calls `POST /api/auth/refresh` for a rotated JWT, then
   `GET /api/auth/me` to hydrate the user.
4. `signOut` clears both tokens.

## Real-time

The `BackendWs` client mirrors the web app: exponential backoff with
jitter, 25 s heartbeat, 60 s dead-socket watchdog, and REST re-seed
after every reconnect via `useBackendStream`.
