Dashboard BigQuery Integration Playbook
Date Created: 2025-10-20Purpose: Step-by-step guide to connect dashboard views to live BigQuery data with correct commission calculations
Overview
This playbook documents the process of migrating a dashboard from mock/fallback data to live BigQuery data. It was successfully applied to the CEO dashboard and can be replicated for Agent, Admin, and other dashboard views.Key Success Criteria
- ✅ Dashboard pulls real-time data from BigQuery
- ✅ Commission calculations match canonical business logic
- ✅ Historical data (2024+) is accessible
- ✅ No hardcoded fallbacks or mock data
- ✅ Proper error handling and logging
- ✅ TypeScript type safety maintained
Phase 1: Understand the Current State
1.1 Identify Data Sources
Questions to answer:- Where is the dashboard currently getting data? (Mock data, CSV files, old BigQuery views?)
- What BigQuery views/tables exist for this dashboard?
- What is the canonical data model and calculation logic?
1.2 Document Canonical Calculations
Example from CEO Dashboard:- Owner Commission = Gross Payout - Chargebacks - Agent Commissions
- NOT a simple 20/80 split of gross
stage4_outputs/export_excel.py- Contains authoritative calculation logicENHANCED_CHURN_WORKBOOK_CANONICAL_SPEC.md- Business logic documentation- Existing Excel reports - Reverse engineer if needed
1.3 Check API Logs
Phase 2: Fix the BigQuery View
2.1 Review Current View Schema
2.2 Identify Incorrect Calculations
Common Issues:- ❌ Hardcoded date filters (e.g.,
WHERE period_label >= '2025-01-01') - ❌ Incorrect commission formulas (e.g.,
gross_payout * 0.2) - ❌ Missing fields needed by API
- ❌ Wrong table joins or filters
2.3 Update View to Provide Raw Data
Principle: Views should provide raw aggregated data; API should perform business logic calculations.2.4 Deploy Updated View
Phase 3: Update API Backend Logic
3.1 Locate the Data Fetching Function
Common locations:api/routes/<dashboard>_metrics.py- FastAPI endpointapi/bigquery/queries.py- BigQuery query functionsmain.py- Legacy endpoints (check for duplicates!)
api/bigquery/queries.py::get_ceo_metrics()- Not being used ❌main.py::get_ceo_metrics_simple()- Actually being called ✅
3.2 Fix Query to Use Correct View
Before:3.3 Implement Canonical Calculation Logic
Multi-Query Approach for Complex Calculations:YTD/QTD Query Patterns (Stage 10)
Overview
YTD (Year-to-Date) and QTD (Quarter-to-Date) queries aggregate data across multiple periods instead of a single period. The implementation uses a hybrid query approach that optimizes performance by combining pre-aggregated views with raw data queries:- Financial metrics: Query
ceo_snapshotview (can SUM pre-aggregated values for faster queries) - Distinct counts: Query
stage1_snapshotsdirectly (must query raw data for accurate distinct counts) - Active businesses: Query
stage1_snapshotsfor end period only (shows current state)
YTD Query Pattern
Purpose: Aggregate data from January 1 of the year to the selected period. Implementation: Uses three separate queries that are merged: Query 1a: Financial Metrics (fromceo_snapshot view)
stage1_snapshots)
stage1_snapshots)
- For
period_label = '2025-10-01':start_date=2025-01-01(year start)end_date=2025-10-01(selected period)
- Aggregates all data from January through October 2025
QTD Query Pattern
Purpose: Aggregate data from the start of the current quarter to the selected period. Implementation: Uses the same three-query approach as YTD, but with different date range calculation: Date Range Calculation:- For
period_label = '2025-10-01':start_date=2025-10-01(Q4 start, since October is the first month of Q4)end_date=2025-10-01(selected period)
- For
period_label = '2025-11-01':start_date=2025-10-01(Q4 start)end_date=2025-11-01(selected period)
- Aggregates all data from the start of the quarter through the selected period
Performance Considerations
Why Hybrid Approach?- Financial metrics from view: Pre-aggregated values can be summed efficiently, reducing query complexity
- Distinct counts from raw data: Must query
stage1_snapshotsdirectly to get accurateCOUNT(DISTINCT ...)across the date range - Active businesses query: Separate query for end period ensures we get the correct current state
- Financial metrics query is fast (pre-aggregated view)
- Distinct counts query is slower but necessary for accuracy
- Consider partitioning on
period_labelfor better performance on date range queries - Cache results for frequently accessed periods
Month-over-Month Delta Queries
Overview
The dashboard displays month-over-month delta indicators for all KPI cards, showing how metrics compare to previous periods. Delta values are calculated in the backend using_calculate_previous_period_range() helper function.
Previous Period Calculation Logic
Implementation:api/bigquery/queries.py - _calculate_previous_period_range()
Month View (MTD):
- Previous period: Previous month
- Example: October 2025 → September 2025
- Comparison type:
"month"
- Previous period: Previous quarter
- Example: Q4 2025 (Oct-Dec) → Q3 2025 (Jul-Sep)
- Comparison type:
"quarter"
- Previous period: Previous year YTD (same date range in previous year)
- Example: Jan-Oct 2025 → Jan-Oct 2024
- Comparison type:
"year"
Delta Field Definitions
All delta fields are optional and may benull/undefined/0:
| Field | Type | Description | Example |
|---|---|---|---|
delta_gross_payout | Decimal | Change in gross payout | +$3,120.00 |
delta_total_businesses | Integer | Change in business count | +15 |
delta_total_employees | Integer | Change in employee count | +39 |
delta_agent_commissions | Decimal | Change in agent commissions | +$1,157.24 |
delta_chargebacks | Decimal | Change in chargebacks | -$500.00 |
previous_period_label | String | Human-readable previous period | ”September 2025” |
comparison_type | String | Type of comparison | ”month”, “quarter”, or “year” |
Query Pattern for Previous Period
Backend Implementation:get_ceo_metrics_range() function
-
Calculate Previous Period Range:
-
Query Previous Period Metrics:
-
Calculate Deltas:
Single Month Delta Calculation
For single month periods (period_type=None), the backend leverages existing MoM fields from ceo_snapshot view:
Edge Case Handling
January (No Previous Month):prev_start_dateandprev_end_datereturnNone- Delta fields set to
0 previous_period_labelisNone- Tooltip not shown, but delta still displayed as
0
- Previous quarter calculation goes back 3 months
- If result is before
MIN_DATA_DATE(2024-01-01), returnsNone - Same fallback behavior as January
- Previous year YTD calculation results in date before
MIN_DATA_DATE - Returns
Nonefor previous period - Delta fields set to
0
Validation Examples (October 2025)
Month View:- Current: October 2025
- Previous: September 2025
- Expected deltas:
delta_gross_payout: +$3,429.06delta_total_businesses: -9delta_total_employees: -253delta_agent_commissions: +$3,251.96
- Current: Q4 2025 (October only, first month)
- Previous: Q3 2025 (Jul-Sep)
- Comparison: Quarter-over-quarter
- Current: Jan-Oct 2025
- Previous: Jan-Oct 2024
- Comparison: Year-over-year
Response Format
The API response includes both aggregated and end-period metrics:Validation Results (October 2025)
Single Month (period_type=null):
total_businesses_ytd=active_businesses= 96 (same period)
period_type=qtd):
- For October (first month of Q4):
total_businesses_ytd=active_businesses= 96 (equal for first month) - For November:
total_businesses_ytd>active_businesses(aggregating Oct-Nov)
period_type=ytd):
total_businesses_ytd= 221 (distinct across Jan-Oct)active_businesses= 96 (distinct at October end)total_businesses_ytd>active_businesses(always true for YTD with multiple months AND tenant_id = @tenant_id AND payee_agent_id IN (721995, 668078, 0) AND business_label IS NOT NULL AND business_label != ” GROUP BY tenant_id
3.5 Remove Forced Mock Data
Check for:Phase 4: Update Frontend Dashboard
4.1 Review Type Definitions
4.2 Update Period Selector for Historical Data
4.3 Remove or Flag Hardcoded Fallbacks
4.4 Fix TypeScript Type Errors
Common issues:4.5 Update API Client URL
Phase 5: Configure Cloud Run Permissions
5.1 Check Service Account
5.2 Grant BigQuery Permissions
5.3 Set Environment Variables
Phase 6: Deploy and Validate
6.1 Deploy API
6.2 Test API Directly
6.3 Check API Logs
6.4 Deploy Frontend
6.5 Validate Dashboard End-to-End
Manual testing checklist:- Dashboard loads without errors
- Can select 2024 periods
- Can select 2025 periods
- Data matches BigQuery direct query results
- No “No data available” errors
- Commission calculations are correct
- No console errors in browser DevTools
Phase 7: Clean Up and Document
7.1 Remove Mock Data Functions (Optional)
7.2 Update API Documentation
7.3 Create Checkpoint Document
Agent Dashboard Adaptation Guide
Key Differences for Agent Dashboard
| Aspect | CEO Dashboard | Agent Dashboard (Anticipated) |
|---|---|---|
| BigQuery View | payroll_analytics.ceo_snapshot | payroll_analytics.agent_performance |
| Aggregation Level | Company-wide totals | Per-agent metrics |
| Key Metrics | Owner commission, business count | Agent commission, client count, performance rank |
| Filters | payee_agent_id IN (721995, 668078) | payee_agent_id = <specific_agent> |
| Calculation | Owner = Gross - Chargebacks - Agent | Agent commission from stage3 directly |
Agent View Checklist
Troubleshooting Guide
Issue: “Using mock data” in logs
Cause: BigQuery client not initialized or query failingFix:
- Check
GCP_PROJECT_IDenvironment variable is set - Verify service account has BigQuery permissions
- Check for
client = Noneforcing mock mode
Issue: “No data found for period”
Cause: Data not in BigQuery or incorrect date filterFix:
- Verify data exists:
bq query "SELECT * FROM table WHERE period_label = '2024-03-01'" - Check date format (YYYY-MM-01 vs YYYY-MM)
- Verify period_label filters in view match data format
Issue: “TypeError: unsupported operand type(s) for +: ‘int’ and ‘NoneType’”
Cause: None values not handled in calculationsFix:
Issue: TypeScript build fails with type errors
Cause: Mismatch between API schema and frontend typesFix:
- Check
dashboard/src/lib/api-client.tsfor type definitions - Ensure all assigned fields exist in type
- Convert number to string if schema expects string:
.toString()
Issue: Dashboard shows old data after deployment
Cause: Frontend or API not redeployed with latest codeFix:
- Verify latest commit is deployed: check Vercel dashboard
- Hard refresh browser: Ctrl+Shift+R (Windows) / Cmd+Shift+R (Mac)
- Check API URL points to latest Cloud Run revision
Reference Files
Key Files Modified (CEO Dashboard Example)
Canonical Calculation References
stage4_outputs/export_excel.py- Lines 210-211 (Owner commission formula)ENHANCED_CHURN_WORKBOOK_CANONICAL_SPEC.md- Business logic documentation
Success Metrics
CEO Dashboard - Validated Results:- March 2024: 33 businesses, 484 employees, 2,988.06 owner commission ✅
- March 2025: 76 businesses, 1,548 employees, 14,111.79 owner commission ✅
- Agent-specific data loads correctly for 2024-2025 periods
- Commission calculations match Excel/Python export logic
- No mock data warnings in production logs
- TypeScript builds without errors
- Dashboard responsive and performant
Next Steps
- Agent Dashboard: Follow this playbook to connect agent views to BigQuery
- Admin Dashboard: Adapt for system-wide analytics and reporting
- Monitoring: Set up alerts for BigQuery query failures or mock data fallbacks
- Performance: Consider caching strategies for frequently accessed periods
- Testing: Add automated tests to verify calculation logic remains correct
Document Version: 1.0
Last Updated: 2025-10-20
Maintained By: Development Team
Related Documents:
BIGQUERY_IMPLEMENTATION_COMPLETE.mdENHANCED_CHURN_WORKBOOK_CANONICAL_SPEC.mdDASHBOARD_LOGIC.md