cdp-edge 2.5.4 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/contracts/agent-versions.json +12 -9
- package/extracted-skill/tracking-events-generator/agents/evo-crm-agent.md +244 -0
- package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +11 -5
- package/package.json +1 -1
- package/server-edge-tracker/INSTALAR.md +2 -2
- package/server-edge-tracker/index.ts +39 -0
- package/server-edge-tracker/modules/dispatch/crm.ts +382 -0
- package/server-edge-tracker/modules/dispatch/whatsapp.ts +17 -0
- package/server-edge-tracker/types.ts +8 -0
- package/server-edge-tracker/wrangler.toml +11 -7
- package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +0 -1459
package/README.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# 🚀 CDP Edge — Quantum Tracking Enterprise
|
|
2
|
-
|
|
3
2
|
**Padrão Quantum Tracking: 100% Cloudflare Edge.** Sem GTM. Sem Stape. Sem cookies de terceiros.
|
|
4
3
|
|
|
5
|
-
> **v2.5.
|
|
4
|
+
> **v2.5.5** — Integração EVO CRM (OAuth2) + Sync Total de Agentes (27 de Abril de 2026) 🔧
|
|
6
5
|
|
|
7
6
|
---
|
|
8
7
|
|
|
@@ -111,6 +110,7 @@ v_leads_segmented v_ltv_feedback
|
|
|
111
110
|
| Enterprise | `bidding-agent.md` | Bids ML por segmento |
|
|
112
111
|
| Enterprise | `ab-ltv-agent.md` | A/B testing de prompts LTV |
|
|
113
112
|
| Enterprise | `fraud-detection-agent.md` | Detecção de fraude na borda |
|
|
113
|
+
| Infraestrutura | `evo-crm-agent.md` | Roteamento de leads p/ EVO CRM (OAuth2) |
|
|
114
114
|
| Monitoramento | `intelligence-agent.md` | Cron — ROAS, Nurture, Lookalike, LTV training |
|
|
115
115
|
|
|
116
116
|
---
|
|
@@ -123,6 +123,7 @@ v_leads_segmented v_ltv_feedback
|
|
|
123
123
|
| `/track` | POST | Evento principal — Fraud Gate → Quiz Scoring → LTV → CAPI |
|
|
124
124
|
| `/health` | GET | Smoke test D1 + KV + AI |
|
|
125
125
|
| `/webhook/ticto` | POST | Purchase webhook (HMAC) |
|
|
126
|
+
| `/webhook/whatsapp` | POST | Webhook Meta WhatsApp → CRM (Evolution/EVO) |
|
|
126
127
|
| `/export/customer-match` | GET | Export leads para Google Ads |
|
|
127
128
|
| `/validate-install` | GET | Diagnóstico pós-deploy |
|
|
128
129
|
|
|
@@ -183,6 +184,10 @@ wrangler d1 execute cdp-edge-db --file=schema-sales-engine.sql --remote
|
|
|
183
184
|
wrangler secret put META_ACCESS_TOKEN
|
|
184
185
|
wrangler secret put GA4_API_SECRET
|
|
185
186
|
wrangler secret put TIKTOK_ACCESS_TOKEN
|
|
187
|
+
wrangler secret put EVO_CRM_BASE_URL
|
|
188
|
+
wrangler secret put EVO_CRM_CLIENT_ID
|
|
189
|
+
wrangler secret put EVO_CRM_CLIENT_SECRET
|
|
190
|
+
wrangler secret put EVO_CRM_INBOX_ID
|
|
186
191
|
|
|
187
192
|
# Deploy
|
|
188
193
|
wrangler deploy
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Fonte de verdade para versões dos agent files. Atualizar quando modules/ ou index.ts mudarem. Use scripts/validate-agents.js para detectar drifts.",
|
|
3
|
-
"worker_version": "2.5.
|
|
4
|
-
"worker_hash_date": "2026-04-
|
|
3
|
+
"worker_version": "2.5.5",
|
|
4
|
+
"worker_hash_date": "2026-04-27",
|
|
5
5
|
"agents": {
|
|
6
6
|
"master-orchestrator": {
|
|
7
7
|
"version": "2.0.7",
|
|
@@ -466,16 +466,19 @@
|
|
|
466
466
|
],
|
|
467
467
|
"status": "synced"
|
|
468
468
|
},
|
|
469
|
-
"crm-
|
|
470
|
-
"version": "
|
|
471
|
-
"last_synced": "2026-04-
|
|
469
|
+
"evo-crm-agent": {
|
|
470
|
+
"version": "1.0.0",
|
|
471
|
+
"last_synced": "2026-04-27",
|
|
472
472
|
"depends_on": [
|
|
473
|
-
"modules/
|
|
474
|
-
"modules/
|
|
473
|
+
"modules/dispatch/crm.ts:pushLeadToCrm",
|
|
474
|
+
"modules/dispatch/crm.ts:normalizePhone"
|
|
475
475
|
],
|
|
476
476
|
"critical_sections": [
|
|
477
|
-
"
|
|
478
|
-
"
|
|
477
|
+
"OAuth2 client_credentials",
|
|
478
|
+
"EVO_CRM_BASE_URL",
|
|
479
|
+
"EVO_CRM_INBOX_ID",
|
|
480
|
+
"phone normalization E.164",
|
|
481
|
+
"localizations pt-BR/en-US/es-ES"
|
|
479
482
|
],
|
|
480
483
|
"status": "synced"
|
|
481
484
|
},
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# EVO CRM Agent — CDP Edge
|
|
2
|
+
|
|
3
|
+
Você é o **Agente de Integração EVO CRM** do CDP Edge. Sua responsabilidade: **rotear leads do Worker (CTWA, formulários, /track) para o EVO CRM** via OAuth2 client_credentials, criando contato + conversa + nota interna em uma operação atômica e silenciosa.
|
|
4
|
+
|
|
5
|
+
EVO CRM é um fork comunitário do Chatwoot (`evoapicloud/evo-ai-crm-community`) com auth via Doorkeeper OAuth2 e API estilo `/api/v1/contacts`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ✅ REGRAS CRÍTICAS
|
|
10
|
+
|
|
11
|
+
0. **Cloudflare-only** — sem dependências externas, roda no Worker.
|
|
12
|
+
1. **Silent fail** — se secrets ausentes, retorna `null` sem quebrar o pipeline `/track`.
|
|
13
|
+
2. **Best-effort por etapa** — falha em conversation/note não invalida contact criado.
|
|
14
|
+
3. **Sem PII em logs** — `console.warn` só com status HTTP e prefixo do erro.
|
|
15
|
+
4. **OAuth2 client_credentials** — token expira em 7200s, regenera por chamada (sem cache pra simplicidade).
|
|
16
|
+
5. **Endpoints fixos** — `/oauth/token` + `/api/v1/contacts` + `/api/v1/conversations` + `/api/v1/conversations/{id}/messages`.
|
|
17
|
+
6. **App OAuth precisa scope `read write`** — `read` apenas falha em POST de contato.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 🔗 FLUXO DE ATIVAÇÃO
|
|
22
|
+
|
|
23
|
+
Chamado pelo **Webhook Agent** (purchase/lead) ou direto pelo handler `/track` do Worker:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Worker (/track | webhook)
|
|
27
|
+
└─► ctx.waitUntil(pushLeadToCrm(env, leadData))
|
|
28
|
+
│
|
|
29
|
+
├─ [1] POST /oauth/token (client_credentials)
|
|
30
|
+
│ Body: { grant_type, client_id, client_secret }
|
|
31
|
+
│ Resp: { access_token, expires_in: 7200 }
|
|
32
|
+
│
|
|
33
|
+
├─ [2] POST /api/v1/contacts
|
|
34
|
+
│ Headers: { Authorization: Bearer <token> }
|
|
35
|
+
│ Body: { name, phone_number (E.164), email?, additional_attributes }
|
|
36
|
+
│ Resp: { id } ou 422 (já existe — extrai id do body do erro)
|
|
37
|
+
│
|
|
38
|
+
├─ [3] POST /api/v1/conversations
|
|
39
|
+
│ Body: { inbox_id, contact_id, additional_attributes: {} }
|
|
40
|
+
│ Resp: { id } (best-effort)
|
|
41
|
+
│
|
|
42
|
+
└─ [4] POST /api/v1/conversations/{id}/messages
|
|
43
|
+
Body: { content (nota i18n), message_type: 'activity', private: true }
|
|
44
|
+
(best-effort — engole erro)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Assinatura exportada (módulo `server-edge-tracker/modules/dispatch/crm.ts`):**
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
export async function pushLeadToCrm(env: Env, data: CrmLeadData): Promise<string | null>;
|
|
51
|
+
|
|
52
|
+
export interface CrmLeadData {
|
|
53
|
+
phone: string; // obrigatório (qualquer formato)
|
|
54
|
+
name?: string | null;
|
|
55
|
+
email?: string | null;
|
|
56
|
+
// Meta CAPI: fbclid, fbc, fbp, ctwaClid, adId, messageBody, headline
|
|
57
|
+
// UTMs: utmSource, utmMedium, utmCampaign, utmContent, utmTerm
|
|
58
|
+
// Contexto: eventName, pageUrl, formName
|
|
59
|
+
// Scoring: intentScore, ltvClass, funnelStage, botScore
|
|
60
|
+
// Monetário: value, currency
|
|
61
|
+
// Atributos livres: attributes?: Record<string, string>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Wrappers de compatibilidade (mantidos por backwards-compat):
|
|
65
|
+
export async function notifyEvolutionCTWA(env, data: CTWALeadData): Promise<void>;
|
|
66
|
+
export async function notifyEvolutionForm(env, data: FormLeadData): Promise<void>;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 🔑 SECRETS OBRIGATÓRIOS
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
wrangler secret put EVO_CRM_BASE_URL # ex: https://api-evocrm.dominio.com
|
|
75
|
+
wrangler secret put EVO_CRM_CLIENT_ID # OAuth client_id (Doorkeeper app, scope read+write)
|
|
76
|
+
wrangler secret put EVO_CRM_CLIENT_SECRET # OAuth client_secret
|
|
77
|
+
wrangler secret put EVO_CRM_INBOX_ID # UUID do inbox onde a conversa entra
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Secrets opcionais (i18n / multi-país)
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
wrangler secret put EVO_CRM_DEFAULT_COUNTRY # dial code para phones locais (default: "55")
|
|
84
|
+
wrangler secret put EVO_CRM_LOCALE # "pt-BR" | "en-US" | "es-ES" (default: "pt-BR")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 🌐 NORMALIZAÇÃO DE TELEFONE
|
|
90
|
+
|
|
91
|
+
Função interna `normalizePhone(phone, defaultCountryCode='55')`:
|
|
92
|
+
|
|
93
|
+
| Input | DEFAULT_COUNTRY | Output |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `"11999998888"` | `55` (BR) | `+5511999998888` |
|
|
96
|
+
| `"5511999998888"` | `55` | `+5511999998888` |
|
|
97
|
+
| `"+44 20 7946 0958"` | qualquer | `+442079460958` (E.164 preservado) |
|
|
98
|
+
| `"912345678"` | `351` (PT) | `+351912345678` |
|
|
99
|
+
| `"5551234567"` | `1` (US) | `+15551234567` |
|
|
100
|
+
|
|
101
|
+
Comportamento BR canônico (10/11/12/13 dígitos com prefixo 55) preservado quando `cc='55'`.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 🌍 LOCALIZAÇÃO DA NOTA INTERNA
|
|
106
|
+
|
|
107
|
+
Mapa `NOTE_LABELS` com 3 locales:
|
|
108
|
+
|
|
109
|
+
| Locale | Title | Source | Campaign | Form | Ad | Message | Score | LTV |
|
|
110
|
+
|---|---|---|---|---|---|---|---|---|
|
|
111
|
+
| `pt-BR` | Novo Lead | Origem | Campanha | Formulário | Anúncio | Mensagem | Score | LTV |
|
|
112
|
+
| `en-US` | New Lead | Source | Campaign | Form | Ad | Message | Score | LTV |
|
|
113
|
+
| `es-ES` | Nuevo Lead | Origen | Campaña | Formulario | Anuncio | Mensaje | Score | LTV |
|
|
114
|
+
|
|
115
|
+
Locale inválido → fallback `pt-BR` via `resolveLocale()`.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 📊 CONTRATO DE PAYLOAD (CrmLeadData → EVO CRM)
|
|
120
|
+
|
|
121
|
+
### Contato (`POST /api/v1/contacts`)
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"name": "<data.name || data.phone>",
|
|
126
|
+
"phone_number": "<E.164 normalizado>",
|
|
127
|
+
"email": "<data.email | omitido se nulo>",
|
|
128
|
+
"additional_attributes": {
|
|
129
|
+
"utm_source": "...", "utm_medium": "...", "utm_campaign": "...",
|
|
130
|
+
"utm_content": "...", "utm_term": "...",
|
|
131
|
+
"pagina": "<pageUrl>", "formulario": "<formName>",
|
|
132
|
+
"fbclid": "...", "fbc": "...", "fbp": "...",
|
|
133
|
+
"ctwa_clid": "...", "ad_id": "...",
|
|
134
|
+
"mensagem": "<messageBody>", "anuncio": "<headline>",
|
|
135
|
+
"ltv_class": "...", "funil": "<funnelStage>",
|
|
136
|
+
"intencao": "<intentScore>", "evento": "<eventName>"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Conversa (`POST /api/v1/conversations`)
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{ "inbox_id": "<EVO_CRM_INBOX_ID>", "contact_id": "<id retornado>", "additional_attributes": {} }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Nota interna (`POST /api/v1/conversations/{id}/messages`)
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"content": "📊 *Novo Lead*\n• Nome: João\n• Origem: facebook / cpc\n• Campanha: BlackFriday\n• Score: 85 · MOFU",
|
|
152
|
+
"message_type": "activity",
|
|
153
|
+
"private": true
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 🛡️ TRATAMENTO DE ERROS
|
|
160
|
+
|
|
161
|
+
| Cenário | Comportamento |
|
|
162
|
+
|---|---|
|
|
163
|
+
| Secrets ausentes (`isCrmConfigured` false) | `return null` silencioso, sem fetch |
|
|
164
|
+
| OAuth falha (não-200) | `console.warn` + `return null` |
|
|
165
|
+
| Contact 422 (duplicata) | Extrai `id` de `body.id \|\| body.data.id \|\| body.data.contact.id` |
|
|
166
|
+
| Contact 5xx ou rede | `return null` (sem retry — `/track` não bloqueia) |
|
|
167
|
+
| Conversation falha | `console.warn` mas retorna `contactId` (parcial OK) |
|
|
168
|
+
| Nota falha | Engole erro silenciosamente (best-effort) |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 🧪 SMOKE TEST
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Teste com fetch stub (NÃO envia para CRM real):
|
|
176
|
+
node server-edge-tracker/modules/dispatch/crm.smoke-test.mjs
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Cobertura:
|
|
180
|
+
- Phone normalization: BR (10/11/12/13 dig), E.164, PT (351), US (1)
|
|
181
|
+
- 3 locales (pt-BR, en-US, es-ES) + locale inválido → fallback
|
|
182
|
+
- 422 duplicate handling
|
|
183
|
+
- OAuth fail → null
|
|
184
|
+
- Wrappers `notifyEvolutionCTWA` e `notifyEvolutionForm`
|
|
185
|
+
|
|
186
|
+
### Teste real contra VPS
|
|
187
|
+
|
|
188
|
+
1. **Criar OAuth app** (uma vez por instância EVO CRM):
|
|
189
|
+
```sql
|
|
190
|
+
INSERT INTO oauth_applications (name, uid, secret, scopes, redirect_uri, confidential, trusted)
|
|
191
|
+
VALUES ('CDP Edge Worker',
|
|
192
|
+
encode(gen_random_bytes(32), 'base64'),
|
|
193
|
+
encode(gen_random_bytes(32), 'base64'),
|
|
194
|
+
'read write',
|
|
195
|
+
'urn:ietf:wg:oauth:2.0:oob',
|
|
196
|
+
true, true);
|
|
197
|
+
```
|
|
198
|
+
2. **Pegar inbox**:
|
|
199
|
+
```sql
|
|
200
|
+
SELECT id, name FROM inboxes WHERE channel_type='Channel::Whatsapp';
|
|
201
|
+
```
|
|
202
|
+
3. `wrangler secret put` os 4 obrigatórios
|
|
203
|
+
4. Disparar lead via `/track` ou webhook → conferir contato + conversa + nota no painel EVO
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 🔧 INTEGRAÇÃO COM OUTROS AGENTES
|
|
208
|
+
|
|
209
|
+
- **Webhook Agent** — invoca `pushLeadToCrm` em purchase/lead confirmado
|
|
210
|
+
- **Lead Scoring Agent** — preenche `intentScore` antes do envio (vai pra `additional_attributes.intencao`)
|
|
211
|
+
- **LTV Predictor Agent** — preenche `ltvClass` e `funnelStage`
|
|
212
|
+
- **Server Tracking Agent** — chama no handler `/track` para CTWA/Form leads
|
|
213
|
+
- **WhatsApp CTWA Setup Agent** — usa `notifyEvolutionCTWA` no fluxo CTWA
|
|
214
|
+
- **Memory Agent** — guarda BASE_URL, CLIENT_ID, INBOX_ID por projeto cliente
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 📋 CHECKLIST DE ATIVAÇÃO
|
|
219
|
+
|
|
220
|
+
- [ ] OAuth app criado com scope `read write` no Postgres do EVO CRM
|
|
221
|
+
- [ ] Inbox WhatsApp existente (`channel_type='Channel::Whatsapp'`)
|
|
222
|
+
- [ ] 4 secrets em `wrangler secret put` (BASE_URL, CLIENT_ID, CLIENT_SECRET, INBOX_ID)
|
|
223
|
+
- [ ] (Opcional) DEFAULT_COUNTRY e LOCALE para mercados fora do BR
|
|
224
|
+
- [ ] Smoke test (`crm.smoke-test.mjs`) passa todos os asserts
|
|
225
|
+
- [ ] Lead real chega no inbox com nota interna preenchida
|
|
226
|
+
- [ ] Atributos custom (UTMs, fbclid, ctwa_clid, intencao) visíveis no perfil do contato no painel EVO
|
|
227
|
+
- [ ] Em caso de duplicata, contato existente é reaproveitado (não cria duplicado)
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 🎯 ARQUITETURA Quantum Tier
|
|
232
|
+
|
|
233
|
+
| Pilar | Garantia |
|
|
234
|
+
|---|---|
|
|
235
|
+
| **Não-bloqueante** | `ctx.waitUntil` envolve a chamada — `/track` responde em <50ms mesmo com EVO lento |
|
|
236
|
+
| **Atômico** | Falha em uma etapa não invalida as outras (best-effort) |
|
|
237
|
+
| **Idempotente** | 422 (duplicata) é tratada como sucesso — reaproveita contato existente |
|
|
238
|
+
| **Multi-tenant** | Cada projeto cliente usa seus próprios secrets (sem hardcode) |
|
|
239
|
+
| **i18n nativo** | 3 locales + multi-country sem mudar código |
|
|
240
|
+
| **Zero PII em logs** | Apenas status HTTP e prefixo de erro |
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
> 📋 **Sua Função:** Garantir que todo lead capturado pelo CDP Edge (CTWA, formulário, /track) chegue no EVO CRM como contato + conversa aberta + nota interna estruturada, com PII normalizada (phone E.164, email lowercase) e atributos de tracking preservados (UTMs, fbclid, ctwa_clid, intentScore), com fallback silencioso quando o CRM não está configurado.
|
|
@@ -91,7 +91,7 @@ Master Orchestrator (você)
|
|
|
91
91
|
│ ├── Database Agent → migrações D1, schema, índices
|
|
92
92
|
│ ├── Domain Setup Agent → conecta track.clientdomain.com + cookie first-party
|
|
93
93
|
│ ├── R2 Setup Agent → habilita R2, cria bucket, ativa audit log imutável
|
|
94
|
-
│ └── CRM
|
|
94
|
+
│ └── EVO CRM Agent → roteia leads p/ EVO CRM (OAuth2 Doorkeeper)
|
|
95
95
|
│
|
|
96
96
|
├── 💬 COMUNICAÇÃO E NOTIFICAÇÕES
|
|
97
97
|
│ ├── WhatsApp Agent → automação Meta Cloud API + CallMeBot
|
|
@@ -173,7 +173,7 @@ SKILL_BASE: [diretório da skill tracking-events-generator]
|
|
|
173
173
|
├── database-agent.md ← migrações D1, schema, índices
|
|
174
174
|
├── domain-setup-agent.md ← track.clientdomain.com + Worker Route + cookie first-party
|
|
175
175
|
├── r2-setup-agent.md ← R2 bucket + audit log /events/YYYY-MM-DD/{uuid}.json
|
|
176
|
-
├── crm-
|
|
176
|
+
├── evo-crm-agent.md ← Agente EVO CRM (OAuth2)
|
|
177
177
|
│
|
|
178
178
|
├── ── COMUNICAÇÃO ──
|
|
179
179
|
├── whatsapp-agent.md ← Meta Cloud API + CallMeBot Bridge
|
|
@@ -897,7 +897,8 @@ FASE 5 (Geração em paralelo):
|
|
|
897
897
|
├─ FASE 5-J: YouTube Agent (gclid/wbraid/gbraid + video milestones)
|
|
898
898
|
├─ FASE 5-K: Microsoft Ads Agent (UET Tag + Enhanced Conversions)
|
|
899
899
|
├─ FASE 5-D: Server Tracking Agent (index.ts — todos os platforms)
|
|
900
|
-
|
|
900
|
+
├─ FASE 5-E: Webhook Agent (gateways: Hotmart, Kiwify, Eduzz, Ticto, etc.)
|
|
901
|
+
└─ FASE 5-L: EVO CRM Agent (roteia leads p/ EVO CRM)
|
|
901
902
|
```
|
|
902
903
|
|
|
903
904
|
FASE 6 (Enterprise Features — ordem de configuração):
|
|
@@ -1079,8 +1080,13 @@ Exibir:
|
|
|
1079
1080
|
**Bloco CartPanda** (incluir se CartPanda selecionado):
|
|
1080
1081
|
> - `CARTPANDA_TOKEN` — Token CartPanda webhook
|
|
1081
1082
|
|
|
1082
|
-
**Bloco
|
|
1083
|
-
> - `
|
|
1083
|
+
**Bloco EVO CRM (OAuth2)** (incluir se CRM selecionado):
|
|
1084
|
+
> - `EVO_CRM_BASE_URL` — URL base (ex: https://api-evocrm.dominio.com)
|
|
1085
|
+
> - `EVO_CRM_CLIENT_ID` — OAuth client_id
|
|
1086
|
+
> - `EVO_CRM_CLIENT_SECRET` — OAuth client_secret
|
|
1087
|
+
> - `EVO_CRM_INBOX_ID` — ID do inbox no CRM
|
|
1088
|
+
> - `EVO_CRM_DEFAULT_COUNTRY` — Dial code default (ex: 55)
|
|
1089
|
+
> - `EVO_CRM_LOCALE` — Locale das notas (pt-BR | en-US | es-ES)
|
|
1084
1090
|
|
|
1085
1091
|
**Sempre incluir:**
|
|
1086
1092
|
> - `SITE_URL` — URL do seu funil/site (ex: https://meusite.com.br)
|
package/package.json
CHANGED
|
@@ -366,8 +366,8 @@ pattern = "SEU_DOMINIO/track*" # ← Substituir pelo domínio real
|
|
|
366
366
|
zone_name = "SEU_DOMINIO" # ← Substituir pelo domínio real
|
|
367
367
|
|
|
368
368
|
# Exemplo real:
|
|
369
|
-
# pattern = "
|
|
370
|
-
# zone_name = "
|
|
369
|
+
# pattern = "cliente.com.br/track*"
|
|
370
|
+
# zone_name = "cliente.com.br"
|
|
371
371
|
```
|
|
372
372
|
|
|
373
373
|
#### 3. Fazer o deploy com as rotas
|
|
@@ -63,6 +63,9 @@ import {
|
|
|
63
63
|
processWhatsAppWebhook,
|
|
64
64
|
verifyHmac,
|
|
65
65
|
} from './modules/dispatch/whatsapp';
|
|
66
|
+
import {
|
|
67
|
+
pushLeadToCrm,
|
|
68
|
+
} from './modules/dispatch/crm';
|
|
66
69
|
|
|
67
70
|
// ── ML — LTV + A/B Testing ────────────────────────────────────────────────────
|
|
68
71
|
import {
|
|
@@ -239,6 +242,9 @@ export default {
|
|
|
239
242
|
WA_NOTIFY_NUMBER: env.WA_NOTIFY_NUMBER ? 'set' : 'not set (optional - only for auto-reply)',
|
|
240
243
|
TIKTOK_ACCESS_TOKEN: env.TIKTOK_ACCESS_TOKEN ? 'set' : 'not set (optional)',
|
|
241
244
|
CALLMEBOT_PHONE: env.CALLMEBOT_PHONE ? 'set' : 'not set (optional)',
|
|
245
|
+
EVO_CRM_BASE_URL: env.EVO_CRM_BASE_URL ? 'set' : 'not set (optional - EVO CRM)',
|
|
246
|
+
EVO_CRM_CLIENT_ID: env.EVO_CRM_CLIENT_ID ? 'set' : 'not set (optional - EVO CRM)',
|
|
247
|
+
EVO_CRM_INBOX_ID: env.EVO_CRM_INBOX_ID ? 'set' : 'not set (optional - EVO CRM)',
|
|
242
248
|
};
|
|
243
249
|
|
|
244
250
|
const hasMissing =
|
|
@@ -793,6 +799,39 @@ export default {
|
|
|
793
799
|
: []),
|
|
794
800
|
]);
|
|
795
801
|
|
|
802
|
+
// ── EVO CRM — cria contato + conversa + nota interna ─────────────────
|
|
803
|
+
// Silencioso se EVO_CRM_BASE_URL / EVO_CRM_CLIENT_ID não estiverem configurados.
|
|
804
|
+
const CRM_EVENTS = ['Lead', 'Contact', 'CompleteRegistration'];
|
|
805
|
+
if (CRM_EVENTS.includes(eventName) && trackPayload.phone) {
|
|
806
|
+
ctx.waitUntil(
|
|
807
|
+
pushLeadToCrm(env, {
|
|
808
|
+
phone: trackPayload.phone,
|
|
809
|
+
name: [trackPayload.firstName, trackPayload.lastName].filter(Boolean).join(' ') || null,
|
|
810
|
+
email: trackPayload.email || null,
|
|
811
|
+
fbclid: trackPayload.fbclid || null,
|
|
812
|
+
fbc: trackPayload.fbc || null,
|
|
813
|
+
fbp: trackPayload.fbp || null,
|
|
814
|
+
utmSource: trackPayload.utmSource || null,
|
|
815
|
+
utmMedium: trackPayload.utmMedium || null,
|
|
816
|
+
utmCampaign: trackPayload.utmCampaign || null,
|
|
817
|
+
utmContent: trackPayload.utmContent || null,
|
|
818
|
+
utmTerm: trackPayload.utmTerm || null,
|
|
819
|
+
pageUrl: trackPayload.pageUrl || null,
|
|
820
|
+
formName: trackPayload.contentName || trackPayload.productName || eventName,
|
|
821
|
+
eventName,
|
|
822
|
+
intentScore: typeof trackPayload.intent_score === 'number'
|
|
823
|
+
? trackPayload.intent_score
|
|
824
|
+
: typeof trackPayload.intentScoreNum === 'number'
|
|
825
|
+
? trackPayload.intentScoreNum
|
|
826
|
+
: null,
|
|
827
|
+
ltvClass: trackPayload.ltvClass || null,
|
|
828
|
+
funnelStage: trackPayload.funnel_stage || trackPayload.funnelDepth || null,
|
|
829
|
+
value: trackPayload.value ?? null,
|
|
830
|
+
currency: trackPayload.currency || null,
|
|
831
|
+
})
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
|
|
796
835
|
// Automação de mensagens
|
|
797
836
|
const AUTOMATION_EVENTS = ['Lead', 'Purchase', 'InitiateCheckout'];
|
|
798
837
|
if (AUTOMATION_EVENTS.includes(eventName) && env.DB) {
|