From 214a6c38778fd7094ae4950e103ab5df2161608c Mon Sep 17 00:00:00 2001 From: oskar Date: Wed, 17 Jun 2026 20:16:32 +0200 Subject: [PATCH] =?UTF-8?q?docs(kb):=20foundacja=20=E2=80=94=20overview=20?= =?UTF-8?q?+=20projekt=20maili=20(2=20=C5=BCywe=20=C5=BAr=C3=B3d=C5=82a)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/kb/kb-00-overview.md | 108 ++++++++++++++++++++++++++++++++++ docs/kb/kb-01-email-design.md | 98 ++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 docs/kb/kb-00-overview.md create mode 100644 docs/kb/kb-01-email-design.md diff --git a/docs/kb/kb-00-overview.md b/docs/kb/kb-00-overview.md new file mode 100644 index 0000000..e99fb0a --- /dev/null +++ b/docs/kb/kb-00-overview.md @@ -0,0 +1,108 @@ +# 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: faza *docs*. Implementacja jeszcze nie ruszyła. + +--- + +## 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. +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. + +--- + +## Decyzje — zamknięte vs otwarte + +**Zamknięte:** +- Spine: Postgres + pgvector (nie Qdrant). +- Embed: **bge-m3** (multilingual, długi kontekst — pod polski lepszy niż multilingual-e5). +- Załączniki: indeksowane w **II turze** (MVP najpierw czysty tekst). +- Warstwa 3 startuje jako **cienki graf encji**; federacja przy zapytaniu dochodzi później (docelowo hybryda). +- Dokumenty: Nextcloud + Paperless-ngx. + +**Otwarte:** +- **Transakcje:** agregator vs CSV, pokrycie mBanku, Revolut, koszt (filar #4). +- **Maile §design:** sizing archiwum / node (ile waży Gmail), unifikacja adaptera (jeden IMAP dla obu vs JMAP+IMAP osobno). + +--- + +## Tor równoległy (nie tutaj) + +Hardening homelabu / stabilizacja control-plane — osobny wątek. + +--- + +## Następny krok + +Etap 1 maili: **zamroź kopertę + postaw Postgres+pgvector + szkielet repo + bulk Gmail historyczny.** Szczegóły w `kb-01-email-design.md`. diff --git a/docs/kb/kb-01-email-design.md b/docs/kb/kb-01-email-design.md new file mode 100644 index 0000000..b3a1d1b --- /dev/null +++ b/docs/kb/kb-01-email-design.md @@ -0,0 +1,98 @@ +# Filar maili — projekt (homelab-codex · KB · projekt #1) + +> Pierwszy filar. Wzorzec referencyjny dla pozostałych (archiwum, embeddingi na SOLARIA, szkielet agenta, deploy). +> Zasady przekrojowe: patrz `kb-00-overview.md`. + +--- + +## 1. Rdzeń: archiwum, nie RAG + +Realna potrzeba to najpierw **archiwum**, nie „RAG nad mailami". Dwie warstwy, fundamentalnie różne: + +- **Archiwum** — surowe, niezmienne, kompletne `.eml` / Maildir, append-only. To, co chcesz mieć u siebie *na zawsze*, niezależnie od jakiegokolwiek AI. Asset. +- **Indeks** — pochodny, odtwarzalny, wyrzucalny. Parse → chunk → embed → pgvector. Re-budowalny z archiwum przy lepszym modelu. + +--- + +## 2. Dwa żywe źródła (zmiana względem pierwotnego planu) + +Gmail **nie jest porzucany** — zostaje jako konto śmieciowe / loginy / 2FA. Stąd maile mają dwa żywe wejścia: + +- **Fastmail** — `source: fastmail`, adapter **JMAP** (read-only token). Primary: tu ląduje sensowna poczta na przyszłość. +- **Gmail** — `source: gmail`, adapter **IMAP** (protokół, nie Gmail API → przenośność). Ciągły sync żywej skrzynki. + +Plus jednorazowy **bulk historyczny Gmaila** (eksport „All Mail" / Takeout → surowy dump do archiwum). Operacja odwracalna i niezależna od reszty pipeline'u — robimy pierwsza. Urgency spadła (konto żyje), ale historia warta zassania od razu. + +--- + +## 3. Koperta (kontrakt zamrożony) + +``` +id — stabilny identyfikator wiadomości +source — fastmail | gmail +ts — UTC (data wiadomości) +geo — null dla maili (uzupełniane cross-source w warstwie 3) +raw_ref — wskaźnik do .eml w archiwum +entities[] — otwarte, wypełniane przy ingeście/enrich +``` + +Addytywna. Nic poza tym nie usztywniamy. + +--- + +## 4. Filtr archiwum → indeks + +**Archiwizuj wszystko. Indeksuj selektywnie.** +Gmail śmieciowy (login/2FA/notyfikacje/newslettery) to szum — wpuszczony do wektorów zaśmieca wyszukiwanie i pali GPU na SOLARII. Filtr na wejściu do indeksu: + +- whitelist/blacklist nadawców i nagłówków (`List-Unsubscribe`, `Auto-Submitted`, typowe domeny powiadomień), +- progi (np. odrzuć czysto automatyczne), +- surowiec zawsze leży w archiwum — filtr nie kasuje, tylko decyduje co trafia do embeddingów. + +Filtr jest częścią indeksu (odtwarzalny), nie archiwum. + +--- + +## 5. Indexer + +`parse (.eml) → chunk → embed (bge-m3 na SOLARIA/ollama) → pgvector` +Retrieval hybrydowy: wektor + filtry metadanych (nadawca, zakres dat, etykieta, source). +Załączniki: **II tura** (MVP = czysty tekst + nagłówki). + +--- + +## 6. Agent maili (dedykowany, cienki) + +- Hybrydowy retrieval: wektor + filtry metadanych. +- Wystawia tool/API, które **agent interdyscyplinarny (warstwa 4)** woła — wzorzec federacji. +- Reużywa szkieletu agenta z control-plane (to samo DNA). + +--- + +## 7. Deploy + +- Wszystko w `homelab-codex`, przez Git na SATURN, konwencja override `hosts//runtime//`. +- Usługi: `jmap-poller` (Fastmail), `imap-poller` (Gmail), `indexer`, embed (ollama na SOLARIA), `postgres+pgvector`, `mail-agent`; bulk importer jako one-shot job. +- Deploy skryptem czytającym `inventory/topology.yaml`. + +--- + +## 8. Kolejność budowy (w obrębie projektu) + +1. Zamroź kopertę + postaw Postgres+pgvector. +2. **Bulk Gmail historyczny → archiwum** *(pierwsze, niezależne)*. +3. Fastmail JMAP live ingest → archiwum. +4. Gmail IMAP live sync → archiwum. +5. Filtr archiwum→indeks. +6. Indexer (parse → chunk → embed bge-m3) → pgvector. +7. Cienki agent maili + tool dla warstwy 4. + +--- + +## 9. Decyzje otwarte (do przyklepania przed/w trakcie startu) + +- **Sizing Gmaila** — ile realnie waży „All Mail"? (przesądza node/dysk archiwum). +- **Unifikacja adaptera** — jeden wspólny IMAP dla Fastmail + Gmail (mniej kodu) vs JMAP dla Fastmail + IMAP dla Gmail (JMAP bogatszy)? +- **Reguły filtra** — startowa lista blacklist domen/nagłówków. +- Vector store: pgvector **przyklepane** (spine). +- Embed model: bge-m3 **przyklepane**.