Skip to main content

Wizard + Dashboard End-to-End Map

Onboarding Bundle for AI/UX Developer

Date: 2026-01-28
Purpose: 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.tsx
Store: dashboard/src/store/useIntakeWizardStore.ts
State 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: FormData with file: File
  • Response Schema: api/schemas/intake.py::BatchPreviewResponse
    {
      batch_id: string;  // UUID
      headers: string[];  // File column headers
      sample_rows: Record<string, string>[];  // First 5 rows
      warnings: string[];  // CSV injection warnings
    }
    
  • Gating Logic: None (entry point)
  • Error Rendering: useIntakeWizardStore.errors → displayed in FileDropZone via 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.headers and useIntakeWizardStore.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
    {
      column_mapping: Record<string, string>;  // canonical -> file header
    }
    
  • Response Schema: api/schemas/intake.py::MappingValidationResult
    {
      is_valid: boolean;
      errors: string[];
      mapped_preview: Record<string, string>[];
    }
    
  • Required Canonical Fields: (from api/routes/intake.py::REQUIRED_CANONICAL_FIELDS)
    • payee_agent_name
    • business_label
    • member_id
    • credit (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:
    1. 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()
    2. Preflight Classification: POST /api/v1/ingestion-wizard/preflight
      • Route Handler: api/routes/intake_preflight.py::preflight()
      • Request Schema: api/schemas/intake_preflight.py::PreflightRequest
        {
          batch_id: string;
          period_label: string;  // YYYY-MM-01, required wizard input
        }
        
      • Response Schema: api/schemas/intake_preflight.py::PreflightResponse
        {
          period_label: string;
          tenant_id: string;
          org_id?: string | null;
          batch_id: string;
          policy: PolicySummary;
          configured_ok: BusinessClassificationItem[];
          owner_rollup_ok?: BusinessClassificationItem[];
          unconfigured_seen_before: BusinessClassificationItem[];
          new_discovered: BusinessClassificationItem[];
          missing_new_business_decisions: BusinessClassificationItem[];
          resolved_new_business_decisions: BusinessClassificationItem[];
          invariants: InvariantCheckResult;
          hash: string;
        }
        
      • Client Function: dashboard/src/lib/intakeClient.ts::preflight()
    3. 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
        {
          batch_id: string;
          period_label: string;
          actions: NewBusinessActionItem[];
        }
        
      • Response Schema: api/schemas/intake_preflight.py::NewBusinessActionsResponse
        {
          batch_id: string;
          period_label: string;
          decisions_logged: number;
          decision_ids: string[];
        }
        
      • Client Function: dashboard/src/lib/intakeClient.ts::submitNewBusinessActions()
  • Gating Logic:
    • Period Label Validation: Must be valid YYYY-MM-01 format (validated in PreflightStep.tsx line 93)
    • Discovery Materialization: Must run discovery before preflight (409 if not materialized)
    • Invariant Checks: unique_normalized_business_mapping_ok must be true (blocks processing)
    • Policy Blocks:
      • unconfigured_seen_before_policy: 'BLOCK' → blocks if unconfigured businesses found
      • new_discovered businesses require explicit actions (CONFIGURE_NOW, POOL, SUSPENSE, BLOCK)
    • Readiness Gate: (Post-processing) Businesses must be configured (agent assignments + PEPM rates) before processing
  • Error Rendering:
    • Preflight errors: useIntakeWizardStore.preflightError → displayed in PreflightStep card
    • Invariant failures: Red alert banner, blocks progression
    • Policy blocks: Yellow/red badges, blocks “Process” button
    • Processing errors: useIntakeWizardStore.processingError → toast notifications

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
    {
      period_label: string;  // YYYY-MM-01, required wizard input
    }
    
  • Response Schema: api/schemas/intake.py::ProcessResponse
    {
      batch_id: string;
      tenant_id: string;
      previous_status: string;
      new_status: string;  // Always 'PROCESSED'
      total_rows: number;
      accepted_rows: number;
      rejected_rows: number;
      sample_errors: Array<{ row_index: number; error_codes: string[] }>;
      processed_at: string;  // ISO datetime
    }
    
  • Gating Logic:
    • Batch status must be MAPPED (409 if already PROCESSED)
    • Preflight checks must pass (normalization drift invariant, policy compliance, new business decisions)
  • Error Rendering:
    • Processing errors: useIntakeWizardStore.errors → displayed in ProcessingView error card
    • Row-level errors: sample_errors array shown in results table
  • 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 ProcessResponse from 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() → queries payroll_analytics.business_growth_loss view (Stage 1 derived)
    • Response Shape:
      {
        summary: {
          gained_employees: number;
          lost_employees: number;
          net_employee_change: number;
          pct_employee_change: number;
        };
        businesses: Array<{
          business: string;
          gained: number;
          lost: number;
          net: number;
          pctChange: number;
        }>;
      }
      
  • 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() → queries payroll_analytics.business_growth_loss view (Stage 1 derived)
    • Response Shape:
      {
        growth: Array<{
          business_name: string;
          current_employees: number;
          net_employee_change: number;
          employee_change_pct: number;
        }>;
        loss: Array<{...}>;  // Same shape
      }
      
  • 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() → queries payroll_analytics.business_growth_loss view (Stage 1 derived)
    • Supports: period_type: 'ytd' | 'qtd' for aggregation
  • 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() → queries payroll_analytics.agent_report_v5 view (Stage 3+ derived)
    • Supports: period_type: 'ytd' | 'qtd' for aggregation
  • 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() → queries payroll_analytics.agent_report_v5 view (Stage 3+ derived)

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() → queries payroll_analytics.agent_report_v5 view (Stage 3+ derived)
    • RBAC: Agents can only access their own data (403 if unauthorized)
    • Response Shape:
      {
        agent_name: string;
        start_period: string;
        end_period: string;
        monthly_breakdown: Array<{...}>;
        business_breakdown: Array<{...}>;
        summary_stats: {...};
        freshness: {...};
      }
      
  • 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() → queries payroll_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
  • 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
  • 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 using agent_report_v5 (Stage 3+) + stage1_snapshots (Stage 1) for employee counts
  • 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() → queries payroll_analytics.agent_report_v5 view (Stage 3+ derived)

Data Source Layer Summary

EndpointData SourceStage
/api/v1/growth-lossbusiness_growth_loss viewStage 1 derived
/api/v1/growth-loss-detailsbusiness_growth_loss viewStage 1 derived
/api/v1/top-businessesbusiness_growth_loss viewStage 1 derived
/api/v1/top-agentsagent_report_v5 viewStage 3+ derived
/api/v1/agent/{name}/detailagent_report_v5 viewStage 3+ derived
/api/v1/agent/{name}/stage1/detailstage1_bridge_rows tableStage 1
/api/v1/agent/{name}/stage1/exportstage1_bridge_rows tableStage 1
/api/v1/agent/portfolio-summaryHybrid (agent_report_v5 + stage1_snapshots)Stage 1 + Stage 3+
/api/v1/agents/{name}/kpi-metricsagent_report_v5 viewStage 3+ derived
Key Tables/Views:
  • 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:
HTTPException(
    status_code: int,
    detail: str | dict  # Can be string or structured dict
)
Structured Error Response (when detail is dict):
{
  error?: string;  // Error code (e.g., "DiscoveryNotMaterialized", "BatchMetadataNotFound")
  message?: string;  // Human-readable message
  trace_id?: string;  // UUID for log correlation (generated by api/utils/error_redaction.py::generate_trace_id())
  batch_id?: string;  // Batch identifier (when applicable)
  period_label?: string;  // Period label (when applicable)
  // ... other context fields
}
Error Redaction: 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_label missing 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-01 period 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 210
    • api/routes/intake.py::map_columns() line 335
    • api/routes/intake_processor.py::process_batch() line 588, 832, 907
  • Condition: BigQuery client unavailable or query failed (detected via RuntimeError with "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_discovered businesses 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 to ApiError class, handled by components

AI Safety Classification

Error TypeAI Explanation Safe?Notes
DiscoveryNotMaterialized✅ YesExplain workflow step
BatchMetadataNotFound⚠️ PartialExplain retry, don’t speculate root cause
PeriodLabelRequired✅ YesExplain format requirement
ServiceUnavailable✅ YesExplain retry strategy
Normalization Drift⚠️ PartialExplain concept, don’t suggest fixes without context
Unresolved New Businesses✅ YesExplain workflow step
Policy BLOCK✅ YesExplain policy options
Deterministic Errors (Must Remain Exact):
  • HTTP status codes (400, 404, 409, 503)
  • Error codes (DiscoveryNotMaterialized, BatchMetadataNotFound, etc.)
  • Trace IDs (for log correlation)
AI-Explainable Errors:
  • 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)

  1. PreflightStep.tsx (dashboard/src/components/intake/PreflightStep.tsx)
    • Location: Sidebar panel or floating panel
    • Observes:
      • useIntakeWizardStore.preflightData (classification results)
      • useIntakeWizardStore.periodLabel
      • useIntakeWizardStore.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 call submitNewBusinessActions() directly
  2. 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() or submitMapping() directly
  3. 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
  4. 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)

  1. CEO Dashboard (dashboard/src/pages/ceo/index.tsx)
    • Location: Right sidebar (similar to existing AIAssistant component, 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
  2. Agent Dashboard (dashboard/src/pages/agent/index.tsx)
    • Location: Right sidebar (similar to existing AIAssistant component, 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
  3. 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)
    • 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 useIntakeWizardStore actions (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:
const preflightData = useIntakeWizardStore(state => state.preflightData);
const periodLabel = useIntakeWizardStore(state => state.periodLabel);
// Use for explanation only
API Response Observation:
// Observe API responses passed as props or from store
// Explain what the data means, don't mutate it
Workflow Guidance:
// Explain next steps based on current state
// Suggest actions, but don't execute them

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)
Store (Read-Only Access, No Mutations):
  • dashboard/src/store/useIntakeWizardStore.ts (read state only, do not add actions)
Client Libraries (Read-Only):
  • 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 (Type Definitions):
  • 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)
