301 lines
12 KiB
SQL
301 lines
12 KiB
SQL
-- Remote Coding Agent - Combined Schema
|
|
-- Version: Combined (final state after migrations 001-020)
|
|
-- Description: Complete database schema (idempotent - safe to run multiple times)
|
|
--
|
|
-- 8 Tables:
|
|
-- 1. remote_agent_codebases
|
|
-- 1b. remote_agent_codebase_env_vars
|
|
-- 2. remote_agent_conversations
|
|
-- 3. remote_agent_sessions
|
|
-- 4. remote_agent_isolation_environments
|
|
-- 5. remote_agent_workflow_runs
|
|
-- 6. remote_agent_workflow_events
|
|
-- 7. remote_agent_messages
|
|
--
|
|
-- Dropped tables (via migrations):
|
|
-- - remote_agent_command_templates (017)
|
|
--
|
|
-- Dropped columns (via migrations):
|
|
-- - conversations.worktree_path (007)
|
|
-- - conversations.isolation_env_id_legacy (007)
|
|
-- - conversations.isolation_provider (007)
|
|
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
|
|
-- ============================================================================
|
|
-- Table 1: Codebases
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_codebases (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name VARCHAR(255) NOT NULL,
|
|
repository_url VARCHAR(500),
|
|
default_cwd VARCHAR(500) NOT NULL,
|
|
ai_assistant_type VARCHAR(20) DEFAULT 'claude',
|
|
allow_env_keys BOOLEAN NOT NULL DEFAULT FALSE,
|
|
commands JSONB DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
COMMENT ON TABLE remote_agent_codebases IS
|
|
'Repository metadata: name, URL, working directory, AI assistant type, and command paths (JSONB)';
|
|
|
|
-- ============================================================================
|
|
-- Table 1b: Codebase Env Vars
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_codebase_env_vars (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
codebase_id UUID NOT NULL REFERENCES remote_agent_codebases(id) ON DELETE CASCADE,
|
|
key VARCHAR(255) NOT NULL,
|
|
value TEXT NOT NULL,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
UNIQUE(codebase_id, key)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_codebase_env_vars_codebase_id
|
|
ON remote_agent_codebase_env_vars(codebase_id);
|
|
|
|
COMMENT ON TABLE remote_agent_codebase_env_vars IS
|
|
'Per-project env vars merged into Options.env on Claude SDK calls. Managed via Web UI or config.';
|
|
|
|
-- ============================================================================
|
|
-- Table 2: Conversations
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_conversations (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
platform_type VARCHAR(20) NOT NULL,
|
|
platform_conversation_id VARCHAR(255) NOT NULL,
|
|
codebase_id UUID REFERENCES remote_agent_codebases(id) ON DELETE SET NULL,
|
|
cwd VARCHAR(500),
|
|
ai_assistant_type VARCHAR(20) DEFAULT 'claude',
|
|
isolation_env_id UUID,
|
|
title VARCHAR(255),
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
hidden BOOLEAN DEFAULT FALSE,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW(),
|
|
last_activity_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
UNIQUE(platform_type, platform_conversation_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_remote_agent_conversations_codebase
|
|
ON remote_agent_conversations(codebase_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conversations_hidden
|
|
ON remote_agent_conversations(hidden);
|
|
CREATE INDEX IF NOT EXISTS idx_conversations_codebase
|
|
ON remote_agent_conversations(codebase_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON COLUMN remote_agent_conversations.isolation_env_id IS
|
|
'UUID reference to isolation_environments table (the only isolation reference)';
|
|
|
|
-- ============================================================================
|
|
-- Table 3: Sessions
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
conversation_id UUID REFERENCES remote_agent_conversations(id) ON DELETE CASCADE,
|
|
codebase_id UUID REFERENCES remote_agent_codebases(id) ON DELETE SET NULL,
|
|
ai_assistant_type VARCHAR(20) NOT NULL,
|
|
assistant_session_id VARCHAR(255),
|
|
active BOOLEAN DEFAULT true,
|
|
metadata JSONB DEFAULT '{}'::jsonb,
|
|
parent_session_id UUID REFERENCES remote_agent_sessions(id),
|
|
transition_reason TEXT,
|
|
ended_reason TEXT,
|
|
started_at TIMESTAMP DEFAULT NOW(),
|
|
ended_at TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_remote_agent_sessions_conversation
|
|
ON remote_agent_sessions(conversation_id, active);
|
|
CREATE INDEX IF NOT EXISTS idx_remote_agent_sessions_codebase
|
|
ON remote_agent_sessions(codebase_id);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_parent
|
|
ON remote_agent_sessions(parent_session_id);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_conversation_started
|
|
ON remote_agent_sessions(conversation_id, started_at DESC);
|
|
|
|
COMMENT ON COLUMN remote_agent_sessions.parent_session_id IS
|
|
'Links to the previous session in this conversation (for audit trail)';
|
|
COMMENT ON COLUMN remote_agent_sessions.transition_reason IS
|
|
'Why this session was created: plan-to-execute, isolation-changed, reset-requested, etc.';
|
|
COMMENT ON COLUMN remote_agent_sessions.ended_reason IS
|
|
'Why this session was deactivated: reset-requested, cwd-changed, conversation-closed, etc.';
|
|
|
|
-- ============================================================================
|
|
-- Table 4: Isolation Environments
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_isolation_environments (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
codebase_id UUID NOT NULL REFERENCES remote_agent_codebases(id) ON DELETE CASCADE,
|
|
|
|
-- Workflow identification (what work this is for)
|
|
workflow_type TEXT NOT NULL,
|
|
workflow_id TEXT NOT NULL,
|
|
|
|
-- Implementation details
|
|
provider TEXT NOT NULL DEFAULT 'worktree',
|
|
working_path TEXT NOT NULL,
|
|
branch_name TEXT NOT NULL,
|
|
|
|
-- Lifecycle
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
created_by_platform TEXT,
|
|
|
|
-- Cross-reference metadata (for linking)
|
|
metadata JSONB DEFAULT '{}'
|
|
);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS unique_active_workflow
|
|
ON remote_agent_isolation_environments (codebase_id, workflow_type, workflow_id)
|
|
WHERE status = 'active';
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_isolation_env_codebase
|
|
ON remote_agent_isolation_environments(codebase_id);
|
|
CREATE INDEX IF NOT EXISTS idx_isolation_env_status
|
|
ON remote_agent_isolation_environments(status);
|
|
CREATE INDEX IF NOT EXISTS idx_isolation_env_workflow
|
|
ON remote_agent_isolation_environments(workflow_type, workflow_id);
|
|
|
|
ALTER TABLE remote_agent_conversations
|
|
ADD COLUMN IF NOT EXISTS isolation_env_id UUID
|
|
REFERENCES remote_agent_isolation_environments(id) ON DELETE SET NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_conversations_isolation_env_id
|
|
ON remote_agent_conversations(isolation_env_id);
|
|
|
|
COMMENT ON TABLE remote_agent_isolation_environments IS
|
|
'Work-centric isolated environments with independent lifecycle';
|
|
COMMENT ON COLUMN remote_agent_isolation_environments.workflow_type IS
|
|
'Type of work: issue, pr, review, thread, task';
|
|
COMMENT ON COLUMN remote_agent_isolation_environments.workflow_id IS
|
|
'Identifier for the work (issue number, PR number, thread hash, etc.)';
|
|
|
|
-- ============================================================================
|
|
-- Table 5: Workflow Runs
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_workflow_runs (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workflow_name VARCHAR(255) NOT NULL,
|
|
conversation_id UUID REFERENCES remote_agent_conversations(id) ON DELETE CASCADE,
|
|
codebase_id UUID REFERENCES remote_agent_codebases(id) ON DELETE SET NULL,
|
|
current_step_index INTEGER,
|
|
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
|
user_message TEXT NOT NULL,
|
|
metadata JSONB DEFAULT '{}',
|
|
parent_conversation_id UUID REFERENCES remote_agent_conversations(id) ON DELETE SET NULL,
|
|
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
completed_at TIMESTAMP WITH TIME ZONE,
|
|
last_activity_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
working_path TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_runs_conversation
|
|
ON remote_agent_workflow_runs(conversation_id);
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_runs_status
|
|
ON remote_agent_workflow_runs(status);
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_runs_parent_conv
|
|
ON remote_agent_workflow_runs(parent_conversation_id);
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_runs_last_activity
|
|
ON remote_agent_workflow_runs(last_activity_at)
|
|
WHERE status = 'running';
|
|
|
|
COMMENT ON TABLE remote_agent_workflow_runs IS
|
|
'Tracks workflow execution state for resumption and observability';
|
|
|
|
-- ============================================================================
|
|
-- Table 6: Workflow Events
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_workflow_events (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workflow_run_id UUID NOT NULL REFERENCES remote_agent_workflow_runs(id) ON DELETE CASCADE,
|
|
event_type VARCHAR(50) NOT NULL,
|
|
step_index INTEGER,
|
|
step_name VARCHAR(255),
|
|
data JSONB DEFAULT '{}',
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_events_run_id
|
|
ON remote_agent_workflow_events(workflow_run_id);
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_events_type
|
|
ON remote_agent_workflow_events(event_type);
|
|
|
|
COMMENT ON TABLE remote_agent_workflow_events IS
|
|
'Lean UI-relevant workflow events for observability (step transitions, artifacts, errors)';
|
|
|
|
-- ============================================================================
|
|
-- Table 7: Messages
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS remote_agent_messages (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
conversation_id UUID NOT NULL REFERENCES remote_agent_conversations(id) ON DELETE CASCADE,
|
|
role VARCHAR(20) NOT NULL,
|
|
content TEXT NOT NULL DEFAULT '',
|
|
metadata JSONB DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_messages_conversation_id
|
|
ON remote_agent_messages(conversation_id, created_at ASC);
|
|
|
|
-- ============================================================================
|
|
-- Cleanup: Drop legacy objects from older schemas
|
|
-- ============================================================================
|
|
|
|
DROP TABLE IF EXISTS remote_agent_command_templates;
|
|
DROP INDEX IF EXISTS idx_remote_agent_command_templates_name;
|
|
|
|
ALTER TABLE remote_agent_conversations DROP COLUMN IF EXISTS worktree_path;
|
|
ALTER TABLE remote_agent_conversations DROP COLUMN IF EXISTS isolation_env_id_legacy;
|
|
ALTER TABLE remote_agent_conversations DROP COLUMN IF EXISTS isolation_provider;
|
|
DROP INDEX IF EXISTS idx_conversations_isolation;
|
|
|
|
ALTER TABLE remote_agent_isolation_environments
|
|
DROP CONSTRAINT IF EXISTS unique_workflow;
|
|
|
|
-- ============================================================================
|
|
-- Idempotent ALTER statements for upgrading existing databases
|
|
-- ============================================================================
|
|
|
|
ALTER TABLE remote_agent_conversations
|
|
ADD COLUMN IF NOT EXISTS isolation_env_id UUID
|
|
REFERENCES remote_agent_isolation_environments(id) ON DELETE SET NULL;
|
|
ALTER TABLE remote_agent_conversations
|
|
ADD COLUMN IF NOT EXISTS last_activity_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();
|
|
|
|
ALTER TABLE remote_agent_workflow_runs
|
|
ADD COLUMN IF NOT EXISTS last_activity_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();
|
|
|
|
ALTER TABLE remote_agent_sessions
|
|
ADD COLUMN IF NOT EXISTS parent_session_id UUID REFERENCES remote_agent_sessions(id);
|
|
ALTER TABLE remote_agent_sessions
|
|
ADD COLUMN IF NOT EXISTS transition_reason TEXT;
|
|
|
|
ALTER TABLE remote_agent_conversations
|
|
ADD COLUMN IF NOT EXISTS title VARCHAR(255);
|
|
ALTER TABLE remote_agent_conversations
|
|
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMP WITH TIME ZONE;
|
|
|
|
ALTER TABLE remote_agent_workflow_runs
|
|
ADD COLUMN IF NOT EXISTS parent_conversation_id UUID
|
|
REFERENCES remote_agent_conversations(id) ON DELETE SET NULL;
|
|
ALTER TABLE remote_agent_conversations
|
|
ADD COLUMN IF NOT EXISTS hidden BOOLEAN DEFAULT FALSE;
|
|
|
|
ALTER TABLE remote_agent_sessions
|
|
ADD COLUMN IF NOT EXISTS ended_reason TEXT;
|
|
|
|
ALTER TABLE remote_agent_codebases
|
|
ADD COLUMN IF NOT EXISTS allow_env_keys BOOLEAN NOT NULL DEFAULT FALSE;
|