-- Phase 11b: 歷史數據回填 alert_operation_log -- 建立時間: 2026-04-08 (台北時區) -- 建立者: Claude Code — 統帥指令「把之前所有的告警訊息,通通寫入資料庫」 -- -- 資料來源: -- incidents (14筆) → ALERT_RECEIVED 事件 -- approval_records (265筆) → TELEGRAM_SENT + USER_ACTION 事件 -- audit_logs (110筆) → EXECUTION_STARTED + EXECUTION_COMPLETED 事件 -- -- 注意: 使用 ON CONFLICT DO NOTHING 避免重複執行 -- ============================================================ -- Step 1: incidents → ALERT_RECEIVED -- ============================================================ INSERT INTO alert_operation_log ( id, incident_id, event_type, actor, action_detail, success, context, created_at ) SELECT gen_random_uuid()::text, incident_id, 'ALERT_RECEIVED', COALESCE(source, 'alertmanager'), COALESCE( signals->0->>'alert_name', 'unknown' ), TRUE, jsonb_build_object( 'severity', severity::text, 'status', status::text, 'alert_name', COALESCE(signals->0->>'alert_name', 'unknown'), 'namespace', COALESCE(signals->0->'labels'->>'namespace', 'default'), 'resource', COALESCE(signals->0->'labels'->>'resource', ''), 'message', COALESCE(signals->0->'annotations'->>'message', ''), 'source', COALESCE(source, 'alertmanager'), 'signal_count', json_array_length(signals), 'backfill', TRUE, 'backfill_at', NOW()::text ), created_at FROM incidents ON CONFLICT DO NOTHING; -- ============================================================ -- Step 2: approval_records → TELEGRAM_SENT (每筆 approval 代表推送了一次卡片) -- ============================================================ INSERT INTO alert_operation_log ( id, incident_id, approval_id, event_type, actor, action_detail, success, context, created_at ) SELECT gen_random_uuid()::text, incident_id, id, 'TELEGRAM_SENT', 'system', 'approval_card_sent', TRUE, jsonb_build_object( 'action', action, 'risk_level', risk_level::text, 'requested_by', requested_by, 'hit_count', hit_count, 'backfill', TRUE, 'backfill_at', NOW()::text ), created_at FROM approval_records ON CONFLICT DO NOTHING; -- ============================================================ -- Step 3: approval_records (APPROVED/REJECTED) → USER_ACTION -- ============================================================ INSERT INTO alert_operation_log ( id, incident_id, approval_id, event_type, actor, action_detail, success, context, created_at ) SELECT gen_random_uuid()::text, incident_id, id, 'USER_ACTION', COALESCE(requested_by, 'unknown'), CASE status::text WHEN 'APPROVED' THEN 'approve' WHEN 'REJECTED' THEN 'reject' WHEN 'EXECUTION_SUCCESS' THEN 'approve' WHEN 'EXECUTION_FAILED' THEN 'approve' ELSE status::text END, CASE status::text WHEN 'APPROVED' THEN TRUE WHEN 'EXECUTION_SUCCESS' THEN TRUE WHEN 'REJECTED' THEN FALSE WHEN 'EXECUTION_FAILED' THEN TRUE -- 批准了但執行失敗 ELSE NULL END, jsonb_build_object( 'status', status::text, 'risk_level', risk_level::text, 'rejection_reason', COALESCE(rejection_reason, ''), 'signatures', signatures, 'resolved_at', COALESCE(resolved_at::text, ''), 'backfill', TRUE, 'backfill_at', NOW()::text ), COALESCE(resolved_at, updated_at, created_at) FROM approval_records WHERE status::text IN ('APPROVED', 'REJECTED', 'EXECUTION_SUCCESS', 'EXECUTION_FAILED') ON CONFLICT DO NOTHING; -- ============================================================ -- Step 4: audit_logs → EXECUTION_COMPLETED -- ============================================================ INSERT INTO alert_operation_log ( id, approval_id, audit_log_id, event_type, actor, action_detail, success, error_message, context, created_at ) SELECT gen_random_uuid()::text, approval_id, id, 'EXECUTION_COMPLETED', COALESCE(executed_by, 'system'), COALESCE(operation_type, 'unknown') || '/' || COALESCE(target_resource, ''), success, error_message, jsonb_build_object( 'operation_type', operation_type, 'target_resource', target_resource, 'namespace', namespace, 'execution_duration_ms', execution_duration_ms, 'dry_run_passed', dry_run_passed, 'authorization_channel', COALESCE(authorization_channel, ''), 'retry_count', retry_count, 'failure_classification', COALESCE(failure_classification, ''), 'auto_repair_attempted', auto_repair_attempted, 'backfill', TRUE, 'backfill_at', NOW()::text ), created_at FROM audit_logs ON CONFLICT DO NOTHING; -- ============================================================ -- 驗證結果 -- ============================================================ SELECT event_type::text, COUNT(*) as count, MIN(created_at) as oldest, MAX(created_at) as newest FROM alert_operation_log GROUP BY event_type ORDER BY event_type;