-- ========================================== -- Chat Switchboard โ€” 009 Workspaces & Git -- ========================================== -- File workspaces, workspace file index, semantic chunks, git credentials. -- ICD ยง7 (Workspaces & Git) -- ========================================== -- ========================================= -- WORKSPACES -- ========================================= CREATE TABLE IF NOT EXISTS workspaces ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), owner_type VARCHAR(20) NOT NULL CHECK (owner_type IN ('user', 'project', 'channel', 'team')), owner_id UUID NOT NULL, name VARCHAR(200) NOT NULL, root_path TEXT NOT NULL, max_bytes BIGINT, status VARCHAR(20) NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived', 'deleting')), indexing_enabled BOOLEAN NOT NULL DEFAULT true, -- Git integration (v0.21.4) git_remote_url TEXT, git_branch TEXT, git_credential_id UUID, git_last_sync TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_workspaces_owner ON workspaces(owner_type, owner_id); CREATE INDEX IF NOT EXISTS idx_workspaces_status ON workspaces(status) WHERE status != 'deleting'; DROP TRIGGER IF EXISTS workspaces_updated_at ON workspaces; CREATE TRIGGER workspaces_updated_at BEFORE UPDATE ON workspaces FOR EACH ROW EXECUTE FUNCTION update_updated_at(); COMMENT ON TABLE workspaces IS 'File workspaces bound to users, projects, channels, or teams'; COMMENT ON COLUMN workspaces.root_path IS 'PVC-relative path to workspace root directory'; -- ========================================= -- WORKSPACE FILES -- ========================================= CREATE TABLE IF NOT EXISTS workspace_files ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE, path TEXT NOT NULL, is_directory BOOLEAN NOT NULL DEFAULT false, content_type VARCHAR(100), size_bytes BIGINT NOT NULL DEFAULT 0, sha256 VARCHAR(64), index_status VARCHAR(20) DEFAULT 'pending' CHECK (index_status IN ('pending', 'indexing', 'ready', 'error', 'skipped')), chunk_count INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_files_path ON workspace_files(workspace_id, path); CREATE INDEX IF NOT EXISTS idx_workspace_files_workspace ON workspace_files(workspace_id); CREATE INDEX IF NOT EXISTS idx_workspace_files_type ON workspace_files(workspace_id, content_type) WHERE content_type IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_workspace_files_index_status ON workspace_files(workspace_id, index_status) WHERE index_status IN ('pending', 'indexing'); DROP TRIGGER IF EXISTS workspace_files_updated_at ON workspace_files; CREATE TRIGGER workspace_files_updated_at BEFORE UPDATE ON workspace_files FOR EACH ROW EXECUTE FUNCTION update_updated_at(); COMMENT ON TABLE workspace_files IS 'Metadata index for workspace files โ€” filesystem is source of truth'; -- ========================================= -- WORKSPACE CHUNKS (v0.21.2) -- ========================================= CREATE TABLE IF NOT EXISTS workspace_chunks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE, file_id UUID NOT NULL REFERENCES workspace_files(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 DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_workspace_chunks_file ON workspace_chunks(file_id); CREATE INDEX IF NOT EXISTS idx_workspace_chunks_workspace ON workspace_chunks(workspace_id); COMMENT ON TABLE workspace_chunks IS 'Text chunks with vector embeddings for workspace file semantic search'; -- ========================================= -- GIT CREDENTIALS (v0.21.4) -- ========================================= CREATE TABLE IF NOT EXISTS git_credentials ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, name TEXT NOT NULL DEFAULT '', auth_type TEXT NOT NULL DEFAULT 'https_pat', encrypted_data BYTEA NOT NULL DEFAULT '', nonce BYTEA NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_git_credentials_user ON git_credentials(user_id); -- Deferred FK: workspaces.git_credential_id โ†’ git_credentials.id DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'fk_workspaces_git_credential' ) THEN ALTER TABLE workspaces ADD CONSTRAINT fk_workspaces_git_credential FOREIGN KEY (git_credential_id) REFERENCES git_credentials(id) ON DELETE SET NULL; END IF; END $$;