# Goon

Self-hosted aggregator of adult-content scene metadata. Multi-source ingest (TPDB, StashDB, 30+ tubes) → dedup → on-demand stream resolution (yt-dlp + JWPlayer unpacker) → API + Expo mobile client.

Stack: Python 3.12 (FastAPI + SQLAlchemy + Alembic), Postgres 16, React Native (Expo), Docker Compose.
Git: github.com/goon-foss/goon (remote: `goonfoss`). Public OSS repo. 18+ — see `DISCLAIMER.md`.

---

## Zmiany mobilne (Expo) → publikuj przez OTA, nie zostawiaj w gicie

Klient `mobile/` (React Native + Expo) aktualizuje się przez **self-hosted Expo Updates (OTA)**, nie przez sklep ani rebuild APK. Zmiany JS (ekrany, komponenty, `api.ts`) lecą silent.

**KRYTYCZNE: `git commit` NIE publikuje OTA.** Sam commit (ani push) nie zmienia NIC na telefonie. Po zmianie w `mobile/` trzeba zbudować bundle i opublikować:

```
# z roota repo; konkretne wartości env w .env.local / prywatnej pamięci (NIE hardcoduj IP tutaj)
GOON_VPS_SSH=<root@vps> GOON_VPS_UPDATES_DIR=/root/goon/app/static/expo-updates \
GOON_PUBLIC_UPDATES_URL=https://api.goon-foss.org/expo-updates/asset \
python scripts/publish_update.py --runtime 1.1
```

Skrypt: `expo export` (build) → scp bundla na VPS pod `app/static/expo-updates/<runtime>/<update_id>/` → przełącza `current.json` (endpoint `GET /expo-updates/manifest` serwuje aktywny). Apka pobiera przy następnym launchu.

Reguły:
- **runtime = `1.1`** (== `runtimeVersion` w `app.json`/APK). Bump TYLKO przy native change (wtedy też nowy APK przez PackageInstaller). `RUNTIME_DEFAULT` w skrypcie = 1.1.
- **Apply dwustopniowy**: 1. launch pobiera w tle, 2. launch aplikuje → po publish **restart apki 2×**.
- **Publish odpala AI** (nie człowiek, nie git-hook). Skrypt działa one-shot też na Windows git-bash (fix 2026-06-02: scp source `.`+`cwd=DIST`, `MSYS_NO_PATHCONV`, defensywne odkręcanie zmanglowanej ścieżki).
- **Backend (`app/`) to OSOBNY deploy** — scp `app/`→VPS + `docker compose restart` (worker/api). NIE przez OTA. `./app` i `./scripts` są wolumenami w compose, więc restart wystarcza (bez rebuildu obrazu).

---

## Kanban (auto-aggregation)

Ten workspace ma własny Kanban (custom tracker type `kanban` w `.nimbalyst/trackers/kanban.yaml`) z kolumnami:

**Backlog → Następne → W trakcie → Czeka → Zrobione**

### Reguła auto-agregacji — WAŻNE

Kiedy podczas sesji pojawi się nowy temat / bug / pomysł / blocker, na który **nie ma teraz czasu** lub jest poboczny względem aktualnego zadania — **utwórz tracker item** zamiast tylko wspomnieć o nim w czacie:

```
mcp__nimbalyst-mcp__tracker_create(
  type: "kanban",
  title: "<krótki tytuł>",
  status: "backlog",
  description: "<1-2 zdania kontekstu + ścieżka pliku jeśli dotyczy>"
)
```

Powód: Jan często skupia się na pierwszej rzeczy z planu, a pozostałe znikają. Kanban jest gwarancją, że nic nie wypadnie. Jeśli wspomnisz coś w czacie i nie założysz ticketu — to się zgubi.

Status `next` = "wybrane na najbliższe dni" (3-5 max). `waiting` = zablokowane na zewnętrzne. `done` ustawia użytkownik, nigdy AI.
