67 lines
2.6 KiB
MySQL
67 lines
2.6 KiB
MySQL
|
|
-- dd0c/portal analytics helpers + scanner constraint updates
|
||
|
|
|
||
|
|
-- Update scan_history scanner check to include new scanner types
|
||
|
|
ALTER TABLE scan_history DROP CONSTRAINT IF EXISTS scan_history_scanner_check;
|
||
|
|
ALTER TABLE scan_history ADD CONSTRAINT scan_history_scanner_check
|
||
|
|
CHECK (scanner IN ('aws', 'github', 'cloudformation', 'apigateway'));
|
||
|
|
|
||
|
|
-- Update staged_updates source check to include new sources
|
||
|
|
ALTER TABLE staged_updates DROP CONSTRAINT IF EXISTS staged_updates_source_check;
|
||
|
|
ALTER TABLE staged_updates ADD CONSTRAINT staged_updates_source_check
|
||
|
|
CHECK (source IN ('aws', 'github', 'cloudformation', 'apigateway', 'manual'));
|
||
|
|
|
||
|
|
-- Materialized view: ownership coverage summary
|
||
|
|
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_ownership_coverage AS
|
||
|
|
SELECT
|
||
|
|
tenant_id,
|
||
|
|
COUNT(*)::int AS total_services,
|
||
|
|
COUNT(*) FILTER (WHERE owner != 'unknown')::int AS owned_services,
|
||
|
|
COUNT(*) FILTER (WHERE owner = 'unknown')::int AS unowned_services,
|
||
|
|
ROUND(
|
||
|
|
(COUNT(*) FILTER (WHERE owner != 'unknown')::numeric / NULLIF(COUNT(*), 0)) * 100, 1
|
||
|
|
) AS coverage_pct
|
||
|
|
FROM services
|
||
|
|
WHERE lifecycle = 'active'
|
||
|
|
GROUP BY tenant_id;
|
||
|
|
|
||
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_mv_ownership_tenant ON mv_ownership_coverage(tenant_id);
|
||
|
|
|
||
|
|
-- Materialized view: health scorecards by tier
|
||
|
|
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_health_by_tier AS
|
||
|
|
SELECT
|
||
|
|
tenant_id,
|
||
|
|
tier,
|
||
|
|
COUNT(*)::int AS count,
|
||
|
|
COUNT(*) FILTER (WHERE last_discovered_at < NOW() - INTERVAL '7 days')::int AS stale_count
|
||
|
|
FROM services
|
||
|
|
WHERE lifecycle = 'active'
|
||
|
|
GROUP BY tenant_id, tier;
|
||
|
|
|
||
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_mv_health_tier ON mv_health_by_tier(tenant_id, tier);
|
||
|
|
|
||
|
|
-- Materialized view: tech debt indicators
|
||
|
|
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_tech_debt AS
|
||
|
|
SELECT
|
||
|
|
tenant_id,
|
||
|
|
COUNT(*)::int AS total_active,
|
||
|
|
COUNT(*) FILTER (WHERE description IS NULL OR description = '')::int AS missing_description,
|
||
|
|
COUNT(*) FILTER (WHERE owner = 'unknown')::int AS missing_owner,
|
||
|
|
COUNT(*) FILTER (WHERE owner_source = 'heuristic' AND owner != 'unknown')::int AS heuristic_ownership,
|
||
|
|
COUNT(*) FILTER (WHERE links = '{}' OR links IS NULL)::int AS missing_links,
|
||
|
|
COUNT(*) FILTER (WHERE last_discovered_at IS NULL)::int AS never_discovered
|
||
|
|
FROM services
|
||
|
|
WHERE lifecycle = 'active'
|
||
|
|
GROUP BY tenant_id;
|
||
|
|
|
||
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_mv_tech_debt_tenant ON mv_tech_debt(tenant_id);
|
||
|
|
|
||
|
|
-- Helper function to refresh all analytics materialized views
|
||
|
|
CREATE OR REPLACE FUNCTION refresh_analytics_views()
|
||
|
|
RETURNS void AS $$
|
||
|
|
BEGIN
|
||
|
|
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_ownership_coverage;
|
||
|
|
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_health_by_tier;
|
||
|
|
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_tech_debt;
|
||
|
|
END;
|
||
|
|
$$ LANGUAGE plpgsql;
|