This page documents every KPI on the Funnel Overview and the product tables (Solar & Storage, Generators) of the FSP Marketing Dashboard, plus the Total / By Region / By Source dimensions and the drilldown / investigate queries. All numbers reproduce the fsp-bi-hub/f2p_2026 reports directly from HubSpot data using a handful of server-aggregated GROUP BY queries.
<aside> 💡
The shared base filters (new_contacts_base, contacted_leads_base, set_appointments_base, closed, cancelled), the product scopes (ProductScopes), the timezone bucketing (ReportingTimeZone), and the caching conventions are documented once on the Conventions & Shared Filters page. This page references them by name rather than repeating them in full.
</aside>
Code citations point at:
app/controllers/api/v1/funnel_controller.rbapp/services/funnel/metrics_calculator.rbapp/services/funnel/overview_calculator.rbapp/services/funnel/drilldown_query.rbapp/services/funnel/investigate_query.rbapp/services/funnel/forecast_injector.rbapp/javascript/components/funnel/constants.js (client-side derived rows / Funnel Health bands)The React funnel table calls GET /api/v1/funnel with a set of query params. Api::V1::FunnelController#index renders cached_metrics, which wraps compute_metrics in Rails.cache.fetch (funnel_controller.rb:172-204).
Product routing (compute_metrics, funnel_controller.rb:177-204):
overview → Funnel::OverviewCalculator (sum of Solar + Generators + HVAC), then Funnel::ForecastInjector.inject! adds the lead-gen Forecast column.hvac → Funnel::HvacCalculator (ServiceTitan-sourced; documented separately).solar / generators) → Funnel::MetricsCalculator, then Funnel::RevenueCostsCalculator.inject! adds the NetSuite Revenue row.Params (all whitelisted in the controller; funnel_controller.rb:206-245):
| Param | Method | Validated by | Default |
|---|---|---|---|
| product | product | ProductScopes::ALL_PRODUCTS | overview |
| scheduler | scheduler | ProductScopes.valid_scheduler | all (Web / Call) |
| appt_type | appt_type | ProductScopes.valid_appt_type | all (Sit / Virtual) |
| source_group | source_group | ProductScopes.valid_source_grouping | cac_category |
| region | region_filter | ProductScopes.valid_region | nil (no cross-filter) |
| source | source_filter | ProductScopes.valid_source_category | nil (no cross-filter) |
| start_date | start_date | Date.parse, fallback 2026-01-01 | Jan 1 2026 (F2P year) |
| end_date | end_date | Date.parse, fallback today (Central) | ReportingTimeZone.current_date |
Cache key & expiry (funnel_controller.rb:11-15, 247-250):