-- Knowledgebase schema -- PostgreSQL, bez pgvector (embeddingy jako double precision[]) -- pg_trgm pro fuzzy matching (volitelné) CREATE EXTENSION IF NOT EXISTS vector; CREATE EXTENSION IF NOT EXISTS pg_trgm; -- ─── Conversation sessions ──────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS kb_sessions ( id VARCHAR(255) PRIMARY KEY, title TEXT, summary TEXT, project VARCHAR(255), tags TEXT[] DEFAULT '{}', msg_count INT DEFAULT 0, started_at TIMESTAMPTZ DEFAULT NOW(), ended_at TIMESTAMPTZ, meta JSONB DEFAULT '{}' ); CREATE INDEX IF NOT EXISTS kb_sessions_project_idx ON kb_sessions(project); CREATE INDEX IF NOT EXISTS kb_sessions_started_idx ON kb_sessions(started_at DESC); CREATE INDEX IF NOT EXISTS kb_sessions_tags_idx ON kb_sessions USING GIN(tags); -- ─── Individual messages within a session ───────────────────────────────────── CREATE TABLE IF NOT EXISTS kb_messages ( id BIGSERIAL PRIMARY KEY, session_id VARCHAR(255) REFERENCES kb_sessions(id) ON DELETE CASCADE, role VARCHAR(20) NOT NULL, -- 'user' | 'assistant' | 'system' content TEXT NOT NULL, seq INT NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS kb_messages_session_idx ON kb_messages(session_id, seq); -- ─── Memories (facts, decisions, summaries, document extracts, …) ───────────── CREATE TABLE IF NOT EXISTS kb_memories ( id BIGSERIAL PRIMARY KEY, -- classification mem_type VARCHAR(50) NOT NULL DEFAULT 'fact', -- fact | decision | preference | summary | document | email | project | person | other title TEXT, content TEXT NOT NULL, summary TEXT, -- linking session_id VARCHAR(255), -- optional: came from this conversation source TEXT, -- file path, email id, URL, … project VARCHAR(255), -- search tags TEXT[] DEFAULT '{}', importance FLOAT DEFAULT 0.5, -- 0..1 embedding vector(512), -- Voyage AI voyage-3-lite (512-dim) fts TSVECTOR, -- lifecycle created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), expires_at TIMESTAMPTZ, -- NULL = never deleted BOOLEAN DEFAULT FALSE, meta JSONB DEFAULT '{}' ); -- full-text (Czech + English, 'simple' covers both without stemming noise) CREATE OR REPLACE FUNCTION kb_memories_fts_update() RETURNS TRIGGER AS $$ BEGIN NEW.fts := to_tsvector('simple', coalesce(NEW.title, '') || ' ' || coalesce(NEW.summary, '') || ' ' || NEW.content ); NEW.updated_at := NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS kb_memories_fts_trig ON kb_memories; CREATE TRIGGER kb_memories_fts_trig BEFORE INSERT OR UPDATE ON kb_memories FOR EACH ROW EXECUTE FUNCTION kb_memories_fts_update(); -- indexes CREATE INDEX IF NOT EXISTS kb_memories_fts_idx ON kb_memories USING GIN(fts); CREATE INDEX IF NOT EXISTS kb_memories_tags_idx ON kb_memories USING GIN(tags); CREATE INDEX IF NOT EXISTS kb_memories_type_idx ON kb_memories(mem_type); CREATE INDEX IF NOT EXISTS kb_memories_project_idx ON kb_memories(project); CREATE INDEX IF NOT EXISTS kb_memories_importance_idx ON kb_memories(importance DESC); CREATE INDEX IF NOT EXISTS kb_memories_created_idx ON kb_memories(created_at DESC); CREATE INDEX IF NOT EXISTS kb_memories_session_idx ON kb_memories(session_id); -- Vector index (aktivovat po ~1k řádcích pro lepší recall) -- CREATE INDEX kb_memories_vec_idx ON kb_memories USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);