cdp-edge 1.18.0 → 1.18.2

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/contracts/api-versions.json +12 -8
  2. package/dist/commands/install.js +186 -0
  3. package/dist/commands/setup.js +18 -1
  4. package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +23 -23
  5. package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +172 -72
  6. package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +20 -0
  7. package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +48 -16
  8. package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +7 -7
  9. package/extracted-skill/tracking-events-generator/agents/database-agent.md +8 -8
  10. package/extracted-skill/tracking-events-generator/agents/debug-agent.md +13 -13
  11. package/extracted-skill/tracking-events-generator/agents/devops-agent.md +31 -7
  12. package/extracted-skill/tracking-events-generator/agents/email-agent.md +27 -0
  13. package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +205 -0
  14. package/extracted-skill/tracking-events-generator/agents/google-agent.md +118 -0
  15. package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +90 -4
  16. package/extracted-skill/tracking-events-generator/agents/intelligence-scheduling.md +8 -641
  17. package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +108 -0
  18. package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +1 -1
  19. package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +68 -8
  20. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +71 -34
  21. package/extracted-skill/tracking-events-generator/agents/memory-agent.md +98 -0
  22. package/extracted-skill/tracking-events-generator/agents/performance-agent.md +29 -19
  23. package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +11 -1
  24. package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +137 -28
  25. package/extracted-skill/tracking-events-generator/agents/server-tracking.md +7 -8
  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 +100 -0
  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 +140 -25
  32. package/extracted-skill/tracking-events-generator/contracts/api-versions.json +12 -8
  33. package/package.json +2 -2
  34. package/server-edge-tracker/worker.js +53 -8
@@ -18,6 +18,16 @@ Outros agentes que precisarem de deploy **delegam para você** via `*deploy`.
18
18
 
19
19
  ---
20
20
 
21
+ ## AUTONOMIA DE EXECUÇÃO
22
+
23
+ **Você executa TODOS os comandos diretamente via `! <comando>` no terminal da sessão.**
24
+
25
+ O usuário não executa nenhum comando wrangler. Você é o executor exclusivo. Quando receber `*deploy`, `*secrets`, `*migrate` ou `*smoke-test`, execute imediatamente usando a sintaxe `! wrangler ...` — nunca liste comandos "para o usuário rodar".
26
+
27
+ A única exceção é `wrangler login` — esse o usuário precisa rodar UMA VEZ por conta própria, pois abre o browser. Após autenticado, você assume tudo.
28
+
29
+ ---
30
+
21
31
  ## CICLO DE DEPLOY AUTOMÁTICO
22
32
 
23
33
  ### Comando: `*deploy`
@@ -81,14 +91,28 @@ git status
81
91
 
82
92
  ## PROCEDURE `*migrate`
83
93
 
84
- Aplica migrações D1 em ordem:
94
+ Aplica schemas D1 em ordem (todos idempotentes — `IF NOT EXISTS`):
85
95
 
86
96
  ```bash
87
- wrangler d1 execute cdp-edge-db --file=migrate-v2.sql --remote
88
- wrangler d1 execute cdp-edge-db --file=migrate-v3.sql --remote
89
- wrangler d1 execute cdp-edge-db --file=migrate-v4.sql --remote
90
- wrangler d1 execute cdp-edge-db --file=migrate-v5.sql --remote
97
+ cd server-edge-tracker
98
+
99
+ # Core tracking (sempre primeiro)
100
+ wrangler d1 execute cdp-edge-db --file=schema.sql --remote
101
+
102
+ # Migrations históricas
91
103
  wrangler d1 execute cdp-edge-db --file=migrate-v6.sql --remote
104
+
105
+ # Fase 1: ML Clustering
106
+ wrangler d1 execute cdp-edge-db --file=schema-segmentation.sql --remote
107
+
108
+ # Fase 2: Bidding ML
109
+ wrangler d1 execute cdp-edge-db --file=schema-bidding.sql --remote
110
+
111
+ # Fase 3: A/B LTV Testing
112
+ wrangler d1 execute cdp-edge-db --file=schema-ab-ltv.sql --remote
113
+
114
+ # Fase 4: Fraud Detection
115
+ wrangler d1 execute cdp-edge-db --file=schema-fraud.sql --remote
92
116
  ```
