Integration Readiness Guide
Purpose
Assess whether current platform capabilities are ready for CRM integrations and identify remaining Phase 4 adapter work.When to run this
- Before onboarding a CRM integration
- During release readiness checks for integration features
- During integration incident triage
Prerequisites
- Access to architecture docs and integration contracts
- BigQuery/query access to integration tables
- Knowledge of target provider and org scope
Inputs
- Target provider(s): Salesforce, HubSpot, Zoho, Zenoti, custom
- Tenant/org scope and expected event path (webhook or polling)
- Current Phase status and integration schema references
Procedure
1) Determine current readiness state
Last Updated: December 2025Status: Phase 3.x Foundation Complete, Phase 4 Adapters Pending Short Answer: Integration-ready primitives exist; adapters come in Phase 4. Current State (Phase 3.x):
- ✅ Multi-tenant isolation (
tenant_idenforced everywhere) - ✅ Org scoping (
org_idwith JWT/header support) - ✅ Config plane (agent profiles, hierarchies, rate plans, assignments)
- ✅ Outbox table foundation (
integration_events_outbox) - ✅ API client security hardening (protected headers, error normalization)
- ✅ Decimal safety policy (NUMERIC/string, no float math)
- 🔲 CRM adapter implementations (Salesforce, HubSpot, Zoho, Zenoti, custom)
- 🔲 Webhook infrastructure (incoming/outgoing)
- 🔲 Pub/Sub workers (event processing)
- 🔲 Secret Manager integration (credential storage)
- 🔲 Connection management UI (OAuth flows, API keys)
2) Validate universal adapter pattern coverage
The “Universal Adapter” is a design pattern that supports multiple CRM integration paths:Webhook Path (Preferred - Real-Time)
- External CRM sends webhook to our platform
- Webhook Handler validates signature and extracts payload
- Event Processor transforms CRM event to internal format
- Outbox Writer appends event to
integration_events_outbox - Pub/Sub Publisher publishes event to topic (fast path)
- Commission Calculator processes event and updates commission data
Polling Path (Fallback)
- Polling Worker (Cloud Scheduler cadence) queries external CRM API
- Change Detection compares current state with last known state
- Event Generator creates events for detected changes
- Outbox Writer appends events to
integration_events_outbox - Pub/Sub Publisher publishes events to topic
- Commission Calculator processes events
3) Validate org scoping contract
Authority Hierarchy
-
JWT
org_idis Authoritative: If JWT containsorg_id, it takes precedence over anyX-Org-Idheader. Org-scoped users cannot override their org context. -
Platform Admin Mode: If JWT has no
org_id(platform admin),X-Org-Idheader is required for org-scoped operations. Requests withoutX-Org-Idreturn 400 Bad Request. -
NULL = Platform-Level: In database schemas,
org_id = NULLmeans platform-level (visible to all orgs within tenant). This is distinct from “no org” (which requiresX-Org-Idheader for platform admins).
Enforcement Rules
- List Operations: Filter by
org_id(WHERE clause includes org_id match or NULL for platform-level) - Get-by-ID Operations: Verify
org_idmatches (return 404 if cross-org, not 403 to avoid existence leaks) - Mutations: Enforce
org_idscope (prevent cross-org writes) - Org-Scoped Users: Cannot access data outside their JWT
org_id(even withX-Org-Idheader)
Implementation
- Backend:
require_org_id()dependency extracts org_id from JWT orX-Org-Idheader - Frontend:
useOrgScope()hook manages org selection for platform admins - Database: All config tables include
org_id STRINGcolumn (NULL = platform-level)
Architect_Context.md for full org scoping contract.
4) Validate credential storage model
Where Credentials Live
Google Secret Manager (not BigQuery):- OAuth tokens (access tokens, refresh tokens)
- API keys (for external CRM APIs)
- Webhook secrets (for signature validation)
- Secret reference IDs (e.g.,
secret_ref: "projects/xxx/secrets/salesforce-oauth-token") - Never store actual credentials in BigQuery
Why This Pattern?
- Security: Secret Manager provides encryption at rest, access control, audit logging
- Rotation: Secrets can be rotated without updating BigQuery records
- Compliance: Meets audit requirements for credential storage
- Isolation: Per-tenant secret isolation via IAM
Example Schema
5) Validate JSON and decimal rules
JSON Storage
Repository Standard:STRING columns storing JSON-encoded data (not native JSON type).
Example:
Decimal Safety (Critical)
Rule: Decimals in JSON payloads MUST be stored as strings (not JSON numbers). Examples:- ✅
"split_pct": "33.333333"(string) - ✅
"pepm_rate": "12.50"(string) - ❌
"split_pct": 33.333333(number - forbidden)
Architect_Context.md
6) Validate operational constraints and outbox model
BigQuery Limitations
BigQuery is OLAP (Online Analytical Processing), not OLTP (Online Transaction Processing). Implications:- Do NOT build high-frequency polling loops against BigQuery
- Use Pub/Sub for real-time event delivery (fast path)
- Use outbox table for audit trail and retry/replay (safety net)
- Worker cadence should be low-frequency (Cloud Scheduler: minutes/hours, not seconds)
Outbox Pattern
Purpose: Audit-grade safety net for event delivery. Architecture:- Fast Path: Pub/Sub for real-time delivery
- Safety Net: Outbox table for retry/replay
- Worker: Phase 4 via Pub/Sub + Cloud Scheduler cadence
integration_events_outbox (see integration/bigquery/sql/tables/integration_events_outbox.sql)
7) Review provider-specific adapter examples
Salesforce
Integration Type: OAuth 2.0 + REST API Data Flow:- OAuth flow stores tokens in Secret Manager
- Webhook path: Salesforce sends webhook → our handler → outbox → Pub/Sub
- Polling path: Worker queries Salesforce API → change detection → outbox → Pub/Sub
account.created,account.updated,account.deletedcontact.created,contact.updatedopportunity.created,opportunity.won,opportunity.lost
HubSpot
Integration Type: OAuth 2.0 + REST API Data Flow:- OAuth flow stores tokens in Secret Manager
- Webhook path: HubSpot sends webhook → our handler → outbox → Pub/Sub
- Polling path: Worker queries HubSpot API → change detection → outbox → Pub/Sub
contact.created,contact.updated,contact.deletedcompany.created,company.updateddeal.created,deal.updated,deal.won
Zoho
Integration Type: OAuth 2.0 + REST API Data Flow:- OAuth flow stores tokens in Secret Manager
- Webhook path: Zoho sends webhook → our handler → outbox → Pub/Sub
- Polling path: Worker queries Zoho API → change detection → outbox → Pub/Sub
contact.created,contact.updatedaccount.created,account.updateddeal.created,deal.updated
Zenoti
Integration Type: API Key + REST API Data Flow:- API key stored in Secret Manager
- Webhook path: Zenoti sends webhook → our handler → outbox → Pub/Sub
- Polling path: Worker queries Zenoti API → change detection → outbox → Pub/Sub
appointment.created,appointment.updated,appointment.completedmember.created,member.updatedservice.created,service.updated
Custom CRM (Champion Health)
Integration Type: Custom API (provider-specific) Data Flow:- Credentials stored in Secret Manager (API key or OAuth)
- Webhook path: Custom CRM sends webhook → our handler → outbox → Pub/Sub
- Polling path: Worker queries custom API → change detection → outbox → Pub/Sub
8) Validate event payload contracts
Event Payload Structure
Decimal Values in Payloads
Critical: All decimal values MUST be strings:9) Confirm Phase 4 roadmap
- Connection Management: OAuth flows, API key management UI
- Webhook Infrastructure: Incoming/outgoing webhook handlers
- Pub/Sub Workers: Event processing workers (Cloud Scheduler cadence)
- Adapters: Provider-specific adapters (Salesforce, HubSpot, Zoho, Zenoti, custom)
- Monitoring: Integration health checks, error alerting
- Testing: Integration test suite for each provider
10) Confirm schema references
Phase 3.x Integration Readiness Schemas
Transaction Events:- Pydantic Schema:
api/schemas/transaction_event.py - BigQuery DDL:
integration/bigquery/sql/tables/transaction_events.sql - Validation:
api/utils/decimal_strings.py - Tests:
api/tests/test_decimal_strings.py,api/tests/test_transaction_event.py
- BigQuery DDL:
integration/bigquery/sql/tables/identity_external_id_map.sql - Purpose: Maps external CRM identifiers (Salesforce contact ID, HubSpot deal ID, etc.) to internal entity identifiers (agent_id, business_id, etc.)
- JSON Schema:
docs/no_code_rules.schema.json - Documentation:
docs/NO_CODE_RULES.md - Validation:
api/utils/rules_schema_validate.py - Purpose: Strict, versioned schema for no-code commission rule definitions
- BigQuery DDL:
integration/bigquery/sql/tables/integration_events_outbox.sql - Purpose: Append-only audit trail for CRM integration events
- Hook:
dashboard/src/hooks/useEmbedMode.ts - Documentation:
docs/EMBED_MODE.md - Purpose: Minimal UI mode for Salesforce/HubSpot Canvas-type integrations
Verification
- Phase 3.x readiness primitives are present and documented
- Remaining Phase 4 items are explicitly tracked
- Secret handling, scoping, and decimal rules align with architecture contracts
Failure modes & fixes
- Credentials stored in BigQuery directly
- Move to Secret Manager and keep only
secret_refin data tables.
- Move to Secret Manager and keep only
- Org scoping ambiguity or bypass risk
- Enforce JWT-first authority with
require_org_id()and route-level checks.
- Enforce JWT-first authority with
- Decimal precision drift in payloads
- Enforce string decimals in JSON payloads; avoid float math paths.
- High-frequency polling design
- Shift to webhook/PubSub fast path and scheduled low-frequency polling.
Artifacts produced
- Integration readiness decision (ready foundations vs pending adapters)
- Gap list for Phase 4 implementation
- Contract/evidence references for security and data correctness
Related docs
Architect_Context.md- Full architecture documentationintegration/bigquery/sql/tables/integration_events_outbox.sql- Outbox table DDL- ADR-001 through ADR-005 in
Architect_Context.md- Architectural decisions