Error Handling:
  • api/utils/error_redaction.py (understand error sanitization, trace_id generation)
Documentation:
  • 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 only
  • api/services/**/*.py (business logic services)
  • api/engine/**/*.py (calculation engine, if exists)
  • api/config/**/*.py (configuration, unless needed for understanding env vars)
SQL Files:
  • **/*.sql (BigQuery SQL files) - Unless needed for explanation only
Tests:
  • api/tests/**/*.py (backend tests)
  • dashboard/tests/**/*.tsx (frontend tests)
Infrastructure:
  • api/Dockerfile, cloudbuild*.yaml (deployment configs)
  • .github/** (CI/CD workflows)

File Access Summary

CategoryPath PatternAccess LevelNotes
Wizard UIdashboard/src/components/intake/**✅ WriteCan add AI Advisor components
Dashboard Pagesdashboard/src/pages/{ingestion,ceo,agent}/**✅ WriteCan integrate AI Advisor
Storedashboard/src/store/useIntakeWizardStore.ts⚠️ Read-OnlyRead state, don’t add actions
API Routesapi/routes/{intake*,dashboard*,agent*}.py📖 Read-OnlyUnderstand contracts
API Schemasapi/schemas/**/*.py📖 Read-OnlyType definitions
Error Utilsapi/utils/error_redaction.py📖 Read-OnlyError handling patterns
BigQuery Queriesapi/bigquery/**/*.py❌ ExcludedUnless explanation-only
SQL Files**/*.sql❌ ExcludedUnless explanation-only
Tests{api,dashboard}/tests/**❌ ExcludedNot needed for UI work
InfrastructureDockerfile, cloudbuild*.yaml❌ ExcludedDeployment configs

Summary

This document provides a comprehensive map of:
  1. Wizard Flow: 6-step process from upload to completion, with API endpoints, request/response shapes, and gating logic
  2. Dashboard Endpoints: CEO and Agent dashboards with data source mapping (Stage 1 vs Stage 3+)
  3. Error Taxonomy: Standard error payloads, wizard-blocking errors, and AI safety classifications
  4. AI Advisor Insertion Points: Safe locations for read-only observation, with explicit NO-GO zones
  5. File Access Control: Write access for UI components, read-only for API contracts, excluded for implementation details
Key Principles:
  • 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