CREATE TABLE knowledge_groups ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), name VARCHAR(100) NOT NULL, parent_id BIGINT REFERENCES knowledge_groups(id) ON DELETE SET NULL, sort_order INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE UNIQUE INDEX uk_knowledge_group_name ON knowledge_groups(tenant_id, COALESCE(parent_id, 0), name) WHERE deleted_at IS NULL; CREATE INDEX idx_knowledge_group_tenant_parent ON knowledge_groups(tenant_id, parent_id, sort_order) WHERE deleted_at IS NULL; CREATE TABLE knowledge_items ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), group_id BIGINT NOT NULL REFERENCES knowledge_groups(id), source_type VARCHAR(20) NOT NULL, name VARCHAR(255) NOT NULL, source_uri TEXT, storage_key TEXT NOT NULL DEFAULT '', content_text TEXT, status VARCHAR(20) NOT NULL DEFAULT 'pending', size_bytes BIGINT NOT NULL DEFAULT 0, item_version INT NOT NULL DEFAULT 1, error_message TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_knowledge_item_group_status ON knowledge_items(tenant_id, group_id, status) WHERE deleted_at IS NULL; CREATE TABLE knowledge_parse_tasks ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), knowledge_item_id BIGINT NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE, source_type VARCHAR(20) NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'pending', error_message TEXT, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_parse_task_status ON knowledge_parse_tasks(tenant_id, status, created_at DESC); CREATE TABLE knowledge_chunks_meta ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id), knowledge_item_id BIGINT NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE, chunk_index INT NOT NULL, token_count INT NOT NULL DEFAULT 0, qdrant_point_id VARCHAR(64) NOT NULL, item_version INT NOT NULL DEFAULT 1, status VARCHAR(20) NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (knowledge_item_id, chunk_index, item_version) ); CREATE INDEX idx_chunk_item_version ON knowledge_chunks_meta(tenant_id, knowledge_item_id, item_version, status); CREATE TABLE prompt_rule_knowledge_groups ( prompt_rule_id BIGINT NOT NULL REFERENCES prompt_rules(id) ON DELETE CASCADE, knowledge_group_id BIGINT NOT NULL REFERENCES knowledge_groups(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (prompt_rule_id, knowledge_group_id) ); CREATE INDEX idx_prompt_rule_knowledge_group ON prompt_rule_knowledge_groups(knowledge_group_id, prompt_rule_id);