cdp-edge 2.0.1 → 2.0.3

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.
Files changed (34) hide show
  1. package/README.md +325 -308
  2. package/contracts/api-versions.json +12 -8
  3. package/dist/commands/install.js +1 -1
  4. package/dist/commands/setup.js +1 -1
  5. package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +23 -23
  6. package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +2 -2
  7. package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +20 -0
  8. package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +48 -16
  9. package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +7 -7
  10. package/extracted-skill/tracking-events-generator/agents/database-agent.md +8 -8
  11. package/extracted-skill/tracking-events-generator/agents/debug-agent.md +13 -13
  12. package/extracted-skill/tracking-events-generator/agents/devops-agent.md +31 -7
  13. package/extracted-skill/tracking-events-generator/agents/email-agent.md +27 -0
  14. package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +205 -0
  15. package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +6 -6
  16. package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +108 -0
  17. package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +1 -1
  18. package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +68 -8
  19. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +75 -38
  20. package/extracted-skill/tracking-events-generator/agents/performance-agent.md +29 -19
  21. package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +11 -1
  22. package/extracted-skill/tracking-events-generator/agents/premium-tracking-intelligence-agent.md +4 -4
  23. package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +137 -28
  24. package/extracted-skill/tracking-events-generator/agents/server-tracking.md +15 -16
  25. package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +1 -1
  26. package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +63 -0
  27. package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +100 -5
  28. package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +62 -4
  29. package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +58 -5
  30. package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +16 -16
  31. package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +143 -28
  32. package/extracted-skill/tracking-events-generator/contracts/api-versions.json +12 -8
  33. package/package.json +76 -76
  34. package/server-edge-tracker/worker.js +53 -8
@@ -212,10 +212,14 @@
212
212
  ]
213
213
  },
214
214
  "conversions_api": {
215
- "current": "v2",
216
- "minimum_supported": "v1",
217
- "recommended": "v2",
218
- "endpoint_pattern": "https://api.linkedin.com/rest/attributionConversions/{VERSION}",
215
+ "current": "202401",
216
+ "minimum_supported": "202401",
217
+ "recommended": "202401",
218
+ "endpoint_pattern": "https://api.linkedin.com/rest/conversionEvents",
219
+ "required_headers": {
220
+ "LinkedIn-Version": "202401",
221
+ "X-Restli-Protocol-Version": "2.0.0"
222
+ },
219
223
  "authentication": "Bearer token (LINKEDIN_ACCESS_TOKEN)",
220
224
  "rate_limits": {
221
225
  "requests_per_second": 10,
@@ -359,10 +363,10 @@
359
363
  },
360
364
 
361
365
  "last_updated_by": {
362
- "agent": "Intelligence Agent",
363
- "session_id": "CDP_2026-03-28_sync",
364
- "timestamp": "2026-03-28T00:00:00.000Z"
366
+ "agent": "Audit — CDP Edge v2.0",
367
+ "session_id": "CDP_2026-04-10_audit",
368
+ "timestamp": "2026-04-10T00:00:00.000Z"
365
369
  },
366
370
 
367
- "next_review_date": "2026-04-27T00:00:00.000Z"
371
+ "next_review_date": "2026-05-10T00:00:00.000Z"
368
372
  }
