REF-901-01: HubSpot Sync Rules
ADR: ADR-901 — IntegrationsEscopo: Dual-account, source of truth por campo, lead dedup, isolamento de deals, sync bidirecional de quotes, conflito de campo, 7 serviços migrados
1. Dual-Account
MIDDAG opera dois HubSpots: BR e Global. Mesmo lead/empresa pode existir em ambos.
| Aspecto | HubSpot BR | HubSpot Global |
|---|---|---|
| Mercado | Brasil | Internacional |
| Moeda | BRL | USD |
| Deals | Deals BR | Deals LLC |
| Sync com | Orgs billing_entity=br | Orgs billing_entity=global |
2. Source of Truth por Campo
| Dado | Source of Truth | Direção | Regra de Conflito |
|---|---|---|---|
| Campos da Organization | Plugin | Plugin → HubSpot | Plugin vence. Audit trail em conflito. |
| Deals / Pipeline | HubSpot | HubSpot → Plugin | HubSpot vence. Plugin lê, não escreve. |
| Status do Quote | Plugin | Plugin → HubSpot | Plugin vence (lifecycle do quote). |
| Dados do Quote (criação) | HubSpot | HubSpot → Plugin | HubSpot inicia, plugin armazena. |
Regra: Sync por campo, não por entidade inteira. Nunca sobrescrever entidade completa.
3. Lead Dedup
Organization no plugin tem dois campos:
| Campo | Valor | Descrição |
|---|---|---|
hubspot_company_id_br | Company ID BR | Vincula company no HubSpot BR |
hubspot_company_id_global | Company ID LLC | Vincula company no HubSpot Global |
Mesmo cliente pode estar nos dois HubSpots — vinculado via Organization. Plugin é ponto de dedup.
4. Isolamento de Deals
| Regra | Detalhe |
|---|---|
| Deals BR → só HubSpot BR | Sem cross-sync entre contas |
| Deals Global → só HubSpot Global | Cada conta tem deals independentes |
| Plugin lê deals de ambos | Exibir no admin UI (somente leitura) |
| Plugin NÃO cria deals | Deals criados no HubSpot por vendas |
5. Sync Bidirecional de Quotes
Criação (HubSpot → Plugin):
Deal avança para stage de quote
→ Webhook: deal updated
→ Plugin cria Quote (status: draft) com dados do deal
→ Quote armazena hubspot_deal_id
Status (Plugin → HubSpot):
Cliente aceita quote no portal
→ Plugin: status → accepted
→ Sync: atualiza propriedade do deal no HubSpot
Quote pago:
→ Plugin: status → paid
→ Sync: deal stage atualizado no HubSpotCada quote pertence a uma entidade (BR ou Global) — sync vai para HubSpot correto.
6. Conflito de Campo
| Cenário | Resolução |
|---|---|
| Campo editado no HubSpot E no plugin | Plugin vence (mestre para org data) |
| Editado apenas no HubSpot | Plugin aceita (próximo sync) |
| Editado apenas no plugin | Push para HubSpot |
| Conflito detectado | Audit trail: campo, valor antigo, valor novo, fonte que venceu |
7. Serviços HubSpot Migrados do Theme
| # | Serviço | Função |
|---|---|---|
| 1 | CompanyService | Sync Organization ↔ HubSpot Company |
| 2 | ContactService | Sync Collaborator → HubSpot Contact |
| 3 | DealService | Leitura de deals HubSpot → exibição admin |
| 4 | QuoteService | Sync bidirecional de quotes |
| 5 | AssociationService | Vinculação company↔contact↔deal |
| 6 | SearchService | Busca de empresas/contatos no HubSpot |
| 7 | LineItemService | Sync de line items de quote |
Todos migrados do theme. Roteamento dual-account adicionado na v5.0.
8. Webhook Events e Handler
O HubSpot envia webhooks para eventos de deals, quotes e contacts. Endpoints separados por conta:
| URL | Conta |
|---|---|
/wp-json/middag-account/v1/webhooks/hubspot/br | HubSpot BR |
/wp-json/middag-account/v1/webhooks/hubspot/llc | HubSpot LLC |
8.1 Eventos Tratados
Deals:
| Evento | Ação no Plugin |
|---|---|
deal.creation | Registra oportunidade localmente |
deal.propertyChange (stage) | Atualiza stage/amount/closedate locais |
deal.deletion | Marca deal como removido |
Quotes:
| Evento | Ação no Plugin |
|---|---|
quote.creation | Cria Quote no plugin (status: draft) |
quote.propertyChange | Atualiza Quote local |
quote.deletion | Marca Quote como cancelado |
Contacts:
| Evento | Ação no Plugin |
|---|---|
contact.creation | Cria/atualiza contato vinculado à Organization |
contact.propertyChange | Atualiza dados de contato |
contact.deletion | Desativa contato |
8.2 Requisitos do Handler
Cada webhook handler implementa:
| Requisito | Detalhe |
|---|---|
| Validação de assinatura | HMAC com secret configurado por conta |
| Idempotência | Via event_id — skip se já processado |
| Retry com backoff | Backoff exponencial para falhas de processamento |
| Logging estruturado | Timestamp, direção, hash do payload, status do resultado |
| Prevenção de loops | Eventos originados pelo plugin não disparam re-sync |
9. DTOs HubSpot
O namespace Middag\Account\Integration\HubSpot\Models\ contém DTOs para cada entidade:
| DTO | Campos Adicionais v5.0 |
|---|---|
Contact | Campos de organização e papel (role) do colaborador |
Company | Campos de dual-account (billing_entity) e vinculação com Organization |
Deal | Campos de stage mapping e probabilidade |
LineItem | Mantido (já completo da migração v3) |
Quote | Campos de status do ciclo de vida (draft/sent/accepted/paid) |
WebhookEvent | Representação padronizada de eventos recebidos (novo) |
SyncStatus | Rastreamento de estado de sincronização por entidade (novo) |
10. Namespace e Estrutura
Middag\Account\
Integration\
HubSpot\
HubSpotClient.php — cliente API dual-account (forCompany pattern)
HubSpotWebhookHandler.php — processamento de eventos de webhook
HubSpotSyncService.php — sincronização Plugin → HubSpot
Models\
Contact.php
Company.php
Deal.php
LineItem.php
Quote.php
WebhookEvent.php
SyncStatus.php
Api\
Webhook\
HubSpotWebhookController.php — endpoint REST que recebe webhooksO controller vive em Api\Webhook\ (conforme ADR-103). A lógica de processamento permanece em Integration\HubSpot\HubSpotWebhookHandler.
11. Configuração Dual-Account
| Env Var | Descrição |
|---|---|
HUBSPOT_BR_ACCESS_TOKEN | Access token HubSpot BR |
HUBSPOT_BR_PORTAL_ID | Portal ID HubSpot BR |
HUBSPOT_LLC_ACCESS_TOKEN | Access token HubSpot LLC |
HUBSPOT_LLC_PORTAL_ID | Portal ID HubSpot LLC |
O HubSpotClient segue o mesmo padrão do StripeClient — forCompany($billingEntity) retorna client configurado com credenciais da conta correspondente.
12. Sync Bidirecional Completa
12.1 Direção de Sincronização por Dado
| Dado | Direção | Detalhe |
|---|---|---|
| Deals (pipeline, stage, valor) | HubSpot → Plugin | Sales team gerencia no HubSpot |
| Quotes (criação, edição) | HubSpot → Plugin | Sales team cria no HubSpot |
| Quote status (aceito, rejeitado) | Plugin → HubSpot | Cliente age no portal |
| Order/payment status | Plugin → HubSpot | WooCommerce confirma pagamento |
| Contact (dados comerciais) | HubSpot → Plugin | CRM é fonte de contatos |
| Organization (verificação) | Plugin → HubSpot | Plugin gerencia verificação |
| Ticket (suporte) | Bidirecional | Criado no portal, gerenciado no CRM |
12.2 Organization vinculada a HubSpot Company IDs
Organization mantém vinculação com ambas as contas:
| Campo | Descrição |
|---|---|
hubspot_company_id_br | Company ID no CRM MIDDAG BR |
hubspot_company_id_global | Company ID no CRM MIDDAG LLC |
Criação de Organization no plugin pode disparar criação de Company no HubSpot (e vice-versa via webhook). O CompanyService sincroniza dados entre Organization e as Companies correspondentes.