#!/usr/bin/env python3 """同步 dev DB — 補齊 prod 有但 dev 沒有的表""" import asyncio from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy import text DEV_URL = "postgresql+asyncpg://awoooi:awoooi_prod_2026@192.168.0.188:5432/awoooi_dev" MIGRATIONS = [ ("auto_repair_executions", """ CREATE TABLE IF NOT EXISTS auto_repair_executions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), incident_id UUID, playbook_name TEXT, status TEXT NOT NULL DEFAULT 'pending', started_at TIMESTAMPTZ, finished_at TIMESTAMPTZ, result JSONB, error_message TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) """), ("alert_operation_log", """ CREATE TABLE IF NOT EXISTS alert_operation_log ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), event_type TEXT NOT NULL, incident_id UUID, approval_id UUID, actor TEXT, action_detail TEXT, success BOOLEAN DEFAULT true, context JSONB DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) """), ("playbooks", """ CREATE TABLE IF NOT EXISTS playbooks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, description TEXT, steps JSONB NOT NULL DEFAULT '[]', tags TEXT[] DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) """), ("drift_reports", """ CREATE TABLE IF NOT EXISTS drift_reports ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), host TEXT NOT NULL, report_type TEXT NOT NULL DEFAULT 'config', items JSONB NOT NULL DEFAULT '[]', summary TEXT, severity TEXT DEFAULT 'low', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) """), ("pr_reviews", """ CREATE TABLE IF NOT EXISTS pr_reviews ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), repo TEXT NOT NULL, pr_id TEXT NOT NULL, review_text TEXT, model TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) """), ("vector_extension", "CREATE EXTENSION IF NOT EXISTS vector"), ("rag_chunks", """ CREATE TABLE IF NOT EXISTS rag_chunks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), source TEXT NOT NULL, source_id TEXT NOT NULL, title TEXT, chunk_text TEXT NOT NULL, embedding vector(768), metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) """), ] async def main(): engine = create_async_engine(DEV_URL, echo=False) async with engine.begin() as conn: r = await conn.execute(text( "SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name" )) existing = {row[0] for row in r} print(f"dev 現有: {sorted(existing)}") for name, sql in MIGRATIONS: try: await conn.execute(text(sql)) print(f" ✓ {name}") except Exception as e: print(f" ⚠ {name}: {e}") r2 = await conn.execute(text( "SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name" )) final = [row[0] for row in r2] print(f"\ndev 最終: {final}") await engine.dispose() asyncio.run(main())