homelab-codex-ws/services/paperless/README.md

113 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Paperless-ngx (serwis, PIHA)
Serwis dokumentów filaru KB #2 (moduł 2, `docs/kb/modules/02-paperless-service.md`):
UI + API + Postgres + Redis. Always-on na PIHA. Ciężki OCR wykonuje osobny worker
na SOLARIA (`services/paperless-worker/`, moduł 3) — tu zostaje tylko wolny
fallback (1 worker × 1 wątek).
**Paperless = archiwum REFERENCJA w hybrydzie kb-02** — jego storage jest źródłem
prawdy dla KB. Backup jest OBOWIĄZKOWY (patrz niżej), nie opcjonalny.
## Stack
| Kontener | Obraz | Rola |
|--------------------|------------------------------------------|-----------------------------|
| `paperless` | `ghcr.io/paperless-ngx/paperless-ngx:2.14` | UI+API+consumer+fallback-OCR (port 8000) |
| `paperless-db` | `postgres:16-alpine` | metadane (alias `db`) |
| `paperless-broker` | `redis:7-alpine` (AOF on) | kolejka zadań OCR (alias `broker`) |
Wszystkie porty bindowane na `LAN_BIND_IP` (192.168.31.5), nigdy 0.0.0.0:
- `8210` → web UI (za npm@PIHA, vhost `paper.kapala.org`, LAN/Tailscale only)
- `5434` → Postgres dla workera@SOLARIA (5433 zajęte przez kb-postgres)
- `6380` → Redis dla workera@SOLARIA (6379 zajęte przez agent-system-redis)
Obraz jest multi-arch (arm64 natywnie na Pi 5). Tag `2.14` MUSI być identyczny
z `services/paperless-worker/docker-compose.yml` — podbijać oba naraz.
## Split OCR: serwis@PIHA + worker@SOLARIA (wynik badania)
Rozproszony worker **nie jest oficjalnie wspierany** przez Paperless-ngx, ale
jest wykonalny i potwierdzony przez maintainerów (GH discussion #3900): drugi
host odpala ten sam obraz z `command: celery --app paperless worker` i musi
widzieć **ten sam Redis, tego samego Postgresa i te same pliki**. Stąd:
- storage dokumentów leży na PIHA (bind mounty `/opt/homelab/data/paperless/*`)
i jest eksportowany przez **NFS po LAN** (nie Tailscale) do SOLARII;
- ścieżki w kontenerze (`/usr/src/paperless/{data,media,consume}`) muszą być
**identyczne** po obu stronach — payloady zadań i DB niosą ścieżki absolutne;
- pliki mają właściciela **numerycznego UID 1000** (`USERMAP_UID/GID=1000`
po obu stronach) — NFS przenosi numeryczne ID, nie nazwy;
- wbudowany worker na PIHA (nie da się go wyłączyć w stockowym obrazie) działa
jako wolny fallback, gdy SOLARIA śpi; zadania czekają w Redis (AOF włączone,
restart brokera nie gubi kolejki).
Szczegóły NFS (export na PIHA, mount na SOLARIA, ryzyko indeksu Whoosh) —
`services/paperless-worker/README.md`.
## OIDC przez Forgejo
Mechanizm: `django-allauth` z providerem `openid_connect`
(`PAPERLESS_APPS=allauth.socialaccount.providers.openid_connect`), konfiguracja
providera w JSON-ie `PAPERLESS_SOCIALACCOUNT_PROVIDERS` (w `.env`, bo zawiera
client secret — patrz `env.example`).
Rejestracja w Forgejo (Settings → Applications, wzorzec jak Vikunja):
- Redirect URI: `https://paper.kapala.org/accounts/oidc/forgejo/login/callback/`
- Confidential client; scope `openid profile email`
`forgejo.kapala.org` jest przypięte przez `extra_hosts` do `192.168.31.5`
(npm na PIHA), żeby OIDC discovery szło po LAN — ta sama lekcja co w Vikunji.
Lokalny login zostaje na czas bootstrapu (konto `PAPERLESS_ADMIN_USER`);
po zweryfikowaniu OIDC rozważyć `PAPERLESS_DISABLE_REGULAR_LOGIN=true`
(TODO DECYZJA OSKARA w compose).
## Storage i backup (WARUNEK BRZEGOWY hybrydy)
Dane na PIHA NVMe:
- `/opt/homelab/data/paperless/media` — **oryginały + zarchiwizowane PDF-y,
niezastępowalne**
- `/opt/homelab/data/paperless/data` — indeks wyszukiwania (Whoosh) +
klasyfikator — odtwarzalne (`document_index reindex`)
- `/opt/homelab/data/paperless/consume` — katalog zrzutu do ingestu
- `paperless_pgdata` (named volume) — metadane (tagi, korespondenci, daty)
- `paperless_redisdata` (named volume) — AOF kolejki zadań
### Propozycja backupu (TODO DECYZJA OSKARA — zatwierdzić przed deployem)
1. **Warstwa 1 — eksport spójny**: nocny cron na PIHA:
`docker exec paperless document_exporter ../export --delete -z`
wbudowane narzędzie; zrzuca oryginały + archiwa + `manifest.json`
(pełne metadane, odtwarzalne przez `document_importer` bez dumpa SQL).
Ląduje w `/opt/homelab/data/paperless/export`.
2. **Warstwa 2 — kopia poza hosta**: rsync/borg eksportu na SOLARIA
(2 TB NVMe, ta sama LAN) — SOLARIA sesyjna, więc pull przy starcie
lub push z retry. Alternatywa/uzupełnienie: offsite (restic → chmura?).
VPS odpada (brak miejsca).
3. **Retencja (propozycja)**: 7 dziennych + 4 tygodniowe + 6 miesięcznych.
4. Dump Postgresa nie jest konieczny do odtworzenia (manifest wystarcza),
ale tani — można dołożyć `pg_dump` do tej samej nocnej pętli.
## RAM na PIHA
Oczekiwany spoczynek: paperless ~400600 Mi (gunicorn + consumer + beat +
1 worker), postgres ~80 Mi, redis ~15 Mi. Limity twarde w
`hosts/piha/runtime/paperless/docker-compose.override.yml`. Warunek: moduł 0
(odchudzenie PIHA) wykonany — po nim ~3.8 Gi available.
## Cutover checklist (przy deployu — NIE teraz)
1. Moduł 0 (piha-slim) domknięty; `free -g` na PIHA potwierdza zapas.
2. Porty wolne na żywym hoście: `ss -tlnp | grep -E '8210|5434|6380'`.
3. `mkdir -p /opt/homelab/data/paperless/{data,media,consume,export}` na PIHA.
4. `.env` z `env.example` (sekrety + rejestracja OAuth2 w Forgejo).
5. DNS `paper.kapala.org` → PIHA (DNS Only) + vhost w npm@PIHA (HTTPS → 192.168.31.5:8210).
6. `docker compose up -d` + `./healthcheck.sh` + testowy login OIDC.
7. Export NFS dla workera (patrz `services/paperless-worker/README.md`) —
dopiero przy module 3.
8. Wpis w `hosts/piha/services.yaml` (dopiero przy deployu — wcześniej
supervisor widziałby drift dla nieistniejącego serwisu).