.vbw-planning/milestones/ui-fixes-and-smart-scraping/phases/03-dashboard-pagination/04-PLAN.md
Add health status distribution counts (Healthy N, Warning N, Declining N, Critical N) to the dashboard stats section. The distribution is computed via a new query in StatsQuery and rendered as inline badge counts below the existing stats cards.
What: Extend StatsQuery#call to include a health_distribution hash with counts per health status.
Files to modify:
lib/source_monitor/dashboard/queries/stats_query.rbImplementation details:
health_distribution key to the returned hashSourceMonitor::Source.active.group(:health_status).count (returns { "healthy" => 42, "warning" => 3, ... })SELECT health_status, COUNT(*) FROM sources WHERE active = true GROUP BY health_status%w[healthy warning declining critical].each_with_object({}) { |s, h| h[s] = raw_counts.fetch(s, 0) }Acceptance criteria:
stats[:health_distribution] returns { "healthy" => N, "warning" => N, "declining" => N, "critical" => N }What: Add a row of inline badge counts below the existing stats cards grid.
Files to modify:
app/views/source_monitor/dashboard/_stats.html.erbImplementation details:
grid of stat cards, add a <div> with inline flex badgesHealthBadgeHelper:
bg-green-100 text-green-700bg-amber-100 text-amber-700bg-orange-100 text-orange-700bg-rose-100 text-rose-700<span class="inline-flex items-center gap-1 rounded-full px-3 py-1 text-xs font-semibold [color-classes]">Healthy <span class="font-bold">42</span></span>id="source_monitor_dashboard_health_distribution" for Turbo Stream targetingAcceptance criteria:
What: Record health distribution metrics via the existing instrumentation pattern.
Files to modify:
lib/source_monitor/dashboard/queries.rbImplementation details:
record_stats_metrics, add gauges for each health status count:
SourceMonitor::Metrics.gauge(:dashboard_stats_health_healthy, stats[:health_distribution]["healthy"])Acceptance criteria:
What: Test the query and verify the badge rendering.
Files to create:
test/lib/source_monitor/dashboard/stats_query_test.rbTest cases:
test "health_distribution counts active sources by health_status" -- Create sources with different health statuses, verify countstest "health_distribution excludes inactive sources" -- Create inactive source with "critical" status, verify it's not countedtest "health_distribution includes zero for missing statuses" -- Only healthy sources exist, verify warning/declining/critical are 0test "health_distribution handles no active sources" -- No active sources, verify all counts are 0Acceptance criteria:
create_source! factory with explicit health_status valuesThis plan modifies:
lib/source_monitor/dashboard/queries/stats_query.rbapp/views/source_monitor/dashboard/_stats.html.erblib/source_monitor/dashboard/queries.rb (metrics recording only -- different methods than Plan 02's upcoming_fetch_schedule method)test/lib/source_monitor/dashboard/stats_query_test.rb (NEW)Conflict analysis with Plan 02: Both plans modify lib/source_monitor/dashboard/queries.rb. However:
upcoming_fetch_schedule method signature and its cache keyrecord_stats_metrics private method onlyrecord_stats_metrics by appending lines (not restructuring), making merge trivial.No overlap with Plan 01 (paginator, shared partial, application_helper) or Plan 03 (sources controller/index).