-- ========================================== -- Chat Switchboard — 006 Knowledge Bases -- ========================================== -- Knowledge bases, documents, chunks, and bindings to channels/personas. -- ICD §5 (Knowledge Bases) -- ========================================== -- ========================================= -- KNOWLEDGE BASES -- ========================================= CREATE TABLE IF NOT EXISTS knowledge_bases ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', scope TEXT NOT NULL DEFAULT 'global', owner_id UUID REFERENCES users(id) ON DELETE CASCADE, team_id UUID REFERENCES teams(id) ON DELETE CASCADE, embedding_config JSONB NOT NULL DEFAULT '{}', document_count INT NOT NULL DEFAULT 0, chunk_count INT NOT NULL DEFAULT 0, total_bytes BIGINT NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'active', discoverable BOOLEAN NOT NULL DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT kb_scope_check CHECK ( (scope = 'global' AND owner_id IS NULL) OR (scope = 'team' AND team_id IS NOT NULL) OR (scope = 'personal' AND owner_id IS NOT NULL) ) ); CREATE INDEX IF NOT EXISTS idx_kb_scope ON knowledge_bases(scope); CREATE INDEX IF NOT EXISTS idx_kb_owner ON knowledge_bases(owner_id) WHERE owner_id IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_kb_team ON knowledge_bases(team_id) WHERE team_id IS NOT NULL; COMMENT ON COLUMN knowledge_bases.discoverable IS 'false = hidden from user KB lists, only accessible through persona binding'; -- ========================================= -- KB DOCUMENTS -- ========================================= CREATE TABLE IF NOT EXISTS kb_documents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), kb_id UUID NOT NULL REFERENCES knowledge_bases(id) ON DELETE CASCADE, filename TEXT NOT NULL, content_type TEXT NOT NULL, size_bytes BIGINT NOT NULL, storage_key TEXT NOT NULL, extracted_text TEXT, chunk_count INT NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'pending', error TEXT, uploaded_by UUID NOT NULL REFERENCES users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_kbdoc_kb ON kb_documents(kb_id); -- ========================================= -- KB CHUNKS -- ========================================= CREATE TABLE IF NOT EXISTS kb_chunks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), kb_id UUID NOT NULL REFERENCES knowledge_bases(id) ON DELETE CASCADE, document_id UUID NOT NULL REFERENCES kb_documents(id) ON DELETE CASCADE, chunk_index INT NOT NULL, content TEXT NOT NULL, token_count INT NOT NULL DEFAULT 0, embedding VECTOR(3072), metadata JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_kbchunk_kb ON kb_chunks(kb_id); CREATE INDEX IF NOT EXISTS idx_kbchunk_doc ON kb_chunks(document_id); -- ========================================= -- CHANNEL ↔ KB BINDING -- ========================================= CREATE TABLE IF NOT EXISTS channel_knowledge_bases ( channel_id UUID NOT NULL REFERENCES channels(id) ON DELETE CASCADE, kb_id UUID NOT NULL REFERENCES knowledge_bases(id) ON DELETE CASCADE, enabled BOOLEAN NOT NULL DEFAULT true, added_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (channel_id, kb_id) ); -- ========================================= -- PERSONA ↔ KB BINDING (v0.17.0) -- ========================================= CREATE TABLE IF NOT EXISTS persona_knowledge_bases ( persona_id UUID NOT NULL REFERENCES personas(id) ON DELETE CASCADE, kb_id UUID NOT NULL REFERENCES knowledge_bases(id) ON DELETE CASCADE, auto_search BOOLEAN NOT NULL DEFAULT false, added_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (persona_id, kb_id) ); CREATE INDEX IF NOT EXISTS idx_persona_kb_persona ON persona_knowledge_bases(persona_id); CREATE INDEX IF NOT EXISTS idx_persona_kb_kb ON persona_knowledge_bases(kb_id); COMMENT ON TABLE persona_knowledge_bases IS 'Binds KBs to personas — the persona becomes a gateway to its KBs'; COMMENT ON COLUMN persona_knowledge_bases.auto_search IS 'true = auto-prepend top-K results to context; false = kb_search tool only';