# Viabilidade — Cross-integration CVCRM × Exent Hub (atribuição de vendas a campanhas)

> Investigação de viabilidade feita em 2026-07-03. **Não foi implementado nada** — é análise de dados.
> Objetivo do dia: avaliar se dá pra cruzar VENDAS do CV (Construtor de Vendas) com LEADS do Exent Hub
> para atribuir vendas a campanhas/mídia/keyword/anúncio. Retomar por aqui.
> Complementa [cvcrm-handoff.md](cvcrm-handoff.md) (este é o "objetivo principal" mencionado lá).

## Objetivo (definido pelo usuário)
Cruzar dados de VENDAS (clientes/proponentes do CV) com LEADS do Exent Hub para responder:
1. **Quantas vendas foram DE FATO feitas pela internet.** Hoje a `midia` do CV é dominada por
   "Campanha Imobiliária" (56%), suspeita de mascarar vendas de internet (recadastro / corretor
   preenchendo errado / perda de info no preenchimento).
2. **Análise profunda das vendas:** qual campanha vendeu mais, qual keyword, qual anúncio Meta, etc.

## Ambiente de teste
- Projeto: **Vale Verde Arena** (`project_id = 2d87d524-825b-44d9-aa74-a3b00b9148a7`).
  - No CV o empreendimento se chama **ARENA** (idempreendimento). No dashboard o projeto é "Vale Verde Arena".
  - Usuário **ativou a integração Exent Hub** neste projeto para o teste.
- Exent Hub: `credential_id = 9f3ce7e3-9969-43fe-983f-909b6a6553e6`,
  `project_integration external_id = 2d87d524-...` (= o próprio project_id), active + has_data.

## Fontes de dados

### Exent Hub — LEAD-LEVEL disponível na API (mas NÃO ingerido) ✅
- **Ingerido hoje:** só o agregado diário → `fact_crm_daily` (contagens + `source_summary`/`keyword_summary`/
  `campaign_summary` em JSON) e `fact_leads_daily` (contagem por campanha/adset/ad/utm/dia). **Sem PII, sem
  lead individual.** Via `ExentHubProvider::sync()` → endpoint `/crm-daily-summary`.
- **Existe endpoint lead-level não usado:** `ExentHubProvider::fetchLeads($cred, $externalId, $query)` →
  `GET /api/dashboard/projects/{externalId}/leads`. Retorna `{project, filters, pagination, data:[...]}`.
  - Paginado: **6.558 leads** no ARENA, `per_page`/`page`, `last_page`, filtros `date_start`/`date_end`/
    `status`/`search`/`sort_by`/`sort_dir`. (219 páginas com per_page=30.)
  - Range de datas dos leads: **2023-12-22 → 2026-07-03**.
  - **Campos por lead:**
    - Identidade (100% preenchidos na amostra): `name`, `email`, `phone`, `phone_display`, `ddd`. **Sem CPF.**
    - Atribuição: `media` ("Facebook - Ads" / "Google Ads"), `origin` = `{key, label, details:{...}}`, `content`,
      `campaing` (sic — às vezes null), `created_at`, `status`/`status_label`, `additional_info.custom_fields`.
    - `origin.details` (Meta): `ad_id, ad_name, adset_id, adset_name, campaign_id, campaign_name, platform`.
    - `origin.details` (Google): `campaignid, adgroupid, keyword, device, network, creative, matchtype,
      utm_source, utm_medium, campaignsource, campaignmedium`.
  - → **Base perfeita para atribuição** (campanha → adset/adgroup → anúncio/keyword), com email+phone p/ match.

### CV — VENDAS e LEADS (camada fact_cvcrm_*)
- `fact_cvcrm_reservas` (Vendida = venda): **309 vendas** no ARENA. Campos úteis: `cliente` (nome), `idcliente`,
  `idlead` (liga ao lead do CV), `midia`. **Raw da reserva** tem: `email`, `documento_cliente` (CPF),
  `cep_cliente`, `campanha`. → **100% têm CPF**; 245/309 email; 247/309 telefone (via lead raw).
  - `midia` das vendas (o problema): **Campanha Imobiliária 173 (56%)**, Facebook 31, Facebook Ads 13,
    Indicação (várias) ~52, Google Ads 3, Instagram/Site/Internet ~5, etc. Total "declarado internet" ≈ 53/309.
- `fact_cvcrm_leads`: leads do CV. **Raw tem** `email`, `telefone`, `documento_cliente`, `nome`, `origem`,
  `midia`. **NÃO tem** `idcliente`. Só ~103 de ~3.600 leads têm CPF (os manuais/"Campanha Imobiliária";
  leads de Facebook/Google NÃO trazem CPF).

## Testes de cruzamento (dados reais, ARENA)

