homelab-codex-ws/kb/services/paperless.md
oskar 05eaf31613 feat(kb): SPLIT paperless -> service + decision + runbook
kb/services/paperless.md (Stack, OIDC, Storage i backup, RAM na PIHA)
kb/decisions/paperless-split-ocr.md (split OCR serwis@PIHA + worker@SOLARIA)
kb/runbooks/paperless-cutover.md (cutover checklist)

Tresc sekcji nietknieta; kontrola multizbioru linii == oryginal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:58:46 +02:00

99 lines
4.5 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.

---
okf: "0.1"
type: service
visibility: private
status: active
updated: 2026-07-09
links:
- ../decisions/paperless-split-ocr.md
- ../runbooks/paperless-cutover.md
---
# 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); auth scram
- `6380` → Redis dla workera@SOLARIA (6379 zajęte przez agent-system-redis);
`requirepass` ustawione — `PAPERLESS_REDIS_PASSWORD` w `.env` po obu stronach
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.
## 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 ustawić `PAPERLESS_DISABLE_REGULAR_LOGIN=true` +
`PAPERLESS_REDIRECT_LOGIN_TO_SSO=true` (decyzja podjęta — zrobić PRZY DEPLOYU,
po potwierdzeniu logowania OIDC; TODO 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ń
### Backup (zatwierdzone — cel: SOLARIA, LAN; offsite później)
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. Wystarcza na start; VPS odpada (brak miejsca).
3. **Retencja (zatwierdzona)**: 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.
5. **Future-note (poza zakresem tego etapu)**: offsite backup (np. restic →
chmura) poza SOLARIA-LAN, gdy pojawi się potrzeba/budżet.
Ten etap to tylko config + dokumentacja decyzji — cron/skrypt deployowy
(cron entry na PIHA, rsync/borg do SOLARII) powstaje przy deployu modułu 2,
nie tutaj.
## 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.