cdp-edge 1.18.0 → 2.0.1
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 +308 -308
- package/bin/cdp-edge.js +61 -61
- package/dist/commands/analyze.js +52 -52
- package/dist/commands/infra.js +54 -54
- package/dist/commands/install.js +186 -0
- package/dist/commands/server.js +174 -174
- package/dist/commands/setup.js +18 -1
- package/dist/commands/validate.js +84 -84
- package/dist/index.js +12 -12
- package/extracted-skill/tracking-events-generator/advanced-matching.js +364 -364
- package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +172 -72
- package/extracted-skill/tracking-events-generator/agents/google-agent.md +118 -0
- package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +86 -0
- package/extracted-skill/tracking-events-generator/agents/intelligence-scheduling.md +8 -641
- package/extracted-skill/tracking-events-generator/agents/memory-agent.md +98 -0
- package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +42 -0
- package/extracted-skill/tracking-events-generator/anti-blocking.js +285 -285
- package/extracted-skill/tracking-events-generator/cdpTrack.js +641 -641
- package/extracted-skill/tracking-events-generator/engagement-scoring.js +226 -226
- package/extracted-skill/tracking-events-generator/evals/evals.json +235 -235
- package/extracted-skill/tracking-events-generator/integration-test.js +497 -497
- package/extracted-skill/tracking-events-generator/micro-events.js +992 -992
- package/extracted-skill/tracking-events-generator/models/pinterest/conversions-api-template.js +144 -144
- package/extracted-skill/tracking-events-generator/models/pinterest/event-mappings.json +48 -48
- package/extracted-skill/tracking-events-generator/models/pinterest/tag-template.js +28 -28
- package/extracted-skill/tracking-events-generator/models/reddit/conversions-api-template.js +205 -205
- package/extracted-skill/tracking-events-generator/models/reddit/event-mappings.json +56 -56
- package/extracted-skill/tracking-events-generator/models/reddit/pixel-template.js +19 -19
- package/extracted-skill/tracking-events-generator/models/scenarios/behavior-engine.js +425 -425
- package/package.json +76 -76
- package/server-edge-tracker/schema.sql +265 -265
- package/server-edge-tracker/worker.js +4160 -4160
- package/server-edge-tracker/wrangler.toml +103 -103
- package/templates/pinterest/conversions-api-template.js +144 -144
- package/templates/pinterest/event-mappings.json +48 -48
- package/templates/pinterest/tag-template.js +28 -28
- package/templates/reddit/conversions-api-template.js +205 -205
- package/templates/reddit/event-mappings.json +56 -56
- package/templates/reddit/pixel-template.js +19 -19
- package/templates/scenarios/behavior-engine.js +425 -425
|
@@ -109,99 +109,199 @@ Implementado via `anti-blocking.js`:
|
|
|
109
109
|
|
|
110
110
|
## 💻 EXEMPLO DE CÓDIGO GERADO
|
|
111
111
|
|
|
112
|
-
### `cdpTrack.js` (SDK Principal)
|
|
112
|
+
### `cdpTrack.js` (SDK Principal — Padrão Multi-Plataforma)
|
|
113
|
+
|
|
114
|
+
> Este é o padrão canônico do cdpTrack SDK para Meta, TikTok e GA4.
|
|
115
|
+
> Cada agente de plataforma injeta seus eventos neste SDK via Browser Tracking Agent.
|
|
113
116
|
|
|
114
117
|
```javascript
|
|
115
118
|
/**
|
|
116
119
|
* cdpTrack SDK - CDP Edge Quantum Tier
|
|
117
120
|
* Browser Tracking SDK Principal
|
|
121
|
+
* Suporta: Meta Pixel, TikTok Pixel, GA4, Pinterest Tag, Reddit Pixel, Spotify Pixel
|
|
118
122
|
*/
|
|
119
123
|
|
|
120
|
-
(function(w
|
|
121
|
-
|
|
122
|
-
w._pbq.push = w._pbq.push || [];
|
|
123
|
-
w._spotify = w._spotify || {};
|
|
124
|
-
|
|
125
|
-
// Carregar configuração
|
|
126
|
-
const config = window.cdpTrack?.config || {};
|
|
124
|
+
(function(w) {
|
|
125
|
+
'use strict';
|
|
127
126
|
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
// ──────────────────────────────────────────────
|
|
128
|
+
// CORE: Geração de event_id único (deduplicação)
|
|
129
|
+
// O mesmo event_id deve ser usado no browser E no servidor (CAPI)
|
|
130
|
+
// ──────────────────────────────────────────────
|
|
131
|
+
function generateEventId() {
|
|
132
|
+
return 'evt_' + Date.now() + '_' + Math.random().toString(36).substring(2, 11);
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
135
|
+
// ──────────────────────────────────────────────
|
|
136
|
+
// CORE: Envio para Cloudflare Worker (same-domain)
|
|
137
|
+
// Usa /track no mesmo domínio — imune a ad-blockers
|
|
138
|
+
// ──────────────────────────────────────────────
|
|
139
|
+
async function sendToWorker(eventName, payload) {
|
|
140
|
+
const eventId = generateEventId();
|
|
141
|
+
|
|
142
|
+
const body = {
|
|
143
|
+
event: eventName,
|
|
144
|
+
event_id: eventId, // CRÍTICO: mesmo ID usado nas CAPIs
|
|
145
|
+
url: window.location.href,
|
|
146
|
+
referrer: document.referrer,
|
|
147
|
+
timestamp: Date.now(),
|
|
148
|
+
...payload
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
// Tentativa primária: fetch
|
|
153
|
+
await fetch('/track', {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: { 'Content-Type': 'application/json' },
|
|
156
|
+
body: JSON.stringify(body),
|
|
157
|
+
keepalive: true
|
|
152
158
|
});
|
|
159
|
+
} catch (_) {
|
|
160
|
+
// Fallback: Beacon API (funciona mesmo no unload da página)
|
|
161
|
+
navigator.sendBeacon('/track', JSON.stringify(body));
|
|
153
162
|
}
|
|
154
|
-
};
|
|
155
163
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
w._spotify.trackEvent('ViewContent', {
|
|
159
|
-
content_name: contentName,
|
|
160
|
-
content_id: contentId,
|
|
161
|
-
...params
|
|
162
|
-
});
|
|
163
|
-
};
|
|
164
|
+
return eventId;
|
|
165
|
+
}
|
|
164
166
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
};
|
|
167
|
+
// ──────────────────────────────────────────────
|
|
168
|
+
// CORE: Captura de cookies first-party
|
|
169
|
+
// ──────────────────────────────────────────────
|
|
170
|
+
function getCookie(name) {
|
|
171
|
+
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
|
172
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
173
|
+
}
|
|
173
174
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
175
|
+
// ──────────────────────────────────────────────
|
|
176
|
+
// CORE: Captura de click IDs da URL (Meta, TikTok, Google)
|
|
177
|
+
// ──────────────────────────────────────────────
|
|
178
|
+
function getClickIds() {
|
|
179
|
+
const params = new URLSearchParams(window.location.search);
|
|
180
|
+
return {
|
|
181
|
+
fbclid: params.get('fbclid') || getCookie('fbclid') || null,
|
|
182
|
+
ttclid: params.get('ttclid') || getCookie('ttclid') || null,
|
|
183
|
+
gclid: params.get('gclid') || null,
|
|
184
|
+
gbraid: params.get('gbraid') || null,
|
|
185
|
+
wbraid: params.get('wbraid') || null,
|
|
186
|
+
fbp: getCookie('_fbp') || null,
|
|
187
|
+
fbc: getCookie('_fbc') || null,
|
|
188
|
+
ttp: getCookie('_ttp') || null,
|
|
189
|
+
uid: getCookie('_cdp_uid') || null // Identity Graph first-party cookie
|
|
190
|
+
};
|
|
191
|
+
}
|
|
183
192
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
// ──────────────────────────────────────────────
|
|
194
|
+
// API PÚBLICA
|
|
195
|
+
// ──────────────────────────────────────────────
|
|
196
|
+
const cdpTrack = {
|
|
197
|
+
generateEventId,
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Rastrear evento genérico — enviado para o Worker
|
|
201
|
+
* O Worker despacha para Meta CAPI, GA4 MP, TikTok Events API etc.
|
|
202
|
+
*
|
|
203
|
+
* @param {string} eventName - Nome do evento (ex: 'Lead', 'Purchase', 'PageView')
|
|
204
|
+
* @param {Object} params - Parâmetros adicionais do evento
|
|
205
|
+
*/
|
|
206
|
+
track(eventName, params = {}) {
|
|
207
|
+
const clickIds = getClickIds();
|
|
208
|
+
return sendToWorker(eventName, { ...clickIds, ...params });
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Rastrear Lead (captura de formulário)
|
|
213
|
+
* Enviar dados PII crus — o Worker faz SHA-256 no servidor
|
|
214
|
+
*/
|
|
215
|
+
trackLead(userData = {}) {
|
|
216
|
+
const clickIds = getClickIds();
|
|
217
|
+
return sendToWorker('Lead', {
|
|
218
|
+
...clickIds,
|
|
219
|
+
email: userData.email || null, // Worker aplica SHA-256
|
|
220
|
+
phone: userData.phone || null, // Worker aplica E.164 + SHA-256
|
|
221
|
+
first_name: userData.first_name || null,
|
|
222
|
+
last_name: userData.last_name || null,
|
|
223
|
+
city: userData.city || null,
|
|
224
|
+
state: userData.state || null,
|
|
225
|
+
zip: userData.zip || null,
|
|
226
|
+
country: userData.country || 'BR'
|
|
227
|
+
});
|
|
228
|
+
},
|
|
192
229
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Rastrear Purchase (confirmação de compra)
|
|
232
|
+
*/
|
|
233
|
+
trackPurchase(orderData = {}) {
|
|
234
|
+
const clickIds = getClickIds();
|
|
235
|
+
return sendToWorker('Purchase', {
|
|
236
|
+
...clickIds,
|
|
237
|
+
value: orderData.value || 0,
|
|
238
|
+
currency: orderData.currency || 'BRL',
|
|
239
|
+
order_id: orderData.order_id || null,
|
|
240
|
+
content_name: orderData.product || null
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Rastrear PageView — chamar no load da página
|
|
246
|
+
*/
|
|
247
|
+
trackPageView() {
|
|
248
|
+
const clickIds = getClickIds();
|
|
249
|
+
return sendToWorker('PageView', { ...clickIds });
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Rastrear InitiateCheckout
|
|
254
|
+
*/
|
|
255
|
+
trackInitiateCheckout(checkoutData = {}) {
|
|
256
|
+
const clickIds = getClickIds();
|
|
257
|
+
return sendToWorker('InitiateCheckout', {
|
|
258
|
+
...clickIds,
|
|
259
|
+
value: checkoutData.value || 0,
|
|
260
|
+
currency: checkoutData.currency || 'BRL'
|
|
261
|
+
});
|
|
262
|
+
}
|
|
200
263
|
};
|
|
201
264
|
|
|
202
|
-
|
|
265
|
+
// Expor no window
|
|
266
|
+
w.cdpTrack = cdpTrack;
|
|
267
|
+
|
|
268
|
+
// Auto page_view no load
|
|
269
|
+
if (document.readyState === 'loading') {
|
|
270
|
+
document.addEventListener('DOMContentLoaded', () => cdpTrack.trackPageView());
|
|
271
|
+
} else {
|
|
272
|
+
cdpTrack.trackPageView();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
})(window);
|
|
203
276
|
```
|
|
204
277
|
|
|
278
|
+
### Uso típico no HTML do cliente
|
|
279
|
+
|
|
280
|
+
```html
|
|
281
|
+
<!-- 1. Carregar o SDK -->
|
|
282
|
+
<script src="/tracking/cdpTrack.js"></script>
|
|
283
|
+
|
|
284
|
+
<!-- 2. Rastrear lead ao submeter formulário -->
|
|
285
|
+
<script>
|
|
286
|
+
document.getElementById('lead-form').addEventListener('submit', function(e) {
|
|
287
|
+
cdpTrack.trackLead({
|
|
288
|
+
email: document.getElementById('email').value,
|
|
289
|
+
phone: document.getElementById('phone').value,
|
|
290
|
+
first_name: document.getElementById('name').value
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
</script>
|
|
294
|
+
|
|
295
|
+
<!-- 3. Rastrear checkout (botão de compra) -->
|
|
296
|
+
<script>
|
|
297
|
+
document.getElementById('buy-btn').addEventListener('click', function() {
|
|
298
|
+
cdpTrack.trackInitiateCheckout({ value: 97.00, currency: 'BRL' });
|
|
299
|
+
});
|
|
300
|
+
</script>
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
> **Nota:** O Worker recebe os dados crus, aplica SHA-256, e despacha para Meta CAPI v22.0, GA4 MP, TikTok Events API v1.3 e demais plataformas configuradas — tudo em paralelo via `Promise.allSettled`.
|
|
304
|
+
|
|
205
305
|
---
|
|
206
306
|
|
|
207
307
|
## 🔧 INTEGRAÇÃO COM OUTROS AGENTES
|
|
@@ -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)
|
|
@@ -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: `WA_PHONE_ID`, `WA_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": ["WA_PHONE_ID", "WA_ACCESS_TOKEN", "ADMIN_PHONE_NUMBER"]
|
|
450
|
+
}
|
|
451
|
+
```
|