CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE TABLE IF NOT EXISTS projects ( id UUID PRIMARY KEY, name TEXT NOT NULL, external_ref TEXT, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL ); CREATE TABLE IF NOT EXISTS work_items ( id UUID PRIMARY KEY, project_id UUID REFERENCES projects(id) ON DELETE SET NULL, type TEXT NOT NULL, description TEXT NOT NULL, payload JSONB, priority INTEGER NOT NULL DEFAULT 3 CHECK (priority BETWEEN 1 AND 5), status TEXT NOT NULL CHECK (status IN ('queued','dispatched','in_progress','blocked','failed','completed','cancelled')), assigned_agent TEXT, created_by TEXT, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, completed_at TIMESTAMPTZ, outcome TEXT CHECK (outcome IN ('success','failed','cancelled') OR outcome IS NULL), notes TEXT, CHECK ( (status IN ('completed','failed','cancelled') AND completed_at IS NOT NULL AND outcome IS NOT NULL) OR (status NOT IN ('completed','failed','cancelled') AND completed_at IS NULL AND outcome IS NULL) ) ); CREATE UNIQUE INDEX IF NOT EXISTS idx_one_in_progress_per_agent ON work_items(assigned_agent) WHERE status = 'in_progress' AND assigned_agent IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_work_items_status ON work_items(status); CREATE INDEX IF NOT EXISTS idx_work_items_agent_status ON work_items(assigned_agent, status); CREATE INDEX IF NOT EXISTS idx_work_items_project_id ON work_items(project_id); CREATE INDEX IF NOT EXISTS idx_work_items_created_at ON work_items(created_at); CREATE TABLE IF NOT EXISTS dispatch_log ( id UUID PRIMARY KEY, work_item_id UUID NOT NULL REFERENCES work_items(id) ON DELETE CASCADE, dispatched_at TIMESTAMPTZ NOT NULL, agent TEXT NOT NULL, completed_at TIMESTAMPTZ, outcome TEXT CHECK (outcome IN ('success','failed','cancelled') OR outcome IS NULL) ); CREATE INDEX IF NOT EXISTS idx_dispatch_log_work_item_id ON dispatch_log(work_item_id);