feat(db): schema v2 — contacts, memory_facts_archive, entity_refs, pompeo_note
- New table: contacts (multi-tenant person graph with aliases, details, GIN indexes) - New table: memory_facts_archive (expired facts cleanup destination) - memory_facts: added pompeo_note TEXT and entity_refs JSONB columns - Applied live to Patroni primary (postgres-1, namespace persistence, DB pompeo) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
19
CHANGELOG.md
19
CHANGELOG.md
@@ -4,6 +4,25 @@ Tutte le modifiche significative al progetto ALPHA_PROJECT sono documentate qui.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [2026-03-21] Schema DB v2 — contacts, memory_facts_archive, entity_refs
|
||||||
|
|
||||||
|
### Nuove tabelle
|
||||||
|
|
||||||
|
- **`contacts`**: grafo di persone multi-tenant. Ogni riga modella una relazione `user_id → subject` con `relation`, `city`, `country`, `profession`, `aliases[]`, `born_year`, `details` (narrativa libera per LLM) e `metadata` JSONB. Traversabile ricorsivamente per inferire relazioni di secondo grado (es. Martin → zio Mujsi → figlio Euris → cugino di primo grado da parte di madre). Indici GIN su `subject` (trigram) e `aliases` per similarity search.
|
||||||
|
- **`memory_facts_archive`**: destinazione del cleanup settimanale dei fatti scaduti. Struttura identica a `memory_facts` + `archived_at` + `archive_reason` (`expired` | `superseded` | `merged`). I fatti archiviati vengono poi condensati in un episodio Qdrant settimanale.
|
||||||
|
|
||||||
|
### Colonne aggiunte a `memory_facts`
|
||||||
|
|
||||||
|
- **`pompeo_note TEXT`**: inner monologue dell'LLM al momento dell'insert — il "perché" del fatto (già in uso nel Calendar Agent, ora standardizzato su tutti i source).
|
||||||
|
- **`entity_refs JSONB`**: entità estratte dal fatto strutturato — `{people: [], places: [], products: [], amounts: []}`. Permette query SQL su persone/luoghi senza full-text scan (es. `entity_refs->'people' ? 'euris vruzhaj'`).
|
||||||
|
|
||||||
|
### Applicato a
|
||||||
|
|
||||||
|
- `alpha/db/postgres.sql` aggiornato (schema v2)
|
||||||
|
- Live su Patroni primary (`postgres-1`, namespace `persistence`, DB `pompeo`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [2026-03-21] Actual Budget — Import Estratto Conto via Telegram
|
## [2026-03-21] Actual Budget — Import Estratto Conto via Telegram
|
||||||
|
|
||||||
### Nuovi workflow
|
### Nuovi workflow
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- ALPHA_PROJECT — Database "pompeo" — Schema iniziale
|
-- ALPHA_PROJECT — Database "pompeo" — Schema v2
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- Applicare su: postgresql://martin@postgres.persistence.svc.cluster.local:5432/pompeo
|
-- Applicare su: postgresql://martin@postgres.persistence.svc.cluster.local:5432/pompeo
|
||||||
--
|
--
|
||||||
@@ -64,7 +64,9 @@ CREATE TABLE IF NOT EXISTS memory_facts (
|
|||||||
action_text TEXT,
|
action_text TEXT,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||||
expires_at TIMESTAMP, -- NULL = permanente
|
expires_at TIMESTAMP, -- NULL = permanente
|
||||||
qdrant_id UUID -- FK logico → collection "episodes"
|
qdrant_id UUID, -- FK logico → collection "episodes"
|
||||||
|
pompeo_note TEXT, -- inner monologue dell'LLM al momento dell'insert
|
||||||
|
entity_refs JSONB -- entità estratte: {people, places, products, amounts}
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_memory_facts_user_source_cat
|
CREATE INDEX IF NOT EXISTS idx_memory_facts_user_source_cat
|
||||||
@@ -207,8 +209,74 @@ INSERT INTO ha_sensor_config (pattern, user_id, group_name, description) VALUES
|
|||||||
ON CONFLICT DO NOTHING;
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
|
||||||
|
-- =============================================================================
|
||||||
|
-- 7. CONTACTS
|
||||||
|
-- Grafo di persone multi-tenant. Ogni riga = una relazione (user_id → subject).
|
||||||
|
-- Traversabile dall'LLM: user_id=martin → cugino → euris, poi user_id=euris → padre → mujsi
|
||||||
|
-- → l'LLM inferisce che Mujsi è lo zio di Martin.
|
||||||
|
-- Il campo 'details' è narrativa libera ottimizzata per consumo LLM.
|
||||||
|
-- =============================================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS contacts (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
user_id TEXT NOT NULL, -- chi "possiede" questa relazione
|
||||||
|
subject TEXT NOT NULL, -- nome normalizzato del contatto
|
||||||
|
relation TEXT NOT NULL, -- 'cugino' | 'zio' | 'madre' | 'moglie' | 'amico' | ...
|
||||||
|
city TEXT,
|
||||||
|
country TEXT,
|
||||||
|
profession TEXT,
|
||||||
|
aliases TEXT[], -- soprannomi/varianti nome ['Eri', 'Mucho']
|
||||||
|
born_year INT,
|
||||||
|
details TEXT, -- narrativa libera per l'LLM (storia, carattere, note)
|
||||||
|
metadata JSONB, -- extra strutturato: {email, phone, children, spouse, ...}
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
UNIQUE (user_id, subject)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_contacts_user
|
||||||
|
ON contacts(user_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_contacts_subject_trgm
|
||||||
|
ON contacts USING gin(subject gin_trgm_ops); -- similarity search su nome
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_contacts_aliases
|
||||||
|
ON contacts USING gin(aliases); -- ricerca per alias/soprannome
|
||||||
|
|
||||||
|
|
||||||
|
-- =============================================================================
|
||||||
|
-- 8. MEMORY_FACTS_ARCHIVE
|
||||||
|
-- Fatti scaduti spostati qui dal cleanup settimanale.
|
||||||
|
-- Struttura identica a memory_facts + campi archivio.
|
||||||
|
-- Un punto Qdrant "episodio settimanale" riassume il batch archiviato.
|
||||||
|
-- =============================================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS memory_facts_archive (
|
||||||
|
id UUID NOT NULL,
|
||||||
|
user_id TEXT NOT NULL DEFAULT 'martin',
|
||||||
|
source TEXT NOT NULL,
|
||||||
|
source_ref TEXT,
|
||||||
|
category TEXT,
|
||||||
|
subject TEXT,
|
||||||
|
detail JSONB,
|
||||||
|
action_required BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
action_text TEXT,
|
||||||
|
pompeo_note TEXT,
|
||||||
|
entity_refs JSONB,
|
||||||
|
qdrant_id UUID,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL,
|
||||||
|
expires_at TIMESTAMPTZ,
|
||||||
|
archived_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
archive_reason TEXT NOT NULL DEFAULT 'expired' -- 'expired' | 'superseded' | 'merged'
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_mf_archive_user_date
|
||||||
|
ON memory_facts_archive(user_id, archived_at DESC);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_mf_archive_source
|
||||||
|
ON memory_facts_archive(user_id, source, category);
|
||||||
|
|
||||||
|
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- Fine script
|
-- Fine script
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
\echo '✅ Schema pompeo applicato correttamente.'
|
\echo '✅ Schema pompeo applicato correttamente.'
|
||||||
\echo ' Tabelle: user_profile, memory_facts, finance_documents, behavioral_context, agent_messages, ha_sensor_config'
|
\echo ' Tabelle: user_profile, memory_facts, memory_facts_archive, contacts, finance_documents, behavioral_context, agent_messages, ha_sensor_config'
|
||||||
|
|||||||
Reference in New Issue
Block a user