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>
This commit is contained in:
parent
1666511475
commit
bbfbb698f8
12
CLAUDE.md
12
CLAUDE.md
|
|
@ -63,6 +63,18 @@ services/<service>/
|
||||||
|
|
||||||
Host-specific runtime config and secrets live at `/opt/homelab/config/<service>/` on the target node (not in Git). Docker Compose overrides are version-controlled at `hosts/<node>/runtime/<service>/docker-compose.override.yml` in this repo and applied during deployment.
|
Host-specific runtime config and secrets live at `/opt/homelab/config/<service>/` on the target node (not in Git). Docker Compose overrides are version-controlled at `hosts/<node>/runtime/<service>/docker-compose.override.yml` in this repo and applied during deployment.
|
||||||
|
|
||||||
|
## Shared Python Libraries (packages/)
|
||||||
|
|
||||||
|
Reusable Python packages that are not deployed services live in `packages/<lib>/`. They have a `pyproject.toml` and `src/` layout but no `docker-compose.yml` or `service.yaml`.
|
||||||
|
|
||||||
|
Services and jobs that depend on them install via Dockerfile:
|
||||||
|
```dockerfile
|
||||||
|
COPY packages/<lib>/ /packages/<lib>/
|
||||||
|
RUN pip install /packages/<lib>/
|
||||||
|
```
|
||||||
|
|
||||||
|
First library: `packages/kb-mail/` — KB envelope model, asyncpg DB helpers, append-only .eml archive helper.
|
||||||
|
|
||||||
## Agent System Architecture
|
## Agent System Architecture
|
||||||
|
|
||||||
The platform uses a multi-agent model with **human-in-the-loop** for destructive actions:
|
The platform uses a multi-agent model with **human-in-the-loop** for destructive actions:
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,24 @@ Hardening homelabu / stabilizacja control-plane — osobny wątek.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Konwencja packages/
|
||||||
|
|
||||||
|
Reużywalne biblioteki Python (nie deploy-osobnych serwisów) żyją w `packages/<lib>/`.
|
||||||
|
Instalacja w Dockerfile serwisu/joba: `pip install /repo/packages/<lib>/`.
|
||||||
|
Biblioteki nie mają `docker-compose.yml` ani `service.yaml` — to nie są serwisy.
|
||||||
|
|
||||||
|
Pierwsza biblioteka: `packages/kb-mail/` — model koperty, helpery DB (asyncpg), helper archiwum.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Następny krok
|
## Następny krok
|
||||||
|
|
||||||
Etap 1 maili: **zamroź kopertę + postaw Postgres+pgvector + szkielet repo + bulk Gmail historyczny.** Szczegóły w `kb-01-email-design.md`.
|
~~Etap 1 maili: zamroź kopertę + postaw Postgres+pgvector + szkielet repo.~~ **ZROBIONE** (2026-06-17).
|
||||||
|
|
||||||
|
- ✅ `services/kb-postgres` — pgvector/pgvector:pg16 na SOLARIA (:5433), `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 2: jednorazowy bulk importer Gmail** (mbox/Takeout → archiwum).
|
||||||
|
Szczegóły kolejności: `kb-01-email-design.md` §8.
|
||||||
|
|
|
||||||
131
docs/sessions/2026-06-17-kb-foundations.md
Normal file
131
docs/sessions/2026-06-17-kb-foundations.md
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
# 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` L65–72.
|
||||||
|
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`.
|
||||||
Loading…
Reference in a new issue