Wizard + Dashboard End-to-End Map
Onboarding Bundle for AI/UX Developer
Date: 2026-01-28Purpose: Repository-based reference for AI/UX developer integrating AI Advisor into wizard and dashboard flows
Scope: Report-only, no code changes
1. Wizard Flow Map (UI → API)
Entry Point
Page:dashboard/src/pages/ingestion/index.tsxStore:
dashboard/src/store/useIntakeWizardStore.tsState Machine:
uiStep: 'UPLOAD' | 'PREVIEW' | 'MAP' | 'PREFLIGHT' | 'PROCESSING' | 'COMPLETE' | 'ERROR'
Step-by-Step Flow
Step 1: UPLOAD
- UI Component:
dashboard/src/components/intake/FileDropZone.tsx - API Endpoint:
POST /api/v1/intake/upload - Route Handler:
api/routes/intake.py::upload_file() - Request:
FormDatawithfile: File - Response Schema:
api/schemas/intake.py::BatchPreviewResponse - Gating Logic: None (entry point)
- Error Rendering:
useIntakeWizardStore.errors→ displayed inFileDropZonevia toast/alert - Client Function:
dashboard/src/lib/intakeClient.ts::upload()
Step 2: PREVIEW
- UI Component:
dashboard/src/components/intake/PreviewTable.tsx - API Endpoint: None (uses data from upload response)
- Data Source:
useIntakeWizardStore.headersanduseIntakeWizardStore.previewRows(stored immediately after upload) - Gating Logic: None (auto-advance after upload)
- Error Rendering: Warnings displayed inline, non-blocking
Step 3: MAP
- UI Component:
dashboard/src/components/intake/ColumnMapper.tsx - API Endpoint:
POST /api/v1/intake/{batch_id}/map - Route Handler:
api/routes/intake.py::map_columns() - Request Schema:
api/schemas/intake.py::MappingRequest - Response Schema:
api/schemas/intake.py::MappingValidationResult - Required Canonical Fields: (from
api/routes/intake.py::REQUIRED_CANONICAL_FIELDS)payee_agent_namebusiness_labelmember_idcredit(money field)debit(money field, chargebacks)period(cadence: Monthly/Bi-Weekly/etc.)
- Optional Fields:
total(computed if missing) - Gating Logic: All required fields must be mapped (
areAllRequiredFieldsMapped()) - Error Rendering: Validation errors shown inline, blocks progression until resolved
- Client Function:
dashboard/src/lib/intakeClient.ts::map()
Step 4: PREFLIGHT (Hybrid New Business Policy)
-
UI Component:
dashboard/src/components/intake/PreflightStep.tsx -
API Endpoints:
- Discovery:
POST /api/v1/intake/{batch_id}/discover-businesses- Route Handler:
api/routes/intake.py::discover_businesses() - Request:
{ period_label: string }(YYYY-MM-01) - Response:
{ discovered_count: number; written_count: number; discovery_run_id: string } - Client Function:
dashboard/src/lib/intakeClient.ts::discoverBusinesses()
- Route Handler:
- Preflight Classification:
POST /api/v1/ingestion-wizard/preflight- Route Handler:
api/routes/intake_preflight.py::preflight() - Request Schema:
api/schemas/intake_preflight.py::PreflightRequest - Response Schema:
api/schemas/intake_preflight.py::PreflightResponse - Client Function:
dashboard/src/lib/intakeClient.ts::preflight()
- Route Handler:
- New Business Actions:
POST /api/v1/ingestion-wizard/new-business-actions- Route Handler:
api/routes/intake_preflight.py::submit_new_business_actions() - Request Schema:
api/schemas/intake_preflight.py::NewBusinessActionsRequest - Response Schema:
api/schemas/intake_preflight.py::NewBusinessActionsResponse - Client Function:
dashboard/src/lib/intakeClient.ts::submitNewBusinessActions()
- Route Handler:
- Discovery:
-
Gating Logic:
- Period Label Validation: Must be valid
YYYY-MM-01format (validated inPreflightStep.tsxline 93) - Discovery Materialization: Must run discovery before preflight (409 if not materialized)
- Invariant Checks:
unique_normalized_business_mapping_okmust betrue(blocks processing) - Policy Blocks:
unconfigured_seen_before_policy: 'BLOCK'→ blocks if unconfigured businesses foundnew_discoveredbusinesses require explicit actions (CONFIGURE_NOW,POOL,SUSPENSE,BLOCK)
- Readiness Gate: (Post-processing) Businesses must be configured (agent assignments + PEPM rates) before processing
- Period Label Validation: Must be valid
-
Error Rendering:
- Preflight errors:
useIntakeWizardStore.preflightError→ displayed inPreflightStepcard - Invariant failures: Red alert banner, blocks progression
- Policy blocks: Yellow/red badges, blocks “Process” button
- Processing errors:
useIntakeWizardStore.processingError→ toast notifications
- Preflight errors:
Step 5: PROCESSING
- UI Component:
dashboard/src/components/intake/ProcessingView.tsx - API Endpoint:
POST /api/v1/intake/{batch_id}/process - Route Handler:
api/routes/intake_processor.py::process_batch() - Request Schema:
api/schemas/intake.py::ProcessRequest - Response Schema:
api/schemas/intake.py::ProcessResponse - Gating Logic:
- Batch status must be
MAPPED(409 if alreadyPROCESSED) - Preflight checks must pass (normalization drift invariant, policy compliance, new business decisions)
- Batch status must be
- Error Rendering:
- Processing errors:
useIntakeWizardStore.errors→ displayed inProcessingViewerror card - Row-level errors:
sample_errorsarray shown in results table
- Processing errors:
- Client Function:
dashboard/src/lib/intakeClient.ts::process()
Step 6: COMPLETE
- UI Component:
dashboard/src/components/intake/ProcessingView.tsx(same component, different state) - API Endpoint: None (uses
ProcessResponsefrom processing step) - Data Display: Processing summary (total/accepted/rejected rows, sample errors)
- Error Rendering: Sample errors displayed in expandable table
2. Dashboard + NI Data Map
Dashboard Pages and Endpoints
CEO Dashboard (dashboard/src/pages/ceo/index.tsx)
-
Growth/Loss Summary:
GET /api/v1/growth-loss- Route Handler:
api/routes/dashboard.py::get_growth_loss_endpoint() - Data Source:
api/bigquery/queries.py::get_growth_loss_summary()→ queriespayroll_analytics.business_growth_lossview (Stage 1 derived) - Response Shape:
- Route Handler:
-
Growth/Loss Details:
GET /api/v1/growth-loss-details- Route Handler:
api/routes/dashboard.py::get_growth_loss_details_endpoint() - Data Source:
api/bigquery/queries.py::get_growth_loss_details()→ queriespayroll_analytics.business_growth_lossview (Stage 1 derived) - Response Shape:
- Route Handler:
-
Top Businesses:
GET /api/v1/top-businesses- Route Handler:
api/routes/dashboard.py::get_top_businesses_endpoint() - Data Source:
api/bigquery/queries.py::get_top_businesses_from_view()→ queriespayroll_analytics.business_growth_lossview (Stage 1 derived) - Supports:
period_type: 'ytd' | 'qtd'for aggregation
- Route Handler:
-
Top Agents:
GET /api/v1/top-agents- Route Handler:
api/routes/dashboard.py::get_top_agents_endpoint() - Data Source:
api/bigquery/queries.py::get_top_agents_from_view()→ queriespayroll_analytics.agent_report_v5view (Stage 3+ derived) - Supports:
period_type: 'ytd' | 'qtd'for aggregation
- Route Handler:
-
Agent Performance:
GET /api/v1/agents/performance- Route Handler:
api/routes/dashboard.py::get_agent_performance_endpoint() - Data Source:
api/bigquery/queries.py::get_agent_performance_summary()→ queriespayroll_analytics.agent_report_v5view (Stage 3+ derived)
- Route Handler:
Agent Dashboard (dashboard/src/pages/agent/index.tsx)
-
Agent Detail:
GET /api/v1/agent/{agent_name}/detail- Route Handler:
api/routes/agent_dashboard.py::get_agent_detail() - Data Source:
api/bigquery/queries.py::get_agent_commission_range(),get_agent_commission_by_business(),get_agent_summary_stats()→ queriespayroll_analytics.agent_report_v5view (Stage 3+ derived) - RBAC: Agents can only access their own data (403 if unauthorized)
- Response Shape:
- Route Handler:
-
Agent Stage 1 Detail:
GET /api/v1/agent/{agent_name}/stage1/detail- Route Handler:
api/routes/agent_dashboard.py::get_agent_stage1_detail_api() - Data Source:
api/bigquery/queries.py::get_agent_stage1_detail()→ queriespayroll_analytics_raw.stage1_bridge_rows(Stage 1) - Hardcoded Filter: Only shows rows where
payee_agent_id = 721995(Robin Bundy) + agent-scoped via Stage 3 business mapping - Response Shape: Paginated row-level detail with PII masking
- Route Handler:
-
Agent Stage 1 Export:
GET /api/v1/agent/{agent_name}/stage1/export- Route Handler:
api/routes/agent_dashboard.py::export_agent_stage1_detail() - Data Source: Same as stage1 detail, returns CSV/XLSX
- Route Handler:
-
Agent Portfolio Summary:
GET /api/v1/agent/portfolio-summary- Route Handler:
api/routes/agent_dashboard.py::get_portfolio_summary() - Data Source:
api/bigquery/queries.py::get_agent_metrics_range()→ hybrid query usingagent_report_v5(Stage 3+) +stage1_snapshots(Stage 1) for employee counts
- Route Handler:
-
Agent KPIs:
GET /api/v1/agents/{agent_name}/kpi-metrics- Route Handler:
api/routes/agents.py::get_agent_kpi_metrics() - Data Source:
api/bigquery/queries.py::get_agent_kpi_metrics()→ queriespayroll_analytics.agent_report_v5view (Stage 3+ derived)
- Route Handler:
Data Source Layer Summary
| Endpoint | Data Source | Stage |
|---|---|---|
/api/v1/growth-loss | business_growth_loss view | Stage 1 derived |
/api/v1/growth-loss-details | business_growth_loss view | Stage 1 derived |
/api/v1/top-businesses | business_growth_loss view | Stage 1 derived |
/api/v1/top-agents | agent_report_v5 view | Stage 3+ derived |
/api/v1/agent/{name}/detail | agent_report_v5 view | Stage 3+ derived |
/api/v1/agent/{name}/stage1/detail | stage1_bridge_rows table | Stage 1 |
/api/v1/agent/{name}/stage1/export | stage1_bridge_rows table | Stage 1 |
/api/v1/agent/portfolio-summary | Hybrid (agent_report_v5 + stage1_snapshots) | Stage 1 + Stage 3+ |
/api/v1/agents/{name}/kpi-metrics | agent_report_v5 view | Stage 3+ derived |
- Stage 1:
payroll_analytics_raw.stage1_bridge_rows,payroll_analytics_raw.stage1_snapshots - Stage 3+:
payroll_analytics.agent_report_v5(normalized commissions) - Derived Views:
payroll_analytics.business_growth_loss(computed from Stage 1 snapshots)
3. Error Contract + Taxonomy
Standard Error Payload Shape
FastAPI HTTPException Format:detail is dict):
api/utils/error_redaction.py sanitizes BigQuery errors, removes table/column names, preserves trace_id for log correlation.
Key Wizard-Blocking Errors
DiscoveryNotMaterialized (409 CONFLICT)
- Location:
api/routes/intake_preflight.py::preflight()line 414 - Condition: Preflight called before discovery step completes
- Message:
{"error": "DiscoveryNotMaterialized", "message": "...", "batch_id": "...", "period_label": "..."} - User Action: Must run discovery (
POST /api/v1/intake/{batch_id}/discover-businesses) first - AI Safe: ✅ Yes (explain workflow step)
BatchMetadataNotFound (404 NOT_FOUND)
- Location:
api/routes/intake_processor.py::process_batch()line 884-891 - Condition: Stage 1 bridge rows query fails due to missing batch metadata
- Message:
{"error": "BatchMetadataNotFound", "trace_id": "...", "batch_id": "...", "tenant_id": "..."} - User Action: Re-upload file or contact support
- AI Safe: ⚠️ Partial (can explain retry, but don’t speculate on root cause)
PeriodLabelRequired (400/422 BAD_REQUEST)
- Location:
api/routes/intake_processor.py::_derive_period_label()line 213-215 - Condition:
period_labelmissing from wizard input (no longer mapped from columns) - Message:
"period_label required as wizard input (YYYY-MM-01 format). Period Label is no longer mapped from file columns." - User Action: Enter valid
YYYY-MM-01period label in wizard UI - AI Safe: ✅ Yes (explain format requirement)
ServiceUnavailable (503 SERVICE_UNAVAILABLE)
- Location: Multiple (BigQuery unavailable/query failed)
api/routes/intake.py::upload_file()line 210api/routes/intake.py::map_columns()line 335api/routes/intake_processor.py::process_batch()line 588, 832, 907
- Condition: BigQuery client unavailable or query failed (detected via
RuntimeErrorwith"BIGQUERY_UNAVAILABLE"or"BIGQUERY_QUERY_FAILED"in message) - Message:
"Service temporarily unavailable"or{"error": "ServiceUnavailable", "trace_id": "...", "batch_id": "..."} - User Action: Retry after delay, contact support if persistent
- AI Safe: ✅ Yes (explain retry strategy)
Normalization Drift Invariant Failed (400 BAD_REQUEST)
- Location:
api/routes/intake_processor.py::_check_preflight_requirements()line 270-273 - Condition:
_check_normalization_drift_invariant()detects inconsistent business name mapping - Message:
{"error": "Normalization drift invariant failed", "errors": [...]} - User Action: Fix business name mappings in onboarding, re-run preflight
- AI Safe: ⚠️ Partial (can explain the concept, but don’t suggest specific fixes without context)
Unresolved New Discovered Businesses (400 BAD_REQUEST)
- Location:
api/routes/intake_processor.py::_check_preflight_requirements()line 349-352 - Condition:
new_discoveredbusinesses exist without decisions logged - Message:
{"error": "Unresolved new_discovered businesses", "business_ids": [...]} - User Action: Submit new business actions via preflight UI
- AI Safe: ✅ Yes (explain workflow step)
Policy BLOCK: Unconfigured Seen Before (400 BAD_REQUEST)
- Location:
api/routes/intake_processor.py::_check_preflight_requirements()line 366-369 - Condition:
unconfigured_seen_before_policy: 'BLOCK'and unconfigured businesses found - Message:
{"error": "Policy BLOCK: unconfigured_seen_before businesses found", "business_ids": [...]} - User Action: Configure businesses in onboarding page, or change policy to
POOL/SUSPENSE - AI Safe: ✅ Yes (explain policy options)
Error Rendering Locations
- Wizard Errors:
dashboard/src/components/intake/PreflightStep.tsx,ProcessingView.tsx→ toast notifications + inline alerts - Dashboard Errors:
dashboard/src/pages/ceo/index.tsx,agent/index.tsx→ error states in cards/tables, toast notifications - API Client Errors:
dashboard/src/lib/apiClient.ts,intakeClient.ts→ converted toApiErrorclass, handled by components
AI Safety Classification
| Error Type | AI Explanation Safe? | Notes |
|---|---|---|
| DiscoveryNotMaterialized | ✅ Yes | Explain workflow step |
| BatchMetadataNotFound | ⚠️ Partial | Explain retry, don’t speculate root cause |
| PeriodLabelRequired | ✅ Yes | Explain format requirement |
| ServiceUnavailable | ✅ Yes | Explain retry strategy |
| Normalization Drift | ⚠️ Partial | Explain concept, don’t suggest fixes without context |
| Unresolved New Businesses | ✅ Yes | Explain workflow step |
| Policy BLOCK | ✅ Yes | Explain policy options |
- HTTP status codes (400, 404, 409, 503)
- Error codes (
DiscoveryNotMaterialized,BatchMetadataNotFound, etc.) - Trace IDs (for log correlation)
- User-facing messages (can be paraphrased for clarity)
- Workflow guidance (can suggest next steps)
- Format requirements (can explain validation rules)
4. AI Advisor Insertion Points (Safe)
Wizard UI Components (Read-Only Observation)
Recommended Insertion Points:
-
PreflightStep.tsx (
dashboard/src/components/intake/PreflightStep.tsx)- Location: Sidebar panel or floating panel
- Observes:
useIntakeWizardStore.preflightData(classification results)useIntakeWizardStore.periodLabeluseIntakeWizardStore.batchId- Policy summary (
policy.unconfigured_seen_before_policy,policy.new_business_policy) - Classification counts (
configured_ok.length,new_discovered.length, etc.)
- Safe Actions: Explain classification, suggest actions, explain policy implications
- NO-GO: Cannot mutate
actionSelections, cannot callsubmitNewBusinessActions()directly
-
ColumnMapper.tsx (
dashboard/src/components/intake/ColumnMapper.tsx)- Location: Inline helper panel below mapping table
- Observes:
useIntakeWizardStore.headers(file headers)useIntakeWizardStore.mapping(current mappings)useIntakeWizardStore.requiredFields- Validation errors
- Safe Actions: Suggest mappings based on header names, explain field requirements
- NO-GO: Cannot call
updateMapping()orsubmitMapping()directly
-
ProcessingView.tsx (
dashboard/src/components/intake/ProcessingView.tsx)- Location: Results summary panel
- Observes:
useIntakeWizardStore.processingResult(row counts, sample errors)useIntakeWizardStore.errors
- Safe Actions: Explain error patterns, suggest fixes for common errors
- NO-GO: Cannot retry processing, cannot mutate batch state
-
Ingestion Page (
dashboard/src/pages/ingestion/index.tsx)- Location: Global sidebar (persists across steps)
- Observes:
useIntakeWizardStore.uiStep(current step)useIntakeWizardStore.backendStatus- All store state (read-only)
- Safe Actions: Provide step-by-step guidance, explain current state, answer questions
- NO-GO: Cannot advance/retreat steps, cannot trigger API calls
Dashboard UI Components (Read-Only Observation)
Recommended Insertion Points:
-
CEO Dashboard (
dashboard/src/pages/ceo/index.tsx)- Location: Right sidebar (similar to existing
AIAssistantcomponent, line 90-93) - Observes:
ExecutiveDashboardData(growth/loss, top businesses, top agents, churn)- Period selection (
selectedPeriod,periodType)
- Safe Actions: Explain trends, answer “why” questions, suggest focus areas
- NO-GO: Cannot mutate period selection, cannot trigger data refresh
- Location: Right sidebar (similar to existing
-
Agent Dashboard (
dashboard/src/pages/agent/index.tsx)- Location: Right sidebar (similar to existing
AIAssistantcomponent, line 37-40) - Observes:
AgentDashboardData(commissions, trends, top businesses, KPIs)- Period selection (
selectedPeriod,periodType)
- Safe Actions: Explain performance metrics, suggest improvement areas, answer questions
- NO-GO: Cannot mutate period selection, cannot trigger data refresh
- Location: Right sidebar (similar to existing
-
Agent Detail (
dashboard/src/components/AgentDetail.tsx)- Location: Inline panel within detail view
- Observes:
- Agent detail response (
monthly_breakdown,business_breakdown,summary_stats) - Period range (
start,end)
- Agent detail response (
- Safe Actions: Explain commission trends, business performance, answer questions
- NO-GO: Cannot change period range, cannot trigger exports
NO-GO Zones (Math, Writes, Inference)
Mathematical Calculations:
- ❌ Commission Calculations: Do not compute commissions, PEPM rates, or percentages (use API data only)
- ❌ Aggregations: Do not sum/average API responses (trust backend calculations)
- ❌ Trend Calculations: Do not compute deltas or growth rates (use API-provided metrics)
Write Operations:
- ❌ API Mutations: Do not call
submitMapping(),submitNewBusinessActions(),startProcessing(), etc. - ❌ State Mutations: Do not call
useIntakeWizardStoreactions (only read state) - ❌ Configuration Changes: Do not modify business configs, agent assignments, or policies
Inference/Guessing:
- ❌ Data Quality: Do not infer data quality issues without explicit error codes
- ❌ Root Causes: Do not speculate on BigQuery/internal errors (refer to trace_id)
- ❌ Business Logic: Do not suggest policy changes or configuration without user context
Safe Patterns
✅ Read-Only State Observation:5. Minimal File List (Read-Only vs Write)
Write Access (AI Dev Can Modify)
Dashboard UI Components:dashboard/src/components/intake/**/*.tsx(wizard components)dashboard/src/pages/ingestion/index.tsx(wizard page)dashboard/src/pages/ceo/index.tsx(CEO dashboard)dashboard/src/pages/agent/index.tsx(agent dashboard)dashboard/src/components/AgentDetail.tsx(agent detail component)dashboard/src/components/**/*.tsx(shared UI components, if needed for AI Advisor UI)
dashboard/src/store/useIntakeWizardStore.ts(read state only, do not add actions)
dashboard/src/lib/intakeClient.ts(understand API contracts, do not modify)dashboard/src/lib/apiClient.ts(understand API contracts, do not modify)
Read-Only Access (Reference Only)
API Routes (Understand Contracts):api/routes/intake.py(upload, map, discover endpoints)api/routes/intake_processor.py(process endpoint)api/routes/intake_preflight.py(preflight, new-business-actions endpoints)api/routes/dashboard.py(growth-loss, top-agents, top-businesses endpoints)api/routes/agent_dashboard.py(agent detail, portfolio-summary, stage1 endpoints)api/routes/agents.py(agent KPIs, trends endpoints)
api/schemas/intake.py(BatchPreviewResponse, MappingRequest, ProcessRequest, ProcessResponse)api/schemas/intake_preflight.py(PreflightRequest, PreflightResponse, NewBusinessActionsRequest)api/schemas/business_onboarding.py(BusinessOnboardingListItem, etc., if referenced)
api/utils/error_redaction.py(understand error sanitization, trace_id generation)
docs/STAGE1_CERTIFICATION.md(understand data pipeline stages)
Excluded (Do Not Access)
Backend Implementation Details:api/bigquery/**/*.py(SQL queries, BigQuery client logic) - Unless needed for explanation onlyapi/services/**/*.py(business logic services)api/engine/**/*.py(calculation engine, if exists)api/config/**/*.py(configuration, unless needed for understanding env vars)
**/*.sql(BigQuery SQL files) - Unless needed for explanation only
api/tests/**/*.py(backend tests)dashboard/tests/**/*.tsx(frontend tests)
api/Dockerfile,cloudbuild*.yaml(deployment configs).github/**(CI/CD workflows)
File Access Summary
| Category | Path Pattern | Access Level | Notes |
|---|---|---|---|
| Wizard UI | dashboard/src/components/intake/** | ✅ Write | Can add AI Advisor components |
| Dashboard Pages | dashboard/src/pages/{ingestion,ceo,agent}/** | ✅ Write | Can integrate AI Advisor |
| Store | dashboard/src/store/useIntakeWizardStore.ts | ⚠️ Read-Only | Read state, don’t add actions |
| API Routes | api/routes/{intake*,dashboard*,agent*}.py | 📖 Read-Only | Understand contracts |
| API Schemas | api/schemas/**/*.py | 📖 Read-Only | Type definitions |
| Error Utils | api/utils/error_redaction.py | 📖 Read-Only | Error handling patterns |
| BigQuery Queries | api/bigquery/**/*.py | ❌ Excluded | Unless explanation-only |
| SQL Files | **/*.sql | ❌ Excluded | Unless explanation-only |
| Tests | {api,dashboard}/tests/** | ❌ Excluded | Not needed for UI work |
| Infrastructure | Dockerfile, cloudbuild*.yaml | ❌ Excluded | Deployment configs |
Summary
This document provides a comprehensive map of:- Wizard Flow: 6-step process from upload to completion, with API endpoints, request/response shapes, and gating logic
- Dashboard Endpoints: CEO and Agent dashboards with data source mapping (Stage 1 vs Stage 3+)
- Error Taxonomy: Standard error payloads, wizard-blocking errors, and AI safety classifications
- AI Advisor Insertion Points: Safe locations for read-only observation, with explicit NO-GO zones
- File Access Control: Write access for UI components, read-only for API contracts, excluded for implementation details
- Read-Only Observation: AI Advisor observes state/API responses, never mutates
- No Math/Writes/Inference: Trust backend calculations, don’t mutate state, don’t speculate on root causes
- Deterministic Errors: Preserve exact error codes and trace_ids for log correlation
- Workflow Guidance: Explain steps and suggest actions, but don’t execute them
Document Version: 1.0
Last Updated: 2026-01-28
Maintained By: Senior QA Engineer