# goon mobile (Expo / React Native)

Mobile client do self-hosted goon backendu. iOS/Android jeden codebase.

## Setup

```bash
cd mobile
npm install
npx expo start
```

Następnie:
- **Expo Go** (iOS/Android): zeskanuj QR z terminala
- **Android emulator**: `npm run android`
- **iOS simulator**: `npm run ios` (tylko macOS)
- **Web preview**: `npm run web`

## Konfiguracja

Po pierwszym uruchomieniu zobaczysz ekran logowania:

- **Backend URL** — adres twojego goon backendu, np.:
  - `http://192.168.1.10:8000` (LAN)
  - `https://goon.tvojadomena.dev` (przez Cloudflare Tunnel/Caddy)
  - `http://100.x.x.x:8000` (przez Tailscale)
- **API Key** — klucz wygenerowany dla backendu, ustawiony w `.env`:
  ```
  API_KEYS=<klucz>
  ```
  Generowanie:
  ```bash
  python -c "import secrets; print(secrets.token_urlsafe(32))"
  ```

Klucz jest trzymany w `expo-secure-store` (Keychain na iOS, Keystore na Androidzie).

## Ekrany

- **Login** — backend URL + API key, weryfikacja przez `/healthz` + `/scenes`
- **Scenes** — lista scen z search; pull-to-refresh
- **Scene detail** — performerzy, tagi, źródła, opis
- **Merge queue** — pending merge candidates, sortowane po score (desc)
- **Merge detail** — side-by-side dwóch scen + reasons + akcje:
  - **Merge → keep LEFT** (default — left to wcześniejsza/kanoniczna)
  - **Merge → keep RIGHT** (gdy nowsza wersja ma lepsze metadane)
  - **Reject (keep both)** — to nie jest duplikat, zostawiamy oddzielnie

## Stack

- Expo SDK 52 + React Native 0.76 (new architecture)
- TypeScript strict
- React Navigation 7 (native stack)
- TanStack Query 5 (cache, optimistic invalidation)
- expo-secure-store (credentials)

## Build .apk (sideload na Androida)

```bash
npx eas build --profile preview --platform android
```

Wymaga konta Expo. Bez niego można użyć `expo prebuild` + `gradlew assembleRelease`.

## Dlaczego nie PWA

Wybrany RN+Expo zamiast PWA bo:
- swipe gestures pasują do triage merge queue
- secure-store jest natywny (Keychain/Keystore) zamiast localStorage
- pull-to-refresh i FlatList virtualization out-of-the-box
- Jeden .apk można rozdać testerom bez App Store
