-- Migración 003: Tablas para sistema de Drones (AtomicDrones) -- Fecha: 2026-04-07 -- Propósito: Crear tablas internas para registro detallado de drones -- ============================================================================ -- Tabla 1: dron_logs - Logs detallados de cada dron -- ============================================================================ CREATE TABLE IF NOT EXISTS bitacoras.dron_logs ( id SERIAL PRIMARY KEY, dron_id VARCHAR(50) NOT NULL, -- ej: dron_083045_123 flujo_id VARCHAR(50), -- ID de orquestación (si aplica) tipo VARCHAR(20) NOT NULL, -- ejecutor|vigilante|sanador|planificador|mensajero|orquestador estado VARCHAR(20) NOT NULL, -- pending|running|completed|failed|zombie cmd TEXT, -- Comando ejecutado output TEXT, -- Salida del comando exit_code INTEGER, -- Código de retorno started_at TIMESTAMP DEFAULT NOW(), completed_at TIMESTAMP, heartbeat TIMESTAMP DEFAULT NOW(), -- Último heartbeat reintentos INTEGER DEFAULT 0, metadata JSONB DEFAULT '{}'::jsonb, -- Metadata adicional created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); -- Índices para consultas eficientes CREATE INDEX IF NOT EXISTS idx_dron_logs_estado ON bitacoras.dron_logs(estado); CREATE INDEX IF NOT EXISTS idx_dron_logs_heartbeat ON bitacoras.dron_logs(heartbeat); CREATE INDEX IF NOT EXISTS idx_dron_logs_flujo ON bitacoras.dron_logs(flujo_id); CREATE INDEX IF NOT EXISTS idx_dron_logs_tipo ON bitacoras.dron_logs(tipo); CREATE INDEX IF NOT EXISTS idx_dron_logs_started_at ON bitacoras.dron_logs(started_at); -- ============================================================================ -- Tabla 2: dron_avances - Avances paso-a-paso (para flujos multi-paso) -- ============================================================================ CREATE TABLE IF NOT EXISTS bitacoras.dron_avances ( id SERIAL PRIMARY KEY, dron_id VARCHAR(50) NOT NULL, flujo_id VARCHAR(50), -- ID de orquestación paso INTEGER NOT NULL, -- Número de paso en flujo descripcion TEXT NOT NULL, -- Qué se está haciendo estado VARCHAR(20) NOT NULL, -- pending|running|completed|failed output TEXT, -- Salida del paso started_at TIMESTAMP DEFAULT NOW(), completed_at TIMESTAMP, metadata JSONB DEFAULT '{}'::jsonb, created_at TIMESTAMP DEFAULT NOW() ); -- Índices para consultas eficientes CREATE INDEX IF NOT EXISTS idx_dron_avances_dron ON bitacoras.dron_avances(dron_id); CREATE INDEX IF NOT EXISTS idx_dron_avances_flujo ON bitacoras.dron_avances(flujo_id); CREATE INDEX IF NOT EXISTS idx_dron_avances_paso ON bitacoras.dron_avances(paso); -- ============================================================================ -- Tabla 3: dron_metricas - Métricas de rendimiento (agregaciones diarias) -- ============================================================================ CREATE TABLE IF NOT EXISTS bitacoras.dron_metricas ( id SERIAL PRIMARY KEY, fecha DATE NOT NULL, dron_tipo VARCHAR(20) NOT NULL, total_ejecuciones INTEGER DEFAULT 0, completados INTEGER DEFAULT 0, fallidos INTEGER DEFAULT 0, zombies INTEGER DEFAULT 0, tiempo_promedio INTERVAL DEFAULT '0 seconds', reintentos_total INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(fecha, dron_tipo) ); -- Índice para consultas por fecha CREATE INDEX IF NOT EXISTS idx_dron_metricas_fecha ON bitacoras.dron_metricas(fecha); -- ============================================================================ -- Trigger: Actualizar updated_at automáticamente -- ============================================================================ -- Función para actualizar updated_at CREATE OR REPLACE FUNCTION bitacoras.update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; -- Trigger para dron_logs DROP TRIGGER IF EXISTS update_dron_logs_updated_at ON bitacoras.dron_logs; CREATE TRIGGER update_dron_logs_updated_at BEFORE UPDATE ON bitacoras.dron_logs FOR EACH ROW EXECUTE FUNCTION bitacoras.update_updated_at_column(); -- Trigger para dron_metricas DROP TRIGGER IF EXISTS update_dron_metricas_updated_at ON bitacoras.dron_metricas; CREATE TRIGGER update_dron_metricas_updated_at BEFORE UPDATE ON bitacoras.dron_metricas FOR EACH ROW EXECUTE FUNCTION bitacoras.update_updated_at_column(); -- ============================================================================ -- Comentario de documentación -- ============================================================================ COMMENT ON TABLE bitacoras.dron_logs IS 'Logs detallados de cada dron en la colonia (NO visible directamente en Bitácora Web)'; COMMENT ON TABLE bitacoras.dron_avances IS 'Avances paso-a-paso de flujos multi-paso (orquestación)'; COMMENT ON TABLE bitacoras.dron_metricas IS 'Métricas agregadas diarias por tipo de dron (para dashboard y estadísticas)'; COMMENT ON COLUMN bitacoras.dron_logs.dron_id IS 'Identificador único del dron (ej: dron_083045_123)'; COMMENT ON COLUMN bitacoras.dron_logs.flujo_id IS 'ID de orquestación para agrupar drones de un mismo flujo'; COMMENT ON COLUMN bitacoras.dron_logs.tipo IS 'Tipo de dron: ejecutor, vigilante, sanador, planificador, mensajero, orquestador'; COMMENT ON COLUMN bitacoras.dron_logs.estado IS 'Estado actual: pending, running, completed, failed, zombie'; COMMENT ON COLUMN bitacoras.dron_logs.heartbeat IS 'Último heartbeat - si > 5min, dron se considera zombie'; -- ============================================================================ -- Vistas útiles para consultas frecuentes -- ============================================================================ -- Vista: Drones activos por estado CREATE OR REPLACE VIEW bitacoras.vw_dron_estado AS SELECT estado, tipo, COUNT(*) as cantidad, MIN(started_at) as mas_antiguo, MAX(started_at) as mas_reciente FROM bitacoras.dron_logs WHERE estado IN ('running', 'pending') GROUP BY estado, tipo; -- Vista: Drones zombies (heartbeat > 5min) CREATE OR REPLACE VIEW bitacoras.vw_dron_zombies AS SELECT id, dron_id, tipo, cmd, started_at, heartbeat, EXTRACT(EPOCH FROM (NOW() - heartbeat))/60 as minutos_sin_heartbeat FROM bitacoras.dron_logs WHERE estado = 'running' AND heartbeat < NOW() - INTERVAL '5 minutes'; -- Vista: Métricas de los últimos 7 días CREATE OR REPLACE VIEW bitacoras.vw_dron_metricas_semanal AS SELECT fecha, dron_tipo, total_ejecuciones, completados, fallidos, zombies, tiempo_promedio, reintentos_total, ROUND(100.0 * completados / NULLIF(total_ejecuciones, 0), 2) as tasa_exito FROM bitacoras.dron_metricas WHERE fecha >= CURRENT_DATE - INTERVAL '7 days' ORDER BY fecha DESC, dron_tipo; -- ============================================================================ -- Mensaje de confirmación -- ============================================================================ DO $$ BEGIN RAISE NOTICE '✅ Migración 003 completada: Tablas de Drones creadas exitosamente'; RAISE NOTICE ' - bitacoras.dron_logs: Logs detallados'; RAISE NOTICE ' - bitacoras.dron_avances: Avances paso-a-paso'; RAISE NOTICE ' - bitacoras.dron_metricas: Métricas agregadas'; RAISE NOTICE ' - Vistas: vw_dron_estado, vw_dron_zombies, vw_dron_metricas_semanal'; END $$;