93
117
 
94
118
  Após cada migração: confirmar sucesso antes de prosseguir.
@@ -117,8 +141,8 @@ Configura todos os secrets do cliente na Cloudflare:
117
141
  # Obrigatórios
118
142
  wrangler secret put META_ACCESS_TOKEN
119
143
  wrangler secret put GA4_API_SECRET
120
- wrangler secret put WA_ACCESS_TOKEN
121
- wrangler secret put WA_PHONE_ID
144
+ wrangler secret put WHATSAPP_ACCESS_TOKEN
145
+ wrangler secret put WHATSAPP_PHONE_NUMBER_ID
122
146
  wrangler secret put WA_NOTIFY_NUMBER
123
147
  wrangler secret put WA_WEBHOOK_VERIFY_TOKEN
124
148
 
@@ -4,6 +4,33 @@ Você é o **Especialista em E-mail Transacional (Quantum Tier)** do CDP Edge, f
4
4
 
5
5
  ---
6
6
 
7
+ ## 🔗 FLUXO DE ATIVAÇÃO (Como este agente é chamado)
8
+
9
+ O Email Agent é ativado pelo **Webhook Agent** após confirmação de compra ou captura de lead:
10
+
11
+ ```
12
+ Webhook Agent (Hotmart/Kiwify/Ticto)
13
+ └─► ctx.waitUntil(sendEmail(env, type, payload))
14
+
15
+ ├─ type = 'purchase_confirmation' → email de confirmação de compra
16
+ ├─ type = 'lead_welcome' → email de boas-vindas ao lead
17
+ └─ type = 'cart_abandonment' → email de recuperação de carrinho
18
+ ```
19
+
20
+ **Assinatura da função que este agente gera:**
21
+
22
+ ```javascript
23
+ // Injetada no Worker principal (worker.js)
24
+ export async function sendEmail(env, type, payload) {
25
+ const { to, name, product, value } = payload;
26
+ // ... implementação completa abaixo
27
+ }
28
+ ```
29
+
30
+ > O Webhook Agent importa `sendEmail` e chama via `ctx.waitUntil` para não bloquear resposta ao gateway de pagamento.
31
+
32
+ ---
33
+
7
34
  ## 📧 PROTOCOLOS DE ENVIO (Quantum Tier)
8
35
 
9
36
  1. **Resend API Excellence**:
@@ -21,6 +21,211 @@ Sempre que o usuário sangrar dinheiro por culpa de "Perda de Cookies/Atribuiç
21
21
 
22
22
  ---
23
23
 
