52 lines
3.7 KiB
JSON
52 lines
3.7 KiB
JSON
{
|
|
"dashboard_title": "Source Coverage & Gaps",
|
|
"description": "Operational dashboard for identifying source coverage gaps, stale sources, and symbols missing expected data feeds.",
|
|
"slug": "source-coverage-gaps",
|
|
"position_json": {
|
|
"HEADER_ID": {"id": "HEADER_ID", "type": "HEADER", "meta": {"text": "Source Coverage & Gaps"}},
|
|
"ROW-1": {
|
|
"type": "ROW",
|
|
"children": ["CHART-coverage-matrix", "CHART-missing-types-table"]
|
|
},
|
|
"ROW-2": {
|
|
"type": "ROW",
|
|
"children": ["CHART-stale-sources-table", "CHART-failure-heatmap"]
|
|
}
|
|
},
|
|
"metadata": {
|
|
"refresh_frequency": 600,
|
|
"default_filters": "{}",
|
|
"color_scheme": "supersetColors"
|
|
},
|
|
"charts": [
|
|
{
|
|
"slice_name": "Source Coverage Matrix",
|
|
"viz_type": "table",
|
|
"description": "Per-symbol source type coverage showing active source counts",
|
|
"datasource_type": "query",
|
|
"query": "SELECT c.ticker, c.legal_name, c.sector, COUNT(s.id) FILTER (WHERE s.active) AS active_sources, COUNT(s.id) FILTER (WHERE s.source_type = 'market_api' AND s.active) AS market_sources, COUNT(s.id) FILTER (WHERE s.source_type = 'news_api' AND s.active) AS news_sources, COUNT(s.id) FILTER (WHERE s.source_type = 'filings_api' AND s.active) AS filings_sources, COUNT(s.id) FILTER (WHERE s.source_type = 'web_scrape' AND s.active) AS web_scrape_sources, COUNT(s.id) FILTER (WHERE s.source_type = 'broker' AND s.active) AS broker_sources FROM companies c LEFT JOIN sources s ON s.company_id = c.id WHERE c.active = TRUE GROUP BY c.ticker, c.legal_name, c.sector ORDER BY c.ticker"
|
|
},
|
|
{
|
|
"slice_name": "Symbols Missing Source Types",
|
|
"viz_type": "table",
|
|
"description": "Companies that lack one or more expected source types (market_api, news_api, filings_api)",
|
|
"datasource_type": "query",
|
|
"query": "SELECT c.ticker, c.legal_name, c.sector, ARRAY_AGG(DISTINCT s.source_type) FILTER (WHERE s.active) AS active_types FROM companies c LEFT JOIN sources s ON s.company_id = c.id AND s.active = TRUE WHERE c.active = TRUE GROUP BY c.ticker, c.legal_name, c.sector HAVING NOT ARRAY['market_api', 'news_api', 'filings_api'] <@ ARRAY_AGG(DISTINCT s.source_type) FILTER (WHERE s.active) OR ARRAY_AGG(DISTINCT s.source_type) FILTER (WHERE s.active) IS NULL ORDER BY c.ticker"
|
|
},
|
|
{
|
|
"slice_name": "Stale Sources (No Success in 24h)",
|
|
"viz_type": "table",
|
|
"description": "Active sources that have not completed a successful ingestion run in the last 24 hours",
|
|
"datasource_type": "query",
|
|
"query": "SELECT c.ticker, s.source_type, s.source_name, MAX(ir.started_at) FILTER (WHERE ir.status = 'completed') AS last_success, MAX(ir.started_at) AS last_attempt, COUNT(*) FILTER (WHERE ir.status = 'failed' AND ir.started_at >= NOW() - INTERVAL '24 hours') AS recent_failures FROM sources s JOIN companies c ON c.id = s.company_id LEFT JOIN ingestion_runs ir ON ir.source_id = s.id WHERE s.active = TRUE AND c.active = TRUE GROUP BY c.ticker, s.source_type, s.source_name HAVING MAX(ir.started_at) FILTER (WHERE ir.status = 'completed') < NOW() - INTERVAL '24 hours' OR MAX(ir.started_at) FILTER (WHERE ir.status = 'completed') IS NULL ORDER BY c.ticker, s.source_type"
|
|
},
|
|
{
|
|
"slice_name": "Source Failure Heatmap",
|
|
"viz_type": "heatmap",
|
|
"description": "Failure counts by source type and ticker in the last 24h",
|
|
"datasource_type": "query",
|
|
"query": "SELECT c.ticker, ir.source_type, COUNT(*) FILTER (WHERE ir.status = 'failed') AS failures FROM ingestion_runs ir JOIN companies c ON c.id = ir.company_id WHERE ir.started_at >= NOW() - INTERVAL '24 hours' GROUP BY c.ticker, ir.source_type HAVING COUNT(*) FILTER (WHERE ir.status = 'failed') > 0 ORDER BY failures DESC"
|
|
}
|
|
]
|
|
}
|