DROP VIEW IF EXISTS mv_reports_ucepsa_demo.loss_priority_board; CREATE VIEW mv_reports_ucepsa_demo.loss_priority_board AS WITH filtered AS ( SELECT e.* FROM mv_reports_ucepsa_demo.loss_events_current e WHERE NOT ( e.loss_type = 'STALE_OR_BAD_TELEMETRY' AND EXISTS ( SELECT 1 FROM mv_reports_ucepsa_demo.loss_events_current x WHERE x.machine_id = e.machine_id AND x.loss_type = 'SIN_TELEMETRIA' ) ) ) SELECT row_number() OVER ( ORDER BY ( severity_score + LEAST((COALESCE(cost_eur, 0) * 10), 50)::int + LEAST((COALESCE(duration_min, 0) * 2), 40)::int ) DESC, detected_at DESC ) AS priority_rank, ( severity_score + LEAST((COALESCE(cost_eur, 0) * 10), 50)::int + LEAST((COALESCE(duration_min, 0) * 2), 40)::int ) AS priority_score, CASE WHEN ( severity_score + LEAST((COALESCE(cost_eur, 0) * 10), 50)::int + LEAST((COALESCE(duration_min, 0) * 2), 40)::int ) >= 90 THEN 'CRÍTICA' WHEN ( severity_score + LEAST((COALESCE(cost_eur, 0) * 10), 50)::int + LEAST((COALESCE(duration_min, 0) * 2), 40)::int ) >= 60 THEN 'ALTA' WHEN ( severity_score + LEAST((COALESCE(cost_eur, 0) * 10), 50)::int + LEAST((COALESCE(duration_min, 0) * 2), 40)::int ) >= 35 THEN 'MEDIA' ELSE 'BAJA' END AS priority_level, detected_at, machine_id, asset, order_ref, loss_type, severity, duration_min, cost_eur, status, description, recommended_action, evidence_json FROM filtered ORDER BY priority_score DESC, detected_at DESC; GRANT SELECT ON mv_reports_ucepsa_demo.loss_priority_board TO grafana_ucepsa_ro;