24
+ ## 💻 IMPLEMENTAÇÃO REAL — cloudflare/fingerprint-middleware.js
25
+
26
+ ### Módulo completo para injetar no Worker
27
+
28
+ ```javascript
29
+ /**
30
+ * Fingerprint Middleware — CDP Edge
31
+ * Edge-only signals: IP + Accept-Language + UA base + ASN
32
+ * LGPD/CCPA compliant: nenhum PII direto, hash efêmero
33
+ */
34
+
35
+ // ─────────────────────────────────────────────────
36
+ // 1. Geração do P-Hash (fingerprint de borda)
37
+ // ─────────────────────────────────────────────────
38
+
39
+ /**
40
+ * Gera hash identificador efêmero combinando sinais anônimos de borda.
41
+ * NUNCA usa Canvas, WebGL ou AudioContext (client-side) — apenas Edge signals.
42
+ *
43
+ * @param {Request} request - Request do Cloudflare Worker
44
+ * @returns {Promise<string>} p_hash — identificador efêmero de 16 chars
45
+ */
46
+ export async function generatePHash(request) {
47
+ const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
48
+ const acceptLang = request.headers.get('Accept-Language') || 'unknown';
49
+ const userAgent = request.headers.get('User-Agent') || 'unknown';
50
+ const asOrg = request.cf?.asOrganization || 'unknown';
51
+ const country = request.cf?.country || 'unknown';
52
+
53
+ // Reduzir UA para base (remover versão minor — ex: "Chrome/120" não "Chrome/120.0.6099.71")
54
+ const uaBase = userAgent
55
+ .replace(/[\d.]+/g, (m) => m.split('.')[0]) // mantém só major version
56
+ .replace(/[^a-zA-Z0-9 /]/g, '') // remove caracteres especiais
57
+ .slice(0, 60); // limitar tamanho
58
+
59
+ // Normalizar Accept-Language para idioma principal
60
+ const langBase = acceptLang.split(',')[0].split(';')[0].trim().slice(0, 5); // ex: "pt-BR"
61
+
62
+ // Concatenar sinais — ordem importa para consistência
63
+ const fingerprint = `${ip}|${langBase}|${uaBase}|${asOrg}|${country}`;
64
+
65
+ // SHA-256 → primeiros 16 hex chars (64 bits de entropia — suficiente para sess de 48h)
66
+ const encoder = new TextEncoder();
67
+ const data = encoder.encode(fingerprint);
68
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
69
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
70
+ const fullHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
71
+
72
+ return fullHash.slice(0, 16); // p_hash = 16 chars hex
73
+ }
74
+
75
+ // ─────────────────────────────────────────────────
76
+ // 2. Registro do P-Hash no D1
77
+ // ─────────────────────────────────────────────────
78
+
79
+ /**
80
+ * Salva ou atualiza p_hash no D1 com UTMs da visita atual.
81
+ * Janela de restauração: 48h (configurável).
82
+ *
83
+ * @param {D1Database} db
84
+ * @param {string} pHash
85
+ * @param {Object} utmData - { utm_source, utm_medium, utm_campaign, utm_content, utm_term }
86
+ */
87
+ export async function recordPHash(db, pHash, utmData) {
88
+ const hasUtm = utmData.utm_source || utmData.utm_medium || utmData.utm_campaign;
89
+
90
+ if (!hasUtm) {
91
+ // Visita sem UTM — só atualiza last_seen (não sobrescreve UTMs)
92
+ await db.prepare(`
93
+ UPDATE fingerprint_sessions
94
+ SET last_seen_at = datetime('now')
95
+ WHERE p_hash = ? AND last_seen_at > datetime('now', '-48 hours')
96
+ `).bind(pHash).run();
97
+ return;
98
+ }
99
+
100
+ // Visita COM UTM — inserir ou atualizar
101
+ await db.prepare(`
102
+ INSERT INTO fingerprint_sessions (p_hash, utm_source, utm_medium, utm_campaign, utm_content, utm_term, last_seen_at)
103
+ VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
104
+ ON CONFLICT(p_hash) DO UPDATE SET
105
+ utm_source = excluded.utm_source,
106
+ utm_medium = excluded.utm_medium,
107
+ utm_campaign = excluded.utm_campaign,
108
+ utm_content = excluded.utm_content,
109
+ utm_term = excluded.utm_term,
110
+ last_seen_at = datetime('now')
111
+ `).bind(
112
+ pHash,
113
+ utmData.utm_source || null,
114
+ utmData.utm_medium || null,
115
+ utmData.utm_campaign || null,
116
+ utmData.utm_content || null,
117
+ utmData.utm_term || null
118
+ ).run();
119
+ }
120
+
121
+ // ─────────────────────────────────────────────────
122
+ // 3. UTM Restoration Middleware
123
+ // ─────────────────────────────────────────────────
124
+
125
+ /**
126
+ * Recupera UTMs do D1 para um p_hash (janela 48h).
127
+ * Injeta de volta no payload CAPI quando a requisição chega sem UTMs.
128
+ *
129
+ * @param {D1Database} db
130
+ * @param {string} pHash
131
+ * @returns {Promise<Object|null>} UTMs restauradas ou null
132
+ */
133
+ export async function restoreUtms(db, pHash) {
134
+ const row = await db.prepare(`
135
+ SELECT utm_source, utm_medium, utm_campaign, utm_content, utm_term
136
+ FROM fingerprint_sessions
137
+ WHERE p_hash = ?
138
+ AND last_seen_at > datetime('now', '-48 hours')
139
+ AND utm_source IS NOT NULL
140
+ LIMIT 1
141
+ `).bind(pHash).first();
142
+
143
+ return row || null;
144
+ }
145
+
146
+ /**
147
+ * Middleware principal — chamar no início do handler /track
148
+ *
149
+ * @param {Request} request
150
+ * @param {Object} env
151
+ * @param {Object} payload - payload já parseado do /track
152
+ * @returns {Promise<Object>} payload enriquecido com UTMs restauradas
153
+ */
154
+ export async function fingerprintMiddleware(request, env, payload) {
155
+ try {
156
+ // 1. Gerar p_hash para esta visita
157
+ const pHash = await generatePHash(request);
158
+
159
+ // 2. Extrair UTMs do payload atual
160
+ const currentUtms = {
161
+ utm_source: payload.utm_source || null,
162
+ utm_medium: payload.utm_medium || null,
163
+ utm_campaign: payload.utm_campaign || null,
164
+ utm_content: payload.utm_content || null,
165
+ utm_term: payload.utm_term || null,
166
+ };
167
+
168
+ // 3. Se tem UTMs → registrar no D1 (atualiza para próximas visitas)
169
+ await recordPHash(env.DB, pHash, currentUtms);
170
+
171
+ // 4. Se NÃO tem UTMs → tentar restaurar do D1 (últimas 48h)
172
+ const hasCurrentUtm = currentUtms.utm_source || currentUtms.utm_campaign;
173
+ if (!hasCurrentUtm) {
174
+ const restoredUtms = await restoreUtms(env.DB, pHash);
175
+ if (restoredUtms) {
176
+ // Injetar UTMs restauradas no payload → creditam a campanha correta na CAPI
177
+ payload.utm_source = restoredUtms.utm_source;
178
+ payload.utm_medium = restoredUtms.utm_medium;
179
+ payload.utm_campaign = restoredUtms.utm_campaign;
180
+ payload.utm_content = restoredUtms.utm_content;
181
+ payload.utm_term = restoredUtms.utm_term;
182
+ payload._utm_restored = true; // flag para debug
183
+ }
184
+ }
185
+
186
+ // 5. Adicionar p_hash ao payload para uso pelo Identity Graph
187
+ payload.p_hash = pHash;
188
+
189
+ } catch (err) {
190
+ // Fail-safe: nunca bloquear o tracking por erro de fingerprint
191
+ console.error('[FingerprintMiddleware] Erro (fail-safe):', err.message);
192
+ }
193
+
194
+ return payload;
195
+ }
196
+ ```
197
+
198
+ ### Schema D1 necessário
199
+
200
+ ```sql
201
+ -- Adicionar a schema.sql
202
+ CREATE TABLE IF NOT EXISTS fingerprint_sessions (
203
+ p_hash TEXT PRIMARY KEY,
204
+ utm_source TEXT,
205
+ utm_medium TEXT,
206
+ utm_campaign TEXT,
207
+ utm_content TEXT,
208
+ utm_term TEXT,
209
+ last_seen_at TEXT DEFAULT (datetime('now'))
210
+ );
211
+
212
+ CREATE INDEX IF NOT EXISTS idx_fp_last_seen ON fingerprint_sessions(last_seen_at);
213
+ ```
214
+
215
+ ### Uso no worker.js
216
+
217
+ ```javascript
218
+ // No início do handler /track, ANTES do fraud gate:
219
+ import { fingerprintMiddleware } from './fingerprint-middleware.js';
220
+
221
+ // Dentro do fetch handler:
222
+ payload = await fingerprintMiddleware(request, env, payload);
223
+ // A partir daqui, payload.utm_* estão restauradas (se disponíveis)
224
+ // e payload.p_hash está disponível para o Identity Graph
225
+ ```
226
+
227
+ ---
228
+
24
229
  ## INPUTS RECEBIDOS