| Teste | Resultado |
|---|---|
| Venda → Exent Hub por **email** (15 vendas recentes 2026) | **0/15** |
| Venda → Exent Hub por **telefone** (15 vendas c/ tel) | **0/15** |
| Venda → Exent Hub por **nome** (20 vendas 2026) | 1/20 — e essa com contato DIVERGENTE |
| Vendas **"Campanha Imobiliária"** → Exent Hub (email+tel+nome, 25 vendas) | **0/25** |
| Bridge por **CPF** (venda.CPF → lead CV com mesmo CPF, internet?) | ❌ leads de internet não têm CPF |
| Bridge por **idcliente** (venda.idcliente → lead CV) | ❌ leads do CV não têm `idcliente` no raw |
| **Leads do CV rotulados internet → Exent Hub por email (20 leads)** | **20/20** ✅ |

Notas:
- O `search` do Exent Hub FUNCIONA (por email/telefone/nome — confirmado com um lead conhecido: 1 resultado).
- As **janelas temporais se sobrepõem** (vendas 2024–2026; leads 2023–2026; 62 vendas em 2026), então NÃO é
  problema de período.

## Diagnóstico (confirma a hipótese do usuário com precisão)
- Os dois sistemas **representam as mesmas pessoas no estágio de LEAD** — leads internet do CV casam **20/20**
  com o Exent Hub por email.
- **Mas o vínculo se perde na VENDA:** ao converter, o CV cria uma **ficha nova ("Campanha Imobiliária")** com
  contato divergente (email/telefone diferentes do lead original) e o `idlead` da reserva aponta pra essa ficha,
  não pro lead de internet. E as chaves possíveis são assimétricas/ausentes: leads de internet **não têm CPF**;
  leads do CV **não têm idcliente**; email/telefone da venda **≠** do lead.
- **Conclusão:** com os dados atuais, **NÃO há chave confiável que ligue a VENDA ao lead de internet original**
  → Objetivos #1 e #2 **não são atribuíveis por venda** de forma confiável. O join está quebrado na ORIGEM (no
  processo/uso do CV), não é gap técnico do dashboard.

## O que É viável hoje (independe do join quebrado)
1. **Funil de leads do Exent Hub × investimento (Google/Meta):** por campanha/keyword/anúncio → nº de leads,
   **custo por lead**, custo por lead qualificado, volume, tendência. Responde "qual campanha/keyword traz
   mais/melhores **leads**" com 100% de confiança. Falta só a última milha (a venda).
   - Requer: **ingerir o lead-level** do Exent Hub (nova fact table lead-level, a partir de `fetchLeads`) OU
     usar o `fact_leads_daily` já existente (agregado por campanha/ad/dia — sem PII, mas já tem a atribuição).
   - Cruzar com `fact_marketing_daily` / `fact_gads_*` / `fact_meta_*` (spend) → custo por lead por campanha.
2. **Conversão agregada lead→venda** (nível conta/período), sem quebra por campanha.

## Para destravar a atribuição por VENDA (Objetivos #1/#2) — 3 saídas
- **(A) Corrigir na origem (CV)** [ideal]: ao converter, o CV vincular a reserva ao **lead original**
  (`idlead` correto) OU gravar contato/CPF consistente entre lead e venda. É processo/config do CV do cliente —
  destrava tudo de forma limpa. **Levar esse achado pro cliente.**
- **(B) Matching fuzzy** (nome + telefone parcial + proximidade de data + CEP): posso pilotar e MEDIR a taxa de
  recuperação. Sinal inicial baixo (nome 1/20) → expectativa realista de recuperar pouco.
- **(C) Aceitar só o agregado** (itens 1+2 acima), sem atribuição por venda.

## Recomendação p/ retomar
Começar pelo **item 1** (lead-level Exent Hub + custo por campanha/keyword/anúncio) — maior valor destravável,
independe do join. Em paralelo, levar (A) pro cliente. (B) só se o usuário quiser um piloto medido.

## Como reproduzir os probes (retomada)
- Chamar o lead-level ao vivo:
  ```php
  $cred = App\Models\IntegrationCredential::find('9f3ce7e3-9969-43fe-983f-909b6a6553e6');
  $prov = app(App\Services\Integrations\IntegrationCredentialService::class)->providerFor($cred->provider);
  $res  = $prov->fetchLeads($cred, '2d87d524-825b-44d9-aa74-a3b00b9148a7', ['per_page'=>30, 'search'=>'...']);
  // $res['data'] = leads; $res['pagination'] = {total, last_page, ...}
  ```
- ⚠️ Espaçar as chamadas (usei ~0.25–0.3s entre buscas). Não sabemos o rate limit do Exent Hub — ir com calma.
- ⚠️ **PII:** os leads têm nome/email/telefone reais. Nos testes só reportei contagens/agregados; não logar PII.
