homelab-codex-ws/docs/sessions/2026-06-17-kb-foundations.md
oskar 510fe0b600 feat(kb): frontmatter OKF dla 39 session logow
Session logi zostaja w docs/sessions/ (decyzja z etapu 1). Dodany wylacznie
blok frontmattera: type: session-log, visibility: private, status: active,
updated = data ostatniego commita pliku.

Tresc nietknieta — kazdy plik to +9/-0 linii.

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

141 lines
5.6 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: session-log
visibility: private
status: active
updated: 2026-06-17
links: []
---
# 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`.