CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE TABLE IF NOT EXISTS colony_missions ( mission_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id TEXT NOT NULL, mission_type TEXT NOT NULL CHECK ( mission_type IN ('oracle_advisory', 'crm_lead_intelligence', 'catalyst_strategy_brief') ), origin_surface TEXT NOT NULL DEFAULT 'api', actor_id TEXT NOT NULL, actor_role TEXT, risk_level TEXT NOT NULL DEFAULT 'low' CHECK (risk_level IN ('low', 'medium', 'high')), sensitivity_class TEXT NOT NULL DEFAULT 'internal' CHECK ( sensitivity_class IN ('public', 'internal', 'confidential') ), status TEXT NOT NULL DEFAULT 'pending' CHECK ( status IN ('pending', 'queued', 'running', 'review', 'completed', 'failed', 'dispatch_failed') ), review_status TEXT CHECK (review_status IN ('pending', 'approved', 'rejected')), time_budget_ms INTEGER NOT NULL CHECK (time_budget_ms > 0), token_budget INTEGER NOT NULL CHECK (token_budget > 0), user_goal TEXT NOT NULL, normalized_goal TEXT NOT NULL, context_refs JSONB NOT NULL DEFAULT '{}'::jsonb, requested_outputs JSONB NOT NULL DEFAULT '[]'::jsonb, payload JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), completed_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS idx_colony_missions_tenant_created ON colony_missions (tenant_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_colony_missions_tenant_status ON colony_missions (tenant_id, status); CREATE TABLE IF NOT EXISTS colony_tasks ( task_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), mission_id UUID NOT NULL REFERENCES colony_missions (mission_id) ON DELETE CASCADE, tenant_id TEXT NOT NULL, parent_task_id UUID, agent_name TEXT NOT NULL, task_type TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending' CHECK ( status IN ('pending', 'queued', 'running', 'completed', 'failed', 'cancelled') ), input JSONB NOT NULL DEFAULT '{}'::jsonb, output JSONB NOT NULL DEFAULT '{}'::jsonb, error TEXT, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_colony_tasks_mission_created ON colony_tasks (mission_id, created_at ASC); CREATE TABLE IF NOT EXISTS colony_worker_results ( result_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), mission_id UUID NOT NULL REFERENCES colony_missions (mission_id) ON DELETE CASCADE, task_id UUID REFERENCES colony_tasks (task_id) ON DELETE SET NULL, tenant_id TEXT NOT NULL, agent_name TEXT NOT NULL, result_type TEXT NOT NULL, confidence NUMERIC(5, 4), payload JSONB NOT NULL DEFAULT '{}'::jsonb, citations JSONB NOT NULL DEFAULT '[]'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_colony_worker_results_mission_created ON colony_worker_results (mission_id, created_at ASC); CREATE TABLE IF NOT EXISTS colony_writeback_proposals ( proposal_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), mission_id UUID NOT NULL REFERENCES colony_missions (mission_id) ON DELETE CASCADE, tenant_id TEXT NOT NULL, target_system TEXT NOT NULL, target_table TEXT, target_id TEXT, action TEXT NOT NULL, before_state JSONB NOT NULL DEFAULT '{}'::jsonb, after_state JSONB NOT NULL DEFAULT '{}'::jsonb, rationale TEXT, approval_status TEXT NOT NULL DEFAULT 'pending' CHECK ( approval_status IN ('pending', 'approved', 'rejected', 'applied', 'failed') ), approved_by TEXT, approved_at TIMESTAMPTZ, rejected_by TEXT, rejected_at TIMESTAMPTZ, rejection_reason TEXT, applied_at TIMESTAMPTZ, error TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_colony_writebacks_mission_status ON colony_writeback_proposals (mission_id, approval_status); CREATE TABLE IF NOT EXISTS colony_event_log ( event_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), mission_id UUID REFERENCES colony_missions (mission_id) ON DELETE CASCADE, tenant_id TEXT NOT NULL, event_type TEXT NOT NULL, actor TEXT, detail JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_colony_event_log_mission_created ON colony_event_log (mission_id, created_at DESC); CREATE TABLE IF NOT EXISTS catalyst_social_posts ( post_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), request_id UUID NOT NULL, tenant_id TEXT NOT NULL, actor_id TEXT NOT NULL, platform TEXT NOT NULL CHECK (platform IN ('facebook', 'instagram', 'linkedin', 'twitter')), post_type TEXT NOT NULL CHECK (post_type IN ('image', 'video', 'carousel', 'text', 'link')), caption TEXT NOT NULL, hashtags JSONB NOT NULL DEFAULT '[]'::jsonb, media_url TEXT, media_path TEXT, link_url TEXT, status TEXT NOT NULL CHECK (status IN ('scheduled', 'publishing', 'published', 'failed')), scheduled_at TIMESTAMPTZ, published_at TIMESTAMPTZ, platform_post_id TEXT, engagement JSONB NOT NULL DEFAULT '{}'::jsonb, error TEXT, platform_response JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_catalyst_social_posts_tenant_created ON catalyst_social_posts (tenant_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_catalyst_social_posts_tenant_status_scheduled ON catalyst_social_posts (tenant_id, status, scheduled_at); CREATE INDEX IF NOT EXISTS idx_catalyst_social_posts_request ON catalyst_social_posts (request_id);