diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 76655b32..73292268 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -5935,6 +5935,24 @@ export type Database = { } Relationships: [] } + grouped_alerts_view: { + Row: { + alert_count: number | null + alert_ids: string[] | null + alert_type: string | null + first_seen: string | null + function_name: string | null + group_key: string | null + has_resolved: boolean | null + last_seen: string | null + messages: string[] | null + metric_type: string | null + severity: string | null + source: string | null + unresolved_count: number | null + } + Relationships: [] + } idempotency_stats: { Row: { avg_duration_ms: number | null diff --git a/supabase/migrations/20251111014854_3934bac3-b5c0-4bd3-9723-2c69efc902f8.sql b/supabase/migrations/20251111014854_3934bac3-b5c0-4bd3-9723-2c69efc902f8.sql new file mode 100644 index 00000000..613b4057 --- /dev/null +++ b/supabase/migrations/20251111014854_3934bac3-b5c0-4bd3-9723-2c69efc902f8.sql @@ -0,0 +1,55 @@ +-- Create view for grouped alerts to reduce alert fatigue +CREATE OR REPLACE VIEW grouped_alerts_view AS +WITH system_alerts_grouped AS ( + SELECT + alert_type AS group_key, + alert_type, + severity, + 'system'::text AS source, + NULL::text AS function_name, + NULL::text AS metric_type, + COUNT(*) AS alert_count, + MIN(created_at) AS first_seen, + MAX(created_at) AS last_seen, + ARRAY_AGG(id::text ORDER BY created_at DESC) AS alert_ids, + ARRAY_AGG(message ORDER BY created_at DESC) AS messages, + BOOL_OR(resolved_at IS NOT NULL) AS has_resolved, + COUNT(*) FILTER (WHERE resolved_at IS NULL) AS unresolved_count + FROM system_alerts + WHERE created_at > NOW() - INTERVAL '7 days' + GROUP BY alert_type, severity +), +rate_limit_alerts_grouped AS ( + SELECT + CONCAT(metric_type, ':', COALESCE(function_name, 'global')) AS group_key, + NULL::text AS alert_type, + 'high'::text AS severity, + 'rate_limit'::text AS source, + function_name, + metric_type, + COUNT(*) AS alert_count, + MIN(created_at) AS first_seen, + MAX(created_at) AS last_seen, + ARRAY_AGG(id::text ORDER BY created_at DESC) AS alert_ids, + ARRAY_AGG(alert_message ORDER BY created_at DESC) AS messages, + BOOL_OR(resolved_at IS NOT NULL) AS has_resolved, + COUNT(*) FILTER (WHERE resolved_at IS NULL) AS unresolved_count + FROM rate_limit_alerts + WHERE created_at > NOW() - INTERVAL '7 days' + GROUP BY metric_type, function_name +) +SELECT * FROM system_alerts_grouped +UNION ALL +SELECT * FROM rate_limit_alerts_grouped; + +-- Grant access to authenticated users +GRANT SELECT ON grouped_alerts_view TO authenticated; + +-- Create indexes for better performance +CREATE INDEX IF NOT EXISTS idx_system_alerts_grouping + ON system_alerts(alert_type, severity, created_at DESC) + WHERE resolved_at IS NULL; + +CREATE INDEX IF NOT EXISTS idx_rate_limit_alerts_grouping + ON rate_limit_alerts(metric_type, function_name, created_at DESC) + WHERE resolved_at IS NULL; \ No newline at end of file