@@ -32,7 +32,7 @@ function printBanner() {
32
32
  console.log(chalk.cyan('╚██████╗██████╔╝██║ ███████╗██████╔╝╚██████╔╝███████╗'));
33
33
  console.log(chalk.cyan(' ╚═════╝╚═════╝ ╚═╝ ╚══════╝╚═════╝ ╚═════╝╚══════╝'));
34
34
  console.log('');
35
- console.log(chalk.gray(' Customer Data Platform on the Edge · Global Edge Tracking · v2.0.1'));
35
+ console.log(chalk.gray(' Customer Data Platform on the Edge · Global Edge Tracking · v2.0.3'));
36
36
  console.log('');
37
37
  console.log(chalk.gray('═'.repeat(68)));
38
38
  console.log('');
@@ -19,7 +19,7 @@ function printBanner() {
19
19
  console.log(chalk.cyan('╚██████╗██████╔╝██║ ███████╗██████╔╝╚██████╔╝███████╗'));
20
20
  console.log(chalk.cyan(' ╚═════╝╚═════╝ ╚═╝ ╚══════╝╚═════╝ ╚═════╝╚══════╝'));
21
21
  console.log('');
22
- console.log(chalk.gray(' Customer Data Platform on the Edge · Global Edge Tracking · v2.0.1'));
22
+ console.log(chalk.gray(' Customer Data Platform on the Edge · Global Edge Tracking · v2.0.3'));
23
23
  console.log('');
24
24
  console.log(chalk.gray('═'.repeat(68)));
25
25
  console.log('');
@@ -264,7 +264,7 @@ function wShapeAttribution(touchpoints) {
264
264
 
265
265
  ```javascript
266
266
  // Modelo Data-Driven simplificado
267
- async function dataDrivenAttribution(touchpoints, userJourneyHistory) {
267
+ async function dataDrivenAttribution(touchpoints, userJourneyHistory, env) {
268
268
  if (!touchpoints || touchpoints.length === 0) return [];
269
269
 
270
270
  // 1. Calcular pesos baseados em dados históricos
@@ -297,14 +297,14 @@ async function dataDrivenAttribution(touchpoints, userJourneyHistory) {
297
297
  }
298
298
 
299
299
  // Calcular peso de canal baseado em conversão histórica
300
- async function calculateChannelWeights(touchpoints, history) {
300
+ async function calculateChannelWeights(touchpoints, history, env) {
301
301
  const weights = {};
302
302
 
303
303
  for (const tp of touchpoints) {
304
304
  const channel = tp.utm_source;
305
305
 
306
306
  // Buscar conversões históricas deste canal
307
- const historicalConversions = await DB.prepare(`
307
+ const historicalConversions = await env.DB.prepare(`
308
308
  SELECT
309
309
  COUNT(*) as total_conversions,
310
310
  AVG(value) as avg_value
@@ -325,14 +325,14 @@ async function calculateChannelWeights(touchpoints, history) {
325
325
  }
326
326
 
327
327
  // Calcular peso de posição baseado em conversão histórica
328
- async function calculatePositionWeights(touchpoints, history) {
328
+ async function calculatePositionWeights(touchpoints, history, env) {
329
329
  const weights = {};
330
330
 
331
331
  for (const tp of touchpoints) {
332
332
  const position = tp.position; // 0 = first, 1 = second, etc.
333
333
 
334
334
  // Buscar conversões históricas nesta posição
335
- const historicalConversions = await DB.prepare(`
335
+ const historicalConversions = await env.DB.prepare(`
336
336
  SELECT
337
337
  COUNT(*) as total_conversions
338
338
  FROM multi_touch_attribution
@@ -458,7 +458,7 @@ CREATE INDEX IF NOT EXISTS idx_channel_model ON channel_performance(attribution_
458
458
 
459
459
  ```javascript
460
460
  // Capturar touchpoint da jornada
461
- export async function captureTouchpoint(eventData, request) {
461
+ export async function captureTouchpoint(eventData, request, env) {
462
462
  const {
463
463
  user_id,
464
464
  session_id,
@@ -485,7 +485,7 @@ export async function captureTouchpoint(eventData, request) {
485
485
  const position = await calculateJourneyPosition(user_id, event_timestamp);
486
486
 
487
487
  // Persistir touchpoint no D1
488
- await DB.prepare(`
488
+ await env.DB.prepare(`
489
489
  INSERT INTO user_journeys
490
490
  (user_id, session_id, email, event_id, event_name,
491
491
  utm_source, utm_medium, utm_campaign, utm_content, utm_term,
@@ -512,8 +512,8 @@ export async function captureTouchpoint(eventData, request) {
512
512
  }
513
513
 
514
514
  // Calcular posição na jornada
515
- async function calculateJourneyPosition(userId, eventTimestamp) {
516
- const result = await DB.prepare(`
515
+ async function calculateJourneyPosition(userId, eventTimestamp, env) {
516
+ const result = await env.DB.prepare(`
517
517
  SELECT COUNT(*) as position
518
518
  FROM user_journeys
519
519
  WHERE user_id = ? AND event_timestamp < ?
@@ -523,7 +523,7 @@ async function calculateJourneyPosition(userId, eventTimestamp) {
523
523
  }
524
524
 
525
525
  // Agendar cálculo de atribuição (via Cloudflare Queue)
526
- async function scheduleAttributionCalculation(email, conversionId, eventName) {
526
+ async function scheduleAttributionCalculation(email, conversionId, eventName, env) {
527
527
  await QUEUE.send('cdp-edge-attribution', {
528
528
  type: 'CALCULATE_ATTRIBUTION',
529
529
  email,
@@ -538,7 +538,7 @@ async function scheduleAttributionCalculation(email, conversionId, eventName) {
538
538
 
539
539
  ```javascript
540
540
  // Calcular atribuição multi-touch
541
- export async function calculateMultiTouchAttribution(conversionData) {
541
+ export async function calculateMultiTouchAttribution(conversionData, env) {
542
542
  const {
543
543
  email,
544
544
  conversion_id,
@@ -548,7 +548,7 @@ export async function calculateMultiTouchAttribution(conversionData) {
548
548
  } = conversionData;
549
549
 
550
550
  // 1. Buscar jornada completa do usuário
551
- const journey = await DB.prepare(`
551
+ const journey = await env.DB.prepare(`
552
552
  SELECT
553
553
  user_id,
554
554
  session_id,
@@ -594,7 +594,7 @@ export async function calculateMultiTouchAttribution(conversionData) {
594
594
  // 3. Persistir atribuição para cada modelo
595
595
  for (const [modelName, attribution] of Object.entries(attributionModels)) {
596
596
  for (const touchpoint of attribution) {
597
- await DB.prepare(`
597
+ await env.DB.prepare(`
598
598
  INSERT OR REPLACE INTO multi_touch_attribution
599
599
  (conversion_id, user_id, email, attribution_model, touchpoint_index,
600
600
  utm_source, utm_medium, utm_campaign, event_name, event_timestamp,
@@ -628,7 +628,7 @@ export async function calculateMultiTouchAttribution(conversionData) {
628
628
  }
629
629
 
630
630
  // Atualizar performance de canal
631
- async function updateChannelPerformance(attributionModels, value, currency) {
631
+ async function updateChannelPerformance(attributionModels, value, currency, env) {
632
632
  const today = new Date().toISOString().split('T')[0];
633
633
 
634
634
  for (const [modelName, attribution] of Object.entries(attributionModels)) {
@@ -660,7 +660,7 @@ async function updateChannelPerformance(attributionModels, value, currency) {
660
660
 
661
661
  // Atualizar tabela de performance
662
662
  for (const perf of Object.values(channelPerformance)) {
663
- await DB.prepare(`
663
+ await env.DB.prepare(`
664
664
  INSERT OR REPLACE INTO channel_performance
665
665
  (utm_source, utm_medium, utm_campaign, attribution_model,
666
666
  total_attribution, total_conversions, total_value, avg_conversion_value, date)
@@ -685,7 +685,7 @@ async function updateChannelPerformance(attributionModels, value, currency) {
685
685
 
686
686
  ```javascript
687
687
  // Enviar Purchase com atribuição calculada
688
- export async function sendPurchaseWithAttribution(conversionData, attributionModel = 'U_SHAPE') {
688
+ export async function sendPurchaseWithAttribution(conversionData, env, attributionModel = 'U_SHAPE') {
689
689
  const {
690
690
  email,
691
691
  conversion_id,
@@ -695,7 +695,7 @@ export async function sendPurchaseWithAttribution(conversionData, attributionMod
695
695
  } = conversionData;
696
696
 
697
697
  // 1. Buscar atribuição calculada
698
- const attribution = await DB.prepare(`
698
+ const attribution = await env.DB.prepare(`
699
699
  SELECT
700
700
  utm_source,
701
701
  utm_medium,
@@ -773,7 +773,7 @@ async function sendMetaPurchaseWithAttribution(purchaseData, attribution) {
773
773
  const response = await fetch('https://graph.facebook.com/v22.0/events', {
774
774
  method: 'POST',
775
775
  headers: {
776
- 'Authorization': `Bearer ${META_ACCESS_TOKEN}`,
776
+ 'Authorization': `Bearer ${env.META_ACCESS_TOKEN}`,
777
777
  'Content-Type': 'application/json'
778
778
  },
779
779
  body: JSON.stringify({ data: [payload] })
@@ -829,7 +829,7 @@ async function sendTikTokPurchaseWithAttribution(purchaseData, attribution) {
829
829
  const response = await fetch('https://business-api.tiktok.com/open_api/v1.3/pixel/conversion/', {
830
830
  method: 'POST',
831
831
  headers: {
832
- 'Authorization': `Bearer ${TIKTOK_ACCESS_TOKEN}`,
832
+ 'Authorization': `Bearer ${env.TIKTOK_ACCESS_TOKEN}`,
833
833
  'Content-Type': 'application/json'
834
834
  },
835
835
  body: JSON.stringify(payload)
@@ -1036,7 +1036,7 @@ export async function getAttributionForConversion(request, env) {
1036
1036
  }
1037
1037
 
1038
1038
  // Buscar atribuição calculada
1039
- const attribution = await DB.prepare(`
1039
+ const attribution = await env.DB.prepare(`
1040
1040
  SELECT
1041
1041
  utm_source,
1042
1042
  utm_medium,
@@ -1052,7 +1052,7 @@ export async function getAttributionForConversion(request, env) {
1052
1052
  `).bind(conversionId, model).all();
1053
1053
 
1054
1054
  // Buscar dados da conversão
1055
- const conversion = await DB.prepare(`
1055
+ const conversion = await env.DB.prepare(`
1056
1056
  SELECT
1057
1057
  value,
1058
1058
  currency,
@@ -1096,7 +1096,7 @@ export async function compareAttributionModels(request, env) {
1096
1096
  const comparison = {};
1097
1097
 
1098
1098
  for (const model of ATTRIBUTION_CONFIG.available_models) {
1099
- const attribution = await DB.prepare(`
1099
+ const attribution = await env.DB.prepare(`
1100
1100
  SELECT
1101
1101
  utm_source,
1102
1102
  credit_percentage
@@ -1136,7 +1136,7 @@ export async function getChannelPerformance(request, env) {
1136
1136
  const days = parseInt(url.searchParams.get('days') || '30');
1137
1137
  const groupBy = url.searchParams.get('group_by') || 'source'; // 'source' ou 'campaign'
1138
1138
 
1139
- const performance = await DB.prepare(`
1139
+ const performance = await env.DB.prepare(`
1140
1140
  SELECT
1141
1141
  ${groupBy === 'source' ? 'utm_source' : 'utm_campaign'} as group_by,
1142
1142
  SUM(total_attribution) as total_attribution,
@@ -33,7 +33,7 @@ Database: Cloudflare D1 (Persistência)
33
33
  ## 📊 FUNCIONALIDADES DO SDK
34
34
 
35
35
  ### 1. Direct Fetch
36
- O rastreamento utiliza chamadas diretas via `fetch()` para o endpoint `/api/tracking` no mesmo domínio.
36
+ O rastreamento utiliza chamadas diretas via `fetch()` para o endpoint `/track` no mesmo domínio.
37
37
 
38
38
  ### 2. Deduplicação
39
39
  Gera um `event_id` único para cada evento disparado no browser para que o Worker possa bater com a CAPI.
@@ -311,7 +311,7 @@ document.getElementById('buy-btn').addEventListener('click', function() {
311
311
  | Depende de | Input Esperado | O que faz com isso |
312
312
  |-------------|----------------|------------------|
313
313
  | **Page Analyzer** | Lista de elementos HTML | Mapeia `content_name` e `content_id` |
314
- | **Server Tracking Agent** | Lista de plataformas | Adiciona endpoint Spotify `/api/wh/spotify` |
314
+ | **Server Tracking Agent** | Lista de plataformas | Adiciona endpoint Spotify `/webhook/spotify` |
315
315
  | **Premium Tracking Intelligence** | Estratégia de tracking | Define eventos prioritários para Spotify |
316
316
  | **Validator Agent** | Código gerado | Valida conformidade com Spotify API v1 |
317
317
 
@@ -2044,6 +2044,26 @@ async function handleGetCurrentPolicy(request, env) {
2044
2044
  - **security-enterprise-agent.md**: Usa encryption de PII para LGPD/GDPR
2045
2045
  - **attribution-agent.md**: Respeita consentimento para analytics e marketing
2046
2046
  - **master-orchestrator.md**: Implementa middleware de consentimento antes de tracking
2047
+ - **validator-agent.md**: O Compliance Agent DEVE ser consultado pelo Validator Agent para verificar conformidade de PII. Fluxo:
2048
+
2049
+ ```
2050
+ validator-agent (auditoria do código gerado)
2051
+ └─► checkComplianceCompliance(generatedCode)
2052
+ ├─ Verificar: SHA-256 aplicado em todos os campos PII (em, ph, fn, ln)?
2053
+ ├─ Verificar: Google Consent Mode v2 implementado (ad_storage, analytics_storage)?
2054
+ ├─ Verificar: url_passthrough: true ativo?
2055
+ ├─ Verificar: PII nunca logada em plaintext?
2056
+ └─ Verificar: opt-in explícito antes de tracking de marketing?
2057
+
2058
+ // No validator-agent, chamar:
2059
+ const complianceCheck = await validateComplianceRequirements(generatedBrowserCode, generatedWorkerCode);
2060
+ if (!complianceCheck.passed) {
2061
+ // Bloquear entrega e reportar issues ao Master Orchestrator
2062
+ return { status: 'BLOCKED', issues: complianceCheck.issues };
2063
+ }
2064
+ ```
2065
+
2066
+ - **google-agent.md**: Consent Mode v2 gerado por este agente valida conformidade detectada pelo Compliance Agent
2047
2067
 
2048
2068
  ---
2049
2069
 
@@ -12,6 +12,38 @@ Você é o **Agente de Integração CRM do CDP Edge**. Sua responsabilidade: **c
12
12
 
13
13
  ---
14
14
 
15
+ ## 🔗 FLUXO DE ATIVAÇÃO (Como este agente é chamado)
16
+
17
+ O CRM Integration Agent é ativado pelo **Webhook Agent** após confirmação de compra ou captura de lead:
18
+
19
+ ```
20
+ Webhook Agent (purchase confirmado)
21
+ └─► ctx.waitUntil(syncToCRM(env, 'purchase', payload))
22
+
23
+ ├─ Criar/atualizar contato no CRM com status 'customer'
24
+ ├─ Criar negócio/oportunidade com valor da compra
25
+ └─ Atualizar D1 com CRM_CONTACT_ID para rastreamento futuro
26
+
27
+ Webhook Agent (lead capturado via /track)
28
+ └─► ctx.waitUntil(syncToCRM(env, 'lead', payload))
29
+
30
+ ├─ Criar contato no CRM com status 'lead'
31
+ └─ Registrar no D1 para cruzamento futuro
32
+ ```
33
+
34
+ **Assinatura da função exportada (injetada no Worker):**
35
+
36
+ ```javascript
37
+ // Injetada no worker.js pelo CRM Integration Agent
38
+ export async function syncToCRM(env, eventType, payload) {
39
+ // eventType: 'lead' | 'purchase' | 'checkout_abandoned'
40
+ // payload: { email, name, product, value, order_id, phone }
41
+ // Retorna: { success: boolean, crm_contact_id: string | null }
42
+ }
43
+ ```
44
+
45
+ ---
46
+
15
47
  ## 🎯 OBJETIVO PRINCIPAL
16
48
 
17
49
  Implementar **integração bidirecional** entre CDP Edge D1 e CRMs externos, permitindo que dados de tracking (leads, purchases, user journeys) fluam automaticamente para sistemas de vendas, marketing e atendimento, eliminando importações manuais e maximizando conversão.
@@ -612,8 +644,8 @@ export const PURCHASE_FIELD_MAPPINGS = {
612
644
 
613
645
  ```javascript
614
646
  // Sincronizar leads do D1 para CRM em batch
615
- export async function syncLeadsToCRM(hours = 24, batchSize = 50) {
616
- const leads = await DB.prepare(`
647
+ export async function syncLeadsToCRM(env, hours = 24, batchSize = 50) {
648
+ const leads = await env.DB.prepare(`
617
649
  SELECT * FROM leads
618
650
  WHERE created_at > datetime('now', '-${hours} hours')
619
651
  ORDER BY created_at DESC
@@ -699,8 +731,8 @@ async function sendLeadsBatchToCRM(leadsBatch) {
699
731
  };
700
732
  }
701
733
 
702
- async function markLeadAsSynced(leadId) {
703
- await DB.prepare(`
734
+ async function markLeadAsSynced(leadId, env) {
735
+ await env.DB.prepare(`
704
736
  UPDATE leads SET crm_synced = 1, crm_synced_at = datetime('now')
705
737
  WHERE id = ?
706
738
  `).bind(leadId).run();
@@ -711,8 +743,8 @@ async function markLeadAsSynced(leadId) {
711
743
 
712
744
  ```javascript
713
745
  // Sincronizar compras do D1 para CRM em batch
714
- export async function syncPurchasesToCRM(hours = 24, batchSize = 20) {
715
- const purchases = await DB.prepare(`
746
+ export async function syncPurchasesToCRM(env, hours = 24, batchSize = 20) {
747
+ const purchases = await env.DB.prepare(`
716
748
  SELECT p.*, l.email
717
749
  FROM purchases p
718
750
  LEFT JOIN leads l ON p.lead_id = l.id
@@ -800,8 +832,8 @@ async function sendPurchasesBatchToCRM(purchasesBatch) {
800
832
  };
801
833
  }
802
834
 
803
- async function markPurchaseAsSynced(purchaseId) {
804
- await DB.prepare(`
835
+ async function markPurchaseAsSynced(purchaseId, env) {
836
+ await env.DB.prepare(`
805
837
  UPDATE purchases SET crm_synced = 1, crm_synced_at = datetime('now')
806
838
  WHERE id = ?
807
839
  `).bind(purchaseId).run();
@@ -853,8 +885,8 @@ export async function handleCRMWebhook(request, env) {
853
885
  }
854
886
  }
855
887
 
856
- async function updateLeadStageFromCRM(payload) {
857
- await DB.prepare(`
888
+ async function updateLeadStageFromCRM(payload, env) {
889
+ await env.DB.prepare(`
858
890
  UPDATE leads SET crm_stage = ?, crm_stage_updated_at = datetime('now')
859
891
  WHERE email = ?
860
892
  `).bind(payload.stage, payload.email).run();
@@ -862,8 +894,8 @@ async function updateLeadStageFromCRM(payload) {
862
894
  console.log(`Stage do lead ${payload.email} atualizado para: ${payload.stage}`);
863
895
  }
864
896
 
865
- async function updateDealStatusFromCRM(payload) {
866
- await DB.prepare(`
897
+ async function updateDealStatusFromCRM(payload, env) {
898
+ await env.DB.prepare(`
867
899
  UPDATE purchases SET crm_deal_status = ?, crm_deal_status_updated_at = datetime('now')
868
900
  WHERE transaction_id = ?
869
901
  `).bind(payload.status, payload.transaction_id).run();
@@ -871,8 +903,8 @@ async function updateDealStatusFromCRM(payload) {
871
903
  console.log(`Status da compra ${payload.transaction_id} atualizado para: ${payload.status}`);
872
904
  }
873
905
 
874
- async function updateLeadScoreFromCRM(payload) {
875
- await DB.prepare(`
906
+ async function updateLeadScoreFromCRM(payload, env) {
907
+ await env.DB.prepare(`
876
908
  UPDATE leads SET lead_score = ?, lead_score_updated_at = datetime('now')
877
909
  WHERE email = ?
878
910
  `).bind(payload.lead_score, payload.email).run();
@@ -979,7 +1011,7 @@ export async function registerCRMWebhooks(crmType, webhookUrl) {
979
1011
  };
980
1012
 
981
1013
  // Salvar configuração no D1
982
- await DB.prepare(`
1014
+ await env.DB.prepare(`
983
1015
  INSERT INTO crm_webhook_config (webhook_url, crm_type, events, signature_enabled)
984
1016
  VALUES (?, ?, ?, ?)
985
1017
  `).bind(
@@ -994,7 +1026,7 @@ export async function registerCRMWebhooks(crmType, webhookUrl) {
994
1026
 
995
1027
  // Endpoint de saúde da integração
996
1028
  export async function handleCRMHealthCheck(request, env) {
997
- const stats = await DB.prepare(`
1029
+ const stats = await env.DB.prepare(`
998
1030
  SELECT
999
1031
  COUNT(*) as total_leads,
1000
1032
  COUNT(CASE WHEN crm_synced = 1 THEN 1 END) as synced_leads,
@@ -96,16 +96,16 @@ Definir o Dashboard como um **Centro de Comando de Dados** que equilibra:
96
96
  **Implementação:**
97
97
  ```javascript
98
98
  // Carregar dados do cache
99
- const fetchMetrics = async (forceRefresh = false) => {
99
+ const fetchMetrics = async (env, forceRefresh = false) => {
100
100
  const cacheKey = 'dashboard_metrics';
101
- const cached = await KV.get(cacheKey);
101
+ const cached = await env.GEO_CACHE.get(cacheKey);
102
102
 
103
103
  if (cached && !forceRefresh) {
104
104
  return JSON.parse(cached);
105
105
  }
106
106
 
107
107
  // Cache miss ou refresh forçado — consultar D1
108
- const metrics = await DB.prepare(`
108
+ const metrics = await env.DB.prepare(`
109
109
  SELECT
110
110
  AVG(heat_score) as avg_heat,
111
111
  COUNT(DISTINCT fingerprint) as total_users,
@@ -115,7 +115,7 @@ const fetchMetrics = async (forceRefresh = false) => {
115
115
  `).all();
116
116
 
117
117
  // Salvar no KV com TTL de 1 hora
118
- await KV.put(cacheKey, JSON.stringify(metrics), { expirationTtl: 3600 });
118
+ await env.GEO_CACHE.put(cacheKey, JSON.stringify(metrics), { expirationTtl: 3600 });
119
119
 
120
120
  return metrics;
121
121
  };
@@ -217,13 +217,13 @@ export const DASHBOARD_API = {
217
217
  };
218
218
 
219
219
  // HANDLER DE SINCronizaÇÃO (atualização de cache)
220
- export async function invalidateCache(domain, pattern) {
220
+ export async function invalidateCache(domain, pattern, env) {
221
221
  const deletePattern = `${domain}:${pattern}`;
222
222
 
223
223
  // Deletar do KV
224
- const keys = await KV.list({ prefix: deletePattern });
224
+ const keys = await env.GEO_CACHE.list({ prefix: deletePattern });
225
225
  for (const key of keys.keys) {
226
- await KV.delete(key);
226
+ await env.GEO_CACHE.delete(key);
227
227
  }
228
228
 
229
229
  // Retornar contagem
@@ -78,7 +78,7 @@ crons = ["0 2 * * 7", "0 3 1 * *"]
78
78
  - **ID:** `SEU_D1_DATABASE_ID`
79
79
  - **Região:** ENAM (US East)
80
80
  - **Engine:** SQLite (Cloudflare D1)
81
- - **Tabelas ativas:** 8
81
+ - **Tabelas ativas:** 24 (core: 13, migrate-v6: 1, Enterprise Fases 1-4: 10)
82
82
 
83
83
  ### Schema Completo (Produção)
84
84
 
@@ -259,7 +259,7 @@ CREATE INDEX IF NOT EXISTS idx_wa_ctwa_clid ON whatsapp_contacts(ctwa_clid);
259
259
  CREATE INDEX IF NOT EXISTS idx_wa_created_at ON whatsapp_contacts(created_at);
260
260
  ```
261
261
  > **Migration:** `migrate-v6.sql` — aplicar com `wrangler d1 execute cdp-edge-db --file=migrate-v6.sql --remote`
262
- > **Tabelas ativas após v6:** 9
262
+ > **Tabelas ativas após v6:** 14 (core: 13 + whatsapp_contacts)
263
263
 
264
264
  ---
265
265
 
@@ -313,9 +313,9 @@ ctx.waitUntil(
313
313
 
314
314
  ---
315
315
 
316
- ## 📬 BINDING 2 — QUEUES (`env.QUEUE`) — *A Adicionar*
316
+ ## 📬 BINDING 2 — QUEUES (`env.RETRY_QUEUE`) — Configurado
317
317
 
318
- > **Status:** Arquitetado, ainda não configurado no `wrangler.toml`. Adicionar para habilitar retry assíncrono robusto.
318
+ > **Status:** Ativo em produção `wrangler.toml` com `RETRY_QUEUE` binding e consumer configurados.
319
319
 
320
320
  ### Configuração no `wrangler.toml`
321
321
  ```toml
@@ -387,9 +387,9 @@ Queue Consumer (assíncrono)
387
387
 
388
388
  ---
389
389
 
390
- ## 🗂️ BINDING 3 — KV NAMESPACE (`env.GEO_CACHE`) — *A Adicionar*
390
+ ## 🗂️ BINDING 3 — KV NAMESPACE (`env.GEO_CACHE`) — Configurado
391
391
 
392
- > **Status:** Arquitetado para cache de geo/IP. Ainda não configurado.
392
+ > **Status:** Ativo em produção — usado para geo cache, fraud blocklist, fraud velocity counters e A/B test cache.
393
393
 
394
394
  ### Configuração no `wrangler.toml`
395
395
  ```toml
@@ -548,7 +548,7 @@ async function runIntelligenceAgent(cron, env) {
548
548
  | `META_TEST_CODE` | ⚠️ Reconfigurar | Só testes | meta-agent |
549
549
  | `META_AD_ACCOUNT_ID` | ⚠️ Reconfigurar | Customer Match | meta-agent |
550
550
  | `META_AUDIENCE_ID` | ⚠️ Reconfigurar | Customer Match | meta-agent |
551
- | `WHATSAPP_TOKEN` | ⚠️ Reconfigurar | WhatsApp | whatsapp-agent |
551
+ | `WHATSAPP_ACCESS_TOKEN` | ⚠️ Reconfigurar | WhatsApp | whatsapp-agent |
552
552
  | `WHATSAPP_PHONE_NUMBER_ID` | ⚠️ Reconfigurar | WhatsApp | whatsapp-agent |
553
553
  | `RESEND_API_KEY` | ⚠️ Reconfigurar | Email | email-agent |
554
554
  | `RESEND_FROM_EMAIL` | ⚠️ Reconfigurar | Email | email-agent |
@@ -560,7 +560,7 @@ async function runIntelligenceAgent(cron, env) {
560
560
  wrangler secret put META_ACCESS_TOKEN
561
561
  wrangler secret put GA4_API_SECRET
562
562
  wrangler secret put TIKTOK_ACCESS_TOKEN
563
- wrangler secret put WHATSAPP_TOKEN
563
+ wrangler secret put WHATSAPP_ACCESS_TOKEN
564
564
  wrangler secret put WHATSAPP_PHONE_NUMBER_ID
565
565
  wrangler secret put RESEND_API_KEY
566
566
  wrangler secret put RESEND_FROM_EMAIL
@@ -56,9 +56,9 @@ export function logWorker(level, category, message, context = {}) {
56
56
  console.log(`[${level}] [${category}] ${message}`, JSON.stringify(context));
57
57
  }
58
58
 
59
- async function persistLogEntry(logEntry) {
59
+ async function persistLogEntry(env, logEntry) {
60
60
  try {
61
- await DB.prepare(`
61
+ await env.DB.prepare(`
62
62
  INSERT INTO worker_logs (timestamp, level, category, message, context, session_id, request_id)
63
63
  VALUES (?, ?, ?, ?, ?, ?, ?)
64
64
  `).bind(
@@ -82,7 +82,7 @@ async function dispatchEventToMeta(event, userContext) {
82
82
  try {
83
83
  const response = await fetch('https://graph.facebook.com/v22.0/events', {
84
84
  method: 'POST',
85
- headers: { 'Authorization': `Bearer ${META_ACCESS_TOKEN}` },
85
+ headers: { 'Authorization': `Bearer ${env.META_ACCESS_TOKEN}` },
86
86
  body: JSON.stringify(event)
87
87
  });
88
88
 
@@ -221,7 +221,7 @@ cdpTrack.track = function(eventName, params) {
221
221
  };
222
222
 
223
223
  // Enviar para Worker
224
- fetch('/api/track', {
224
+ fetch('/track', {
225
225
  method: 'POST',
226
226
  headers: { 'Content-Type': 'application/json' },
227
227
  body: JSON.stringify(eventPayload)
@@ -331,7 +331,7 @@ export async function handleDebugRequest(request, env) {
331
331
  }
332
332
 
333
333
  async function getApiHealth(platform) {
334
- const recentFailures = await DB.prepare(`
334
+ const recentFailures = await env.DB.prepare(`
335
335
  SELECT
336
336
  COUNT(*) as failure_count,
337
337
  MAX(created_at) as last_failure_at
@@ -339,7 +339,7 @@ async function getApiHealth(platform) {
339
339
  WHERE platform = ? AND created_at > datetime('now', '-1 hour')
340
340
  `).bind(platform).get();
341
341
 
342
- const recentSuccesses = await DB.prepare(`
342
+ const recentSuccesses = await env.DB.prepare(`
343
343
  SELECT COUNT(*) as success_count
344
344
  FROM events_log
345
345
  WHERE platform = ? AND status = 'success' AND created_at > datetime('now', '-1 hour')
@@ -394,7 +394,7 @@ export async function handleHealthCheck(request, env) {
394
394
  }
395
395
 
396
396
  async function getSimpleApiHealth(platform) {
397
- const lastSuccess = await DB.prepare(`
397
+ const lastSuccess = await env.DB.prepare(`
398
398
  SELECT created_at
399
399
  FROM events_log
400
400
  WHERE platform = ? AND status = 'success'
@@ -402,7 +402,7 @@ async function getSimpleApiHealth(platform) {
402
402
  LIMIT 1
403
403
  `).bind(platform).get();
404
404
 
405
- const lastFailure = await DB.prepare(`
405
+ const lastFailure = await env.DB.prepare(`
406
406
  SELECT created_at
407
407
  FROM api_failures
408
408
  WHERE platform = ?
@@ -433,7 +433,7 @@ export async function handleEventsLogRequest(request, env) {
433
433
  const limit = parseInt(url.searchParams.get('limit') || '50');
434
434
  const hours = parseInt(url.searchParams.get('hours') || '24');
435
435
 
436
- const events = await DB.prepare(`
436
+ const events = await env.DB.prepare(`
437
437
  SELECT
438
438
  event_name,
439
439
  platform,
@@ -485,7 +485,7 @@ export async function handleEventsLogRequest(request, env) {
485
485
 
486
486
  - [ ] **Envio de eventos para Worker:**
487
487
  - [ ] Verificar Network tab em Developer Tools
488
- - [ ] Confirmar requisição para `/api/track`
488
+ - [ ] Confirmar requisição para `/track`
489
489
  - [ ] Verificar status da resposta (deve ser 200 OK)
490
490
  - [ ] Verificar payload enviado (deve conter event_name, params, timestamp)
491
491
 
@@ -1033,7 +1033,7 @@ export async function handleEventsLogRequest(request, env) {
1033
1033
  const limit = parseInt(url.searchParams.get('limit') || '50');
1034
1034
  const hours = parseInt(url.searchParams.get('hours') || '24');
1035
1035
 
1036
- const events = await DB.prepare(`
1036
+ const events = await env.DB.prepare(`
1037
1037
  SELECT event_name, platform, status, error_message, created_at
1038
1038
  FROM events_log
1039
1039
  WHERE created_at > datetime('now', '-${hours} hours')
@@ -1057,7 +1057,7 @@ export async function handleBrowserLogs(request, env) {
1057
1057
 
1058
1058
  // Persistir logs do browser no D1
1059
1059
  for (const log of logs) {
1060
- await DB.prepare(`
1060
+ await env.DB.prepare(`
1061
1061
  INSERT INTO browser_logs (timestamp, level, category, message, context, session_id, page_url)
1062
1062
  VALUES (?, ?, ?, ?, ?, ?, ?)
1063
1063
  `).bind(
@@ -1182,7 +1182,7 @@ window.pbDebugLogger = logger;
1182
1182
  **Possíveis Causas:**
1183
1183
 
1184
1184
  1. **Evento não está sendo enviado para a plataforma**
1185
- - Verificar se `/api/track` está recebendo o evento
1185
+ - Verificar se `/track` está recebendo o evento
1186
1186
  - Consultar `/api/events-log` para ver se evento foi processado
1187
1187
  - Verificar logs do Worker: `wrangler tail`
1188
1188