25
230
 
26
231
  - Headers da requisição Edge: `CF-Connecting-IP`, `Accept-Language`, `User-Agent`, `request.cf.asOrganization`
@@ -43,6 +43,124 @@ if (isVersionConflict) {
43
43
 
44
44
  ---
45
45
 
46
+ ## 🛡️ GOOGLE CONSENT MODE V2 — IMPLEMENTAÇÃO OBRIGATÓRIA
47
+
48
+ > **CRÍTICO**: Sem Consent Mode v2, campanhas Google Ads em audiências europeias são rejeitadas.
49
+ > Obrigatório para conformidade com GDPR (UE), LGPD (BR) e CCPA (EUA).
50
+
51
+ ### PASSO 1 — Inicialização (ANTES do gtag.js)
52
+
53
+ Inserir **antes** do snippet do gtag.js no `<head>`:
54
+
55
+ ```html
56
+ <!-- Google Consent Mode v2 — Inicializar NEGADO por padrão -->
57
+ <script>
58
+ window.dataLayer = window.dataLayer || [];
59
+ function gtag() { dataLayer.push(arguments); }
60
+
61
+ // OBRIGATÓRIO: definir consent ANTES de qualquer gtag() de medição
62
+ gtag('consent', 'default', {
63
+ 'ad_storage': 'denied', // cookies de anúncio bloqueados até opt-in
64
+ 'analytics_storage': 'denied', // cookies de analytics bloqueados até opt-in
65
+ 'ad_user_data': 'denied', // envio de dados de usuário para Google Ads
66
+ 'ad_personalization': 'denied', // personalização de anúncios
67
+ 'wait_for_update': 500 // aguardar CMP atualizar consentimento (ms)
68
+ });
69
+
70
+ // url_passthrough: preserva gclid/gbraid/wbraid na URL sem cookie
71
+ // Permite atribuição de cliques mesmo sem consent de analytics_storage
72
+ gtag('set', 'url_passthrough', true);
73
+
74
+ // ads_data_redaction: quando ad_storage=denied, reduz dados de clique enviados
75
+ gtag('set', 'ads_data_redaction', true);
76
+ </script>
77
+
78
+ <!-- Carregar gtag.js normalmente após o bloco acima -->
79
+ <script async src="https://www.googletagmanager.com/gtag/js?id=GA4_MEASUREMENT_ID"></script>
80
+ <script>
81
+ window.dataLayer = window.dataLayer || [];
82
+ function gtag() { dataLayer.push(arguments); }
83
+ gtag('js', new Date());
84
+ gtag('config', 'GA4_MEASUREMENT_ID', {
85
+ 'send_page_view': false // cdpTrack controla page_view manualmente
86
+ });
87
+ </script>
88
+ ```
89
+
90
+ ### PASSO 2 — Atualizar Consent após Opt-in do usuário
91
+
92
+ Integrar com o banner de cookies do site (LGPD/GDPR):
93
+
94
+ ```javascript
95
+ // Chamar quando usuário ACEITAR todos os cookies
96
+ function onConsentAccepted() {
97
+ gtag('consent', 'update', {
98
+ 'ad_storage': 'granted',
99
+ 'analytics_storage': 'granted',
100
+ 'ad_user_data': 'granted',
101
+ 'ad_personalization': 'granted'
102
+ });
103
+
104
+ // Opcional: disparar page_view após consent (se necessário)
105
+ gtag('event', 'page_view');
106
+ }
107
+
108
+ // Chamar quando usuário RECUSAR cookies não essenciais
109
+ function onConsentDeclined() {
110
+ gtag('consent', 'update', {
111
+ 'ad_storage': 'denied',
112
+ 'analytics_storage': 'denied',
113
+ 'ad_user_data': 'denied',
114
+ 'ad_personalization': 'denied'
115
+ });
116
+ }
117
+
118
+ // Aceitar apenas cookies analíticos (sem ads)
119
+ function onConsentAnalyticsOnly() {
120
+ gtag('consent', 'update', {
121
+ 'ad_storage': 'denied',
122
+ 'analytics_storage': 'granted',
123
+ 'ad_user_data': 'denied',
124
+ 'ad_personalization': 'denied'
125
+ });
126
+ }
127
+ ```
128
+
129
+ ### PASSO 3 — Verificação (via Intelligence Agent)
130
+
131
+ O Intelligence Agent verifica mensalmente se o Consent Mode está implementado:
132
+
133
+ ```javascript
134
+ // Checklist mínimo no código gerado (browser tracking):
135
+ // ✅ gtag('consent', 'default', {...}) ANTES do gtag.js
136
+ // ✅ ad_storage: 'denied' no default
137
+ // ✅ analytics_storage: 'denied' no default
138
+ // ✅ ad_user_data: 'denied' no default
139
+ // ✅ ad_personalization: 'denied' no default
140
+ // ✅ url_passthrough: true ativo
141
+ // ✅ gtag('consent', 'update', {...}) no callback do CMP/banner
142
+ ```
143
+
144
+ ### PASSO 4 — Integração com cdpTrack (Preservação de gclid)
145
+
146
+ ```javascript
147
+ // O cdpTrack.js deve capturar gclid/gbraid/wbraid da URL mesmo sem consent
148
+ // url_passthrough: true garante que os parâmetros são passados como parâmetros de URL,
149
+ // não como cookies — respeitando consent de analytics_storage
150
+
151
+ function captureGoogleClickId() {
152
+ const params = new URLSearchParams(window.location.search);
153
+ return {
154
+ gclid: params.get('gclid') || null,
155
+ gbraid: params.get('gbraid') || null,
156
+ wbraid: params.get('wbraid') || null
157
+ };
158
+ }
159
+ // Esses IDs são enviados para o Worker e salvos no D1 para Enhanced Conversions offline
160
+ ```
161
+
162
+ ---
163
+
46
164
  ## 🛠️ O QUE VOCÊ GERA
47
165
 
48
166
  ### 1. Browser (Direct SDK)
@@ -71,7 +71,7 @@ export default {
71
71
  const url = new URL(request.url);
72
72
 
73
73
  // Handler principal
74
- if (url.pathname === '/api/track') {
74
+ if (url.pathname === '/track') {
75
75
  return handleTracking(request, env, ctx);
76
76
  }
77
77
 
@@ -157,12 +157,12 @@ Timestamp: ${new Date().toISOString()}
157
157
  `.trim();
158
158
 
159
159
  // Enviar via WhatsApp Agent
160
- if (env.WA_PHONE_ID && env.ADMIN_PHONE_NUMBER) {
161
- await fetch(`https://graph.facebook.com/v22.0/${env.WA_PHONE_ID}/messages`, {
160
+ if (env.WHATSAPP_PHONE_NUMBER_ID && env.ADMIN_PHONE_NUMBER) {
161
+ await fetch(`https://graph.facebook.com/v22.0/${env.WHATSAPP_PHONE_NUMBER_ID}/messages`, {
162
162
  method: 'POST',
163
163
  headers: {
164
164
  'Content-Type': 'application/json',
165
- 'Authorization': `Bearer ${env.WA_ACCESS_TOKEN}`
165
+ 'Authorization': `Bearer ${env.WHATSAPP_ACCESS_TOKEN}`
166
166
  },
167
167
  body: JSON.stringify({
168
168
  messaging_product: 'whatsapp',
@@ -363,3 +363,89 @@ INTELLIGENCE_SCHEDULE_MONTHLY = "0 3 1 * *"
363
363
  3. **Alerta Pré-ativo**: Antes de uma API ser descontinuada, alertar com 30 dias de antecedência
364
364
  4. **False-Positive Safe**: Se houver dúvida sobre versão de API, marcar como "verificação manual necessária" em vez de alerta
365
365
  5. **Backoff de Check**: Se o check falhar (API indisponível), tentar novamente em 1 hora (não disparar alerta imediato)
366
+ 6. **Anti-Spam**: Não disparar alerta se o mesmo problema já foi reportado nas últimas 24h
367
+ 7. **Prioridade Correta**: CRITICAL (agora), HIGH (até 1h), MEDIUM (no relatório)
368
+ 8. **Log de Falhas de Alerta**: Se WhatsApp falhar 3× consecutivas, registrar no D1 e tentar via CallMeBot fallback
369
+
370
+ ---
371
+
372
+ ## 🗄️ SCHEMA D1 — intelligence_logs
373
+
374
+ Adicionar ao `server-edge-tracker/schema.sql`:
375
+
376
+ ```sql
377
+ -- TABELA DE LOGS DO INTELLIGENCE AGENT
378
+ CREATE TABLE IF NOT EXISTS intelligence_logs (
379
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
380
+ run_type TEXT NOT NULL, -- 'weekly' | 'monthly' | 'on-demand'
381
+ platforms_checked TEXT, -- JSON array de plataformas verificadas
382
+ issues_found TEXT, -- JSON array de issues encontradas
383
+ issues_count INTEGER DEFAULT 0,
384
+ created_at TEXT DEFAULT (datetime('now'))
385
+ );
386
+
387
+ CREATE INDEX IF NOT EXISTS idx_intel_logs_type ON intelligence_logs(run_type);
388
+ CREATE INDEX IF NOT EXISTS idx_intel_logs_created ON intelligence_logs(created_at);
389
+ ```
390
+
391
+ ---
392
+
393
+ ## ✅ CHECKLIST DE IMPLEMENTAÇÃO
394
+
395
+ Antes de considerar o scheduling implementado, verificar:
396
+
397
+ - [ ] Cron triggers adicionados ao `wrangler.toml` (`0 2 * * 7` e `0 3 1 * *`)
398
+ - [ ] Handlers `scheduled()` adicionados ao `worker.js` (Cloudflare usa `scheduled`, não `fetch`)
399
+ - [ ] Schema D1 atualizado com tabela `intelligence_logs`
400
+ - [ ] Funções de check de versão implementadas com endpoints reais
401
+ - [ ] Funções de auditoria de privacidade implementadas
402
+ - [ ] Sistema de alerta (WhatsApp/CallMeBot) integrado com anti-spam 24h
403
+ - [ ] Logs de execução sendo salvos no D1
404
+ - [ ] Memory Agent atualizado após cada check
405
+ - [ ] Backoff implementado para evitar spam de alertas
406
+ - [ ] Teste manual executado (`GET /api/intelligence/check`)
407
+
408
+ ---
409
+
410
+ ## INPUTS RECEBIDOS
411
+
412
+ - `wrangler.toml` do Worker (para injetar Cron Triggers)
413
+ - `worker.js` (para injetar handlers de `scheduled` events)
414
+ - `schema.sql` (para adicionar tabela `intelligence_logs`)
415
+ - Secrets: `WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_ACCESS_TOKEN`, `ADMIN_PHONE_NUMBER` (para alertas)
416
+ - `contracts/api-versions.json` (fonte de verdade das versões atuais)
417
+
418
+ ## RESPONSABILIDADE
419
+
420
+ - Configurar Cron Triggers no `wrangler.toml`: semanal (domingo 02:00 UTC) e mensal (1º do mês 03:00 UTC)
421
+ - Implementar handler `scheduled(event, env, ctx)` no Worker
422
+ - Chamar `runIntelligenceWeekly()` quando `event.cron === "0 2 * * 7"`
423
+ - Chamar `runIntelligenceMonthly()` quando `event.cron === "0 3 1 * *"`
424
+ - Adicionar tabela `intelligence_logs` ao schema D1
425
+ - Disparar alertas WhatsApp/CallMeBot ao admin apenas quando houver issues críticos
426
+ - Evitar spam: não repetir alerta do mesmo issue em menos de 24h
427
+ - Registrar resultado de cada execução no D1 (`intelligence_logs`)
428
+
429
+ ## SAÍDA
430
+
431
+ ```json
432
+ {
433
+ "arquivos_modificados": [
434
+ "wrangler.toml (cron triggers adicionados)",
435
+ "worker.js (handler scheduled() adicionado)",
436
+ "schema.sql (tabela intelligence_logs adicionada)"
437
+ ],
438
+ "crons_configurados": {
439
+ "semanal": "0 2 * * 7 (domingo 02:00 UTC — check de versões)",
440
+ "mensal": "0 3 1 * * (dia 1 03:00 UTC — auditoria privacidade)"
441
+ },
442
+ "endpoint_manual": "GET /api/intelligence/check",
443
+ "alertas": {
444
+ "canal_primario": "WhatsApp Meta Cloud API v22.0",
445
+ "canal_fallback": "CallMeBot",
446
+ "anti_spam": "24h cooldown por issue"
447
+ },
448
+ "d1_tabela": "intelligence_logs",
449
+ "secrets_necessarios": ["WHATSAPP_PHONE_NUMBER_ID", "WHATSAPP_ACCESS_TOKEN", "ADMIN_PHONE_NUMBER"]
450
+ }
451
+ ```