homelab-codex-ws/docs/sessions/2026-06-17-kb-foundations.md
oskar bbfbb698f8 docs(kb): etap 1 fundament done + session log 2026-06-17
- kb-00-overview.md: etap 1 oznaczony jako DONE (kb-postgres + koperta +
  packages/kb-mail), następny krok = etap 2 bulk Gmail; dodana sekcja
  konwencji packages/
- CLAUDE.md: sekcja "Shared Python Libraries (packages/)" — konwencja,
  layout, instalacja w Dockerfile
- docs/sessions/2026-06-17-kb-foundations.md: pełny log sesji (architektura
  KB, decyzje, etap 1 zbudowany, poprawki spójności, następny krok)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 20:02:25 +02:00

132 lines
5.5 KiB
Markdown
Raw Permalink 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.

# Sesja 2026-06-17 — KB foundations (etap 1 maili)
## Cel
Zbudowanie fundamentu filaru maili: pgvector spine na SOLARIA, zamrożona koperta, pakiet domeny `kb-mail`, testy. Bez live ingestu, bez bulk Gmaila, bez indexera — sam fundament pod kolejne etapy.
---
## Architektura KB — ustalona w tej sesji (docs)
### 4 warstwy × 4 filary + rdzeń
```
[ 4. Agent interdyscyplinarny ] NL query + analityka (LLM) ← wspólne
[ 3. Join + Enrich ] entity resolution · graf · OwnTracks ← wspólne
[ 2. Preprocess + Index ] → pgvector / → SQL ← per filar
[ 1. Ingest ] Maile Dokumenty Zdjęcia Transakcje ← per filar
```
OwnTracks = **klucz czasoprzestrzenny w warstwie 3**, nie osobny filar (ciągła funkcja czas→miejsce).
### Decyzje zamknięte
- Spine: **Postgres + pgvector** (nie Qdrant) na SOLARIA
- Embed: **bge-m3** (multilingual, długi kontekst, lepszy pod polski)
- Maile: **dwa żywe źródła** — Fastmail (JMAP, primary) + Gmail (IMAP; konto zostaje jako śmieciowe/2FA)
- Bulk historyczny Gmail (jednorazowy) — etap 2
- Reguła: **archiwizuj wszystko, indeksuj selektywnie** (filtr na wejściu do indeksu, nie archiwum)
- Załączniki: **II tura** (MVP = czysty tekst + nagłówki)
- Warstwa 3 startuje jako **cienki graf encji**; federacja przy zapytaniu — później
- Dokumenty: **Nextcloud** (drive, WebDAV) + **Paperless-ngx** (skany/faktury/OCR)
- Koperta: zamrożona addytywna — `id / source / ts(UTC) / geo / raw_ref / entities[]`
### Decyzje otwarte
- **Transakcje (filar #4):** OPEN ISSUE — agregator PSD2 (GoCardless / Tink) dla mBank + Revolut, ale zgoda SCA wygasa co 90 dni → brak pełnego bezobsługowego sync; fallback: CSV/MT940. Do decyzji przy starcie filaru #4.
---
## Etap 1 — ZBUDOWANY
### services/kb-postgres
- Obraz: `pgvector/pgvector:pg16`
- SOLARIA, port **5433** (5432 zarezerwowany na potencjalny lokalny postgres)
- Named volume: `kb_postgres_data`
- Init SQL (`init/001_envelope.sql`): `CREATE EXTENSION vector` + tabela `envelope`
- Per-host override: `hosts/solaria/runtime/kb-postgres/docker-compose.override.yml``mem_limit: 4g`
- `inventory/topology.yaml` + `hosts/solaria/services.yaml` — wpisy dodane
### Zamrożona koperta (001_envelope.sql + Envelope dataclass)
```sql
CREATE TABLE envelope (
id TEXT PRIMARY KEY,
source TEXT NOT NULL, -- fastmail | gmail | ...
ts TIMESTAMPTZ NOT NULL,
geo JSONB, -- null dla maili; warstwa 3 uzupełnia
raw_ref TEXT NOT NULL, -- ścieżka do .eml w archiwum
entities JSONB NOT NULL DEFAULT '[]'
);
```
`Envelope` dataclass waliduje `ts.tzinfo is not None` w `__post_init__`.
### packages/kb-mail — nowa konwencja shared lib
Lokalizacja: `packages/<lib>/` (nie `services/`) — biblioteki reużywalne przez joby.
Instalacja w Dockerfile: `COPY packages/kb-mail/ /packages/kb-mail/ && pip install /packages/kb-mail/`.
| Moduł | Co robi |
|-------|---------|
| `envelope.py` | `@dataclass Envelope`, walidacja tz-aware ts |
| `db.py` | `insert_envelope` (ON CONFLICT DO NOTHING) + `get_envelope` (asyncpg) |
| `archive.py` | `save_eml` — append-only, `asyncio.to_thread` na write, `FileExistsError` na duplikat |
structlog JSON w każdym module (`structlog.get_logger(__name__)`); konfiguracja po stronie konsumenta (biblioteka nie konfiguruje structlog).
### Testy
- 15 unit testów (nie-integration): model, archiwum, sanity SQL — wszystkie zielone bez DB
- 5 integration testów (`@pytest.mark.integration`): round-trip DB, duplikat, geo, entities — wymagają `KB_TEST_DSN`
- `conftest.py`: fixture `db_conn` = asyncpg connection + BEGIN/ROLLBACK na każdy test
### Poprawki spójności (code-review sesji)
1. **README deploy**: pierwotna wersja miała `docker compose --env-file /opt/homelab/config/…` — pomijała override file i miała złą ścieżkę. Naprawiono: README dokumentuje trzy ścieżki (standardowa przez `deploy.sh solaria`, first-time setup `.env` obok compose file, manual z dwoma `-f`), zgodnie z `deploy-node.sh` L6572.
2. **.gitignore**: reguła `*.env` (L3) już łapie `services/kb-postgres/.env` — potwierdzono `git check-ignore`. Nic nie dodano.
---
## Higiena git
- Cała praca w worktree `task/kb-foundations` — master czysty przez cały czas
- 2 commity na branchu po zakończeniu sesji
---
## Commits
```
31c64d5 feat(kb-mail): fundament — pgvector spine, koperta, archiwum, pakiet domeny
<docs-commit> docs(kb): etap 1 fundament done + session log 2026-06-17
```
## Files changed (etap 1)
```
services/kb-postgres/docker-compose.yml
services/kb-postgres/service.yaml
services/kb-postgres/env.example
services/kb-postgres/healthcheck.sh
services/kb-postgres/init/001_envelope.sql
services/kb-postgres/README.md
hosts/solaria/runtime/kb-postgres/docker-compose.override.yml
hosts/solaria/services.yaml
inventory/topology.yaml
packages/kb-mail/pyproject.toml
packages/kb-mail/src/kb_mail/{__init__,envelope,db,archive}.py
packages/kb-mail/tests/{conftest,test_envelope,test_archive,test_db,test_migration}.py
docs/kb/kb-00-overview.md (etap 1 done, konwencja packages/)
CLAUDE.md (sekcja Shared Python Libraries)
docs/sessions/2026-06-17-kb-foundations.md
```
## Następny krok
**Etap 2: jednorazowy bulk importer Gmail** — mbox/Takeout → archiwum.
Wejście: plik `.mbox` lub katalog Maildir z eksportu Google Takeout.
Wyjście: `.eml` w archiwum + wiersze `envelope` w DB.
Jako one-shot job (nie serwis), reużywa `packages/kb-mail`.