--- okf: "0.1" type: subsystem visibility: private status: active updated: 2026-06-26 links: - ../decisions/kb-log-decyzji.md --- # Baza wiedzy — przegląd i log decyzji (homelab-codex · KB) > Master-dokument inicjatywy. Stoi ponad dokumentami per-projekt (`kb-01-email-design.md`, …). > Cel: każda kolejna sesja / Claude Code startuje z pełnym kontekstem ustaleń. > Status: implementacja ruszyła. Etap 1 (fundament) done; spine Postgres+pgvector stoi na **PIHA** (always-on); bulk importer Gmaila następny. --- ## Czym to jest Nie sama „baza wiedzy" — **de-Google'izacja życia + warstwa wiedzy na wierzchu.** Każde źródło ma dwie twarze: - **migracja off-cloud** — gdzie dane fizycznie lądują u Ciebie, - **archiwum + ingest** — warstwa wiedzy. --- ## Architektura: 4 warstwy × 4 filary + rdzeń Dwa spojrzenia, ta sama rzecz: - **Pionowo — 4 filary źródeł**, każdy = `ingest + index` (per-filar, wymienny): maile · dokumenty · zdjęcia · transakcje. - **Poziomo — 4 warstwy** przepływu: 1. **Ingest** — per filar (adaptery przeciw protokołom). 2. **Preprocess + Index** — per filar (parse/chunk/embed → pgvector; transakcje → SQL). 3. **Join + Enrich** — **wspólny rdzeń**: entity resolution, graf encji, klucz czasoprzestrzenny. 4. **Advanced analytics + NL query** — **wspólny**: agent interdyscyplinarny, zapytania w języku naturalnym, analityka LLM. Dwa dolne tiery są per-filar i neutralne. Dwa górne są wspólne dla wszystkich źródeł. **OwnTracks = nie piąty filar, lecz klucz czasoprzestrzenny w warstwie 3** (ciągła funkcja czas→miejsce, bez własnego ingestu/agenta). ``` [ 4. Agent interdyscyplinarny ] NL query + analityka (LLM) ↑ (wspólne) [ 3. Join + Enrich ] entity resolution · graf · OwnTracks (czas+miejsce) ↑ ↑ ↑ ↑ (wspólne) [ 2. Preprocess + Index ] → pgvector / → SQL ↑ ↑ ↑ ↑ (per filar) [ 1. Ingest ] Maile Dokumenty Zdjęcia Transakcje ``` --- ## Zasady przekrojowe (obowiązują każdy projekt) 1. **Archiwum ≠ indeks.** Archiwum surowe/niezmienne (asset, wieczne); indeks pochodny i odtwarzalny (wyrzucalny). Re-indeks z archiwum przy lepszym modelu. 2. **Koperta = jedyny kontrakt zamrożony z góry.** Addytywna. Zamrożone: `id · source · ts(UTC) · geo · raw_ref` + otwarte pole `entities[]`. Cała semantyka (typy encji, resolution, graf) **płynie** — rośnie z danych. 3. **Czas + miejsce jako byty pierwszej klasy od dnia zero.** Uniwersalny klucz złączeń między źródłami, karmiony OwnTracks. Nie da się retrofitować bez re-ingestu — stąd w kopercie od startu. 4. **Local-first / privacy.** Korpus (bank + prywatne zdjęcia + maile) → wszystko lokalnie. Embeddingi i modele na SOLARIA (GPU + ollama). Zero chmury dla danych wrażliwych. 5. **Protokół, nie provider.** Ingest pisany przeciw standardom (JMAP, IMAP, WebDAV), nie przeciw firmie → przenośność. 6. **Jeden spine: Postgres + pgvector.** Koperta + wektory (+ później encje + punkty OwnTracks) w jednym store. Mniej ruchomych części. Spine stoi na **PIHA** (Raspberry Pi 5, always-on) — zapytania KB muszą działać 24/7, a SOLARIA bywa offline. SOLARIA zostaje do GPU/embeddingów (bge-m3) i indexera. 7. **Warstwa 4 nie jest waterfallem.** Kontrakt encji (warstwa 3) definiujemy wcześnie — przy 2 źródłach; po drugim źródle stawiamy *cienką* wersję warstwy 4, by udowodnić cross-source linking; dopiero potem dokładamy resztę. --- ## Kolejność projektów (z uzasadnieniem) 1. **Maile** — urgency historyczna (Gmail), czysty text RAG (najprostszy), stawia wzorce reużywalne przez resztę (archiwum, embeddingi na SOLARIA, szkielet agenta, deploy). Wzorzec referencyjny. 2. **Dokumenty** — reużywają ~80% maili (text RAG + OCR), niosą własną migrację Drive → self-host. 3. **Zdjęcia** — silnie zde-ryzykowane: Immich już robi multimodal. Projekt = cienki agent nad API Immicha. Może iść w parze z dokumentami. 4. **Transakcje** — inny paradygmat (strukturalny/analityka, *nie* RAG); najmniej danych, najtrudniejszy acquisition. Na koniec. 5. **Interdyscyplinarny** — capstone; ale jego *szkielet* (schema encji) powstaje już przy 1–2. --- ## Stan per źródło - **Maile** — **dwa żywe źródła:** Fastmail (JMAP, primary) + Gmail (IMAP, bo konto **zostaje** jako śmieciowe/loginy/2FA). Plus jednorazowy bulk historyczny Gmaila. Reguła: **archiwizuj wszystko, indeksuj selektywnie** (filtr odrzuca login/2FA/notyfikacje z wektorów). Design: `kb-01-email-design.md`. **Następny do realizacji.** - **Dokumenty** — **zdecydowane:** Nextcloud (zamiennik Drive, dowolne pliki + sync) **i** Paperless-ngx (podzbiór: skany/faktury/umowy z OCR). Dwa deploye; w ingeście jeden adapter na każdy (Nextcloud WebDAV + Paperless API). - **Zdjęcia** — **Immich już działa** (storage + sync z telefonu + CLIP + twarze + EXIF). Projekt = cienki agent nad API Immicha + job: twarze→osoby, EXIF→miejsca do warstwy encji. - **Transakcje** — **OPEN ISSUE.** Banki: gł. mBank + Revolut (+ reszta PL). Cel: maks automatyzacja. Kandydat: **agregator PSD2** (GoCardless Bank Account Data / Tink) — jedno wejście zamiast N adapterów. Ograniczenie regulacyjne: **zgoda PSD2 wygasa co 90 dni (SCA)** — pełnego bezobsługowego sync nie da się zrobić legalnie. Fallback zero-API: import CSV/MT940. Pokrycie mBanku, koszt agregatora, Revolut → do weryfikacji przy starcie filaru #4. - **OwnTracks** — **działa**; feed do middleware jako warstwa spatio-temporalna (warstwa 3). --- ## Middleware — co zamrożone, co płynne - **Zamrożone (cienkie, addytywne):** koperta (`id/source/ts/geo/raw_ref`) + mechanizm `entities[]`. - **Płynne (rośnie z danych):** typy encji, entity resolution, graf tożsamości, linki cross-source. - Powód: koperta jest retrofit-hostile ale data-independent (można ustalić „na ślepo"); semantyka odwrotnie — wymaga prawdziwych danych, więc jej nie usztywniamy. --- ## Tor równoległy (nie tutaj) Hardening homelabu / stabilizacja control-plane — osobny wątek. --- ## Konwencje katalogów Python | Katalog | Co tu trafia | |---------|-------------| | `packages//` | Reużywalne biblioteki (nie deployowane samodzielnie). Instalacja: `pip install /repo/packages//`. Nie mają `docker-compose.yml` ani `service.yaml`. | | `services//` | Długo żyjące serwisy Docker z `docker-compose.yml` + `service.yaml`. | | `jobs//` | Jednorazowe i periodyczne joby CLI — bez Dockera, odpalane bezpośrednio na węźle (`pip install -e`). | Pierwsza biblioteka: `packages/kb-mail/` — model koperty, helpery DB (asyncpg), helper archiwum. Pierwszy job: `jobs/gmail-bulk-import/` — jednorazowy bulk importer Gmail Takeout. --- ## Stan etapów ~~Etap 1 maili: zamroź kopertę + postaw Postgres+pgvector + szkielet repo.~~ **ZROBIONE** (2026-06-17). - ✅ `services/kb-postgres` — pgvector/pgvector:pg16 na **PIHA** (:5433, always-on), `init/001_envelope.sql` - ✅ Zamrożona koperta — tabela `envelope` + `@dataclass Envelope` (tz-aware) - ✅ `packages/kb-mail` — `envelope` / `db` (asyncpg) / `archive` (append-only .eml) - ✅ 15 testów unit + 5 integration (mark `integration`, wymaga `KB_TEST_DSN`) **Etap 2a: relokacja spine SOLARIA→PIHA + deploy** — ZROBIONE (2026-06-22). - ✅ override SOLARIA usunięty; `hosts/piha/runtime/kb-postgres/docker-compose.override.yml` (mem_limit 1g, tuning pod małą maszynę), obraz `pgvector/pgvector:pg16` arm64 - ✅ PIHA przygotowany: 4GB swap + `cgroup_enable=memory` (mem_limit działa), volume `kb_postgres_data` na NVMe - ✅ deploy na PIHA: kontener healthy, schemat `envelope` + extension `vector` zweryfikowane - ⏳ zostaje: transfer archiwum/.eml na PIHA NVMe (docelowo), poprawka `KB_TEST_DSN` (solaria→piha) w testach ~~Etap 2b: jednorazowy bulk importer Gmail (mbox/Takeout → archiwum).~~ **URUCHOMIONY** (2026-06-25). - ✅ `jobs/gmail-bulk-import/` — CLI importer bez Dockera (pip install -e na PIHA) - ✅ entities[]: manifest załączników (filename, content_type, size, sha256) od dnia zero - ✅ batch inserty, idempotentny, --limit, epoch_fallback, statystyki załączników - ✅ 24 testy jednostkowe, wszystkie zielone - ✅ Pełny import uruchomiony na PIHA (~29 min): **225 030 unikalnych kopert**, **27 GB archiwum .eml**, manifest **70 193 załączników** **Backlog / następne kroki**: - Faza 2 załączników: ekstrakcja/OCR (PDF/skany → Paperless lub dedykowany job) - Odzysk 2559 dat epoch-fallback z nagłówków `Received:`/`X-GM-RECEIVED` - Etap 3: Fastmail JMAP live ingest → `jobs/fastmail-poller/` - Etap 4: Gmail IMAP live sync → `jobs/gmail-imap-poller/`