cdp-edge 2.0.4 → 2.0.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.
@@ -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.4'));
35
+ console.log(chalk.gray(' Customer Data Platform on the Edge · Global Edge Tracking · v2.0.5'));
36
36
  console.log('');
37
37
  console.log(chalk.gray('═'.repeat(68)));
38
38
  console.log('');
@@ -1,138 +1,353 @@
1
- /**
2
- * Setup Wizard - Wrapper para invocar CDP Edge Skill
1
+ /**
2
+ * CDP Edge Setup Wizard Guiado e não-técnico
3
3
  *
4
- * O CLI é apenas um disparador. A skill (Master Orchestrator) faz tudo.
4
+ * Coleta os dados do projeto do cliente e gera:
5
+ * • Comandos wrangler secret put prontos para copiar
6
+ * • URLs de webhook com domínio preenchido
7
+ * • Checklist de próximos passos para o agente
5
8
  */
6
9
 
7
10
  import inquirer from 'inquirer';
8
11
  import chalk from 'chalk';
9
12
  import ora from 'ora';
13
+ import { writeFileSync } from 'fs';
14
+ import { join } from 'path';
10
15
 
11
16
  function printBanner() {
12
17
  console.log('');
13
- console.log(chalk.white.bold(' CDP Edge Setup Wizard'));
14
- console.log('');
15
- console.log(chalk.cyan(' ██████╗██████╗ ██████╗ ███████╗██████╗ ██████╗ ███████╗'));
16
- console.log(chalk.cyan('██╔════╝██╔══██╗██╔══██╗ ██╔════╝██╔══██╗██╔════╝ ██╔════╝'));
17
- console.log(chalk.cyan('██║ ██║ ██║██████╔╝ █████╗ ██║ ██║██║ ███╗█████╗ '));
18
- console.log(chalk.cyan('██║ ██║ ██║██╔═══╝ ██╔══╝ ██║ ██║██║ ██║██╔══╝ '));
19
- console.log(chalk.cyan('╚██████╗██████╔╝██║ ███████╗██████╔╝╚██████╔╝███████╗'));
20
- console.log(chalk.cyan(' ╚═════╝╚═════╝ ╚═╝ ╚══════╝╚═════╝ ╚═════╝╚══════╝'));
21
- console.log('');
22
- console.log(chalk.gray(' Customer Data Platform on the Edge · Global Edge Tracking · v2.0.4'));
23
- console.log('');
24
- console.log(chalk.gray('═'.repeat(68)));
18
+ console.log(chalk.cyan(' ╔═══════════════════════════════════════╗'));
19
+ console.log(chalk.cyan('') + chalk.white.bold(' CDP Edge — Setup Wizard ') + chalk.cyan('║'));
20
+ console.log(chalk.cyan(' ║') + chalk.gray(' Configuração Guiada de Tracking ') + chalk.cyan('║'));
21
+ console.log(chalk.cyan(' ╚═══════════════════════════════════════╝'));
25
22
  console.log('');
26
23
  }
27
24
 
25
+ function sep(label = '') {
26
+ if (label) {
27
+ console.log('\n' + chalk.gray('── ') + chalk.cyan.bold(label) + chalk.gray(' ' + '─'.repeat(Math.max(0, 40 - label.length))));
28
+ } else {
29
+ console.log(chalk.gray('─'.repeat(50)));
30
+ }
31
+ }
32
+
28
33
  export async function runSetupWizard(dir = '.') {
29
34
  printBanner();
30
35
 
31
- // === MENSAGEM INICIAL ===
36
+ console.log(chalk.cyan(' Vou te fazer algumas perguntas simples.'));
37
+ console.log(chalk.cyan(' Não precisa saber programar — é só preencher os dados.\n'));
38
+ console.log(chalk.gray(' Ao final, vou gerar todos os comandos prontos para instalar.\n'));
32
39
 
33
- console.log(chalk.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
34
- console.log(chalk.green.bold(' ✅ CDP Edge INSTALADO COM SUCESSO!'));
35
- console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
40
+ // ── PASSO 1: Dados do projeto ──────────────────────────────────────────────
41
+ sep('1. Dados do Projeto');
36
42
 
37
- console.log(chalk.cyan('🎯 O Master Orchestrator controla todo o processo de criação.'));
38
- console.log(chalk.cyan(' Ele vai:\n'));
39
- console.log(chalk.cyan(' • Fazer as perguntas necessárias'));
40
- console.log(chalk.cyan(' • Analisar suas páginas automaticamente'));
41
- console.log(chalk.cyan(' Chamar os agentes especialistas'));
42
- console.log(chalk.cyan(' • Gerar todos os arquivos de tracking'));
43
- console.log(chalk.cyan(' Validar o código gerado\n'));
43
+ const projeto = await inquirer.prompt([
44
+ {
45
+ type: 'input',
46
+ name: 'domain',
47
+ message: 'Qual o domínio do site? (ex: meusite.com.br)',
48
+ validate: v => v.trim() ? true : 'Domínio é obrigatório',
49
+ filter: v => v.trim().replace(/^https?:\/\//, '').replace(/\/$/, ''),
50
+ },
51
+ {
52
+ type: 'input',
53
+ name: 'projectName',
54
+ message: 'Nome do projeto (para identificação):',
55
+ default: answers => answers.domain.split('.')[0],
56
+ },
57
+ {
58
+ type: 'list',
59
+ name: 'productType',
60
+ message: 'Que tipo de produto você vende?',
61
+ choices: [
62
+ { name: 'Infoproduto / Curso Online', value: 'infoproduto' },
63
+ { name: 'E-commerce físico', value: 'ecommerce' },
64
+ { name: 'SaaS / Assinatura', value: 'saas' },
65
+ { name: 'Serviço / Consultoria', value: 'servico' },
66
+ { name: 'Lead Generation (captação)', value: 'leadgen' },
67
+ ],
68
+ },
69
+ ]);
44
70
 
45
- // === MENU DE OPÇÃO ===
71
+ // ── PASSO 2: Plataforma de vendas ──────────────────────────────────────────
72
+ sep('2. Plataforma de Vendas / Checkout');
46
73
 
47
- const menu = await inquirer.prompt([
74
+ const { plataformas } = await inquirer.prompt([
48
75
  {
49
- type: 'list',
50
- name: 'action',
51
- message: 'O que você deseja fazer?',
76
+ type: 'checkbox',
77
+ name: 'plataformas',
78
+ message: 'Quais plataformas de checkout você usa? (espaço para marcar)',
52
79
  choices: [
53
- { name: '🚀 Iniciar Master Orchestrator (Configuração Completa)', value: 'start' },
54
- { name: '📖 Ver documentação', value: 'docs' },
55
- { name: '❌ Sair', value: 'exit' }
56
- ]
57
- }
80
+ { name: 'Hotmart', value: 'hotmart', checked: false },
81
+ { name: 'Kiwify', value: 'kiwify', checked: false },
82
+ { name: 'Ticto', value: 'ticto', checked: false },
83
+ { name: 'Eduzz', value: 'eduzz', checked: false },
84
+ { name: 'Stripe', value: 'stripe', checked: false },
85
+ { name: 'Nenhuma (apenas formulário de captação)', value: 'none', checked: false },
86
+ ],
87
+ validate: v => v.length > 0 ? true : 'Selecione pelo menos uma opção',
88
+ },
89
+ ]);
90
+
91
+ // ── PASSO 3: Plataformas de anúncios ───────────────────────────────────────
92
+ sep('3. Plataformas de Anúncios');
93
+
94
+ const { adsPlataformas } = await inquirer.prompt([
95
+ {
96
+ type: 'checkbox',
97
+ name: 'adsPlataformas',
98
+ message: 'Onde você faz anúncios? (espaço para marcar)',
99
+ choices: [
100
+ { name: 'Meta Ads (Facebook / Instagram)', value: 'meta', checked: true },
101
+ { name: 'Google Ads / YouTube', value: 'google', checked: false },
102
+ { name: 'TikTok Ads', value: 'tiktok', checked: false },
103
+ { name: 'Pinterest Ads', value: 'pinterest', checked: false },
104
+ { name: 'LinkedIn Ads', value: 'linkedin', checked: false },
105
+ ],
106
+ validate: v => v.length > 0 ? true : 'Selecione pelo menos uma plataforma',
107
+ },
58
108
  ]);
59
109
 
60
- if (menu.action === 'exit') {
61
- console.log(chalk.yellow('\n👋 Até logo!\n'));
62
- process.exit(0);
63
- }
64
-
65
- if (menu.action === 'docs') {
66
- console.log(chalk.cyan('\n📚 Documentação:'));
67
- console.log(' Acesse: ' + chalk.underline('docs/guia-cloudflare-iniciante.md'));
68
- console.log(' Ou visite: ' + chalk.underline('github.com/ricardosoli777/CDP-Edge-Premium'));
69
- return;
70
- }
71
-
72
- if (menu.action === 'start') {
73
- const spinner = ora('Iniciando Master Orchestrator...').start();
74
- await sleep(800);
75
- spinner.succeed(chalk.green('Master Orchestrator iniciado!'));
76
-
77
- console.log(chalk.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
78
- console.log(chalk.cyan.bold(' ' + chalk.bold('🧠 MASTER ORCHESTRATOR ATIVO')));
79
- console.log(chalk.cyan(' Controlando todo o fluxo de criação...'));
80
- console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
81
-
82
- // === AQUI INVOCARIA A SKILL ===
83
- //
84
- // Em produção, aqui seria:
85
- //
86
- // import { spawnMasterOrchestrator } from '../skill-wrapper';
87
- // await spawnMasterOrchestrator({ dir, platforms: [] });
88
- //
89
- // A skill faria:
90
- // - Perguntar modo (guiado/livre)
91
- // - Perguntar plataformas
92
- // - Acessar projeto
93
- // - Spawnar Page Analyzer Agent
94
- // - Spawnar Browser Agent
95
- // - Spawnar Meta Agent, Google Agent, TikTok Agent
96
- // - Spawnar Server Agent
97
- // - Gerar todos os arquivos
98
- // - Validar
99
-
100
- // === DEMONSTRAÇÃO DO QUE ACONTECE ===
101
-
102
- console.log(chalk.yellow.bold('\n🔄 MODO DEMONSTRAÇÃO\n'));
103
- console.log(chalk.gray(' Nesta versão, veja o fluxo que a skill executaria:\n'));
104
-
105
- const demoFlow = [
106
- ' [1] Perguntar: Como prefere configurar?',
107
- ' → Guiado ou Livre',
108
- ' [2] Perguntar: Quais plataformas de ads usa?',
109
- ' → Meta, Google, TikTok, LinkedIn, Spotify...',
110
- ' [3] Acessar: Seu projeto (GitHub ou local)',
111
- ' [4] Page Analyzer: Analisar páginas',
112
- ' → Detecta tipo de produto, nicho, formulários',
113
- ' [5] Browser Agent: Gerar cdpTrack.js',
114
- ' → Tracking SDK + micro-events',
115
- ' [6] Meta Agent: Gerar Pixel + CAPI',
116
- ' [7] Google Agent: Gerar GA4 + Google Ads',
117
- ' [8] TikTok Agent: Gerar Pixel + Events API',
118
- ' [9] Server Agent: Gerar Worker + D1',
119
- ' [10] Validator: Auditar código gerado',
120
- ' [11] Entregar: Arquivos no seu projeto',
121
- ' → tracking.config.js, cdpTrack.js, worker.js, schema.sql'
122
- ];
123
-
124
- demoFlow.forEach(line => console.log(chalk.cyan(line)));
125
-
126
- console.log(chalk.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
127
- console.log(chalk.green.bold(' ✅ SETUP CONCLUÍDO!'));
128
- console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
129
-
130
- console.log(chalk.cyan('📁 Arquivos gerados: ' + chalk.underline(dir || '.')));
131
- console.log(chalk.gray('\nPróximos passos:'));
132
- console.log(' 1. Configure seus API tokens no Wrangler');
133
- console.log(' 2. Faça o deploy: ' + chalk.bold('wrangler deploy'));
134
- console.log(' 3. Configure o domínio no Cloudflare Dashboard');
110
+ // ── PASSO 4: Credenciais Meta ──────────────────────────────────────────────
111
+ const creds = {};
112
+
113
+ if (adsPlataformas.includes('meta')) {
114
+ sep('4a. Credenciais — Meta Ads');
115
+ console.log(chalk.gray(' Onde encontrar: Meta Events Manager → Configurações → Pixel\n'));
116
+
117
+ const meta = await inquirer.prompt([
118
+ {
119
+ type: 'input',
120
+ name: 'pixelId',
121
+ message: 'Meta Pixel ID:',
122
+ validate: v => v.trim() ? true : 'Pixel ID é obrigatório',
123
+ filter: v => v.trim(),
124
+ },
125
+ {
126
+ type: 'password',
127
+ name: 'accessToken',
128
+ message: 'Meta Access Token (CAPI):',
129
+ mask: '*',
130
+ validate: v => v.trim() ? true : 'Access Token é obrigatório',
131
+ },
132
+ {
133
+ type: 'input',
134
+ name: 'testCode',
135
+ message: 'Meta Test Event Code (opcional, para homologação):',
136
+ default: '',
137
+ filter: v => v.trim(),
138
+ },
139
+ ]);
140
+ creds.meta = meta;
141
+ }
142
+
143
+ if (adsPlataformas.includes('google')) {
144
+ sep('4b. Credenciais Google Analytics 4');
145
+ console.log(chalk.gray(' Onde encontrar: GA4 Admin Data Streams → Measurement Protocol\n'));
146
+
147
+ const google = await inquirer.prompt([
148
+ {
149
+ type: 'input',
150
+ name: 'measurementId',
151
+ message: 'GA4 Measurement ID (G-XXXXXXXX):',
152
+ validate: v => /^G-[A-Z0-9]+$/i.test(v.trim()) ? true : 'Formato: G-XXXXXXXX',
153
+ filter: v => v.trim().toUpperCase(),
154
+ },
155
+ {
156
+ type: 'password',
157
+ name: 'apiSecret',
158
+ message: 'GA4 API Secret:',
159
+ mask: '*',
160
+ validate: v => v.trim() ? true : 'API Secret é obrigatório',
161
+ },
162
+ ]);
163
+ creds.google = google;
164
+ }
165
+
166
+ if (adsPlataformas.includes('tiktok')) {
167
+ sep('4c. Credenciais TikTok');
168
+ console.log(chalk.gray(' Onde encontrar: TikTok Events Manager → Pixel → Detalhes\n'));
169
+
170
+ const tiktok = await inquirer.prompt([
171
+ {
172
+ type: 'input',
173
+ name: 'pixelId',
174
+ message: 'TikTok Pixel ID:',
175
+ validate: v => v.trim() ? true : 'Pixel ID é obrigatório',
176
+ filter: v => v.trim(),
177
+ },
178
+ {
179
+ type: 'password',
180
+ name: 'accessToken',
181
+ message: 'TikTok Access Token:',
182
+ mask: '*',
183
+ validate: v => v.trim() ? true : 'Access Token é obrigatório',
184
+ },
185
+ ]);
186
+ creds.tiktok = tiktok;
187
+ }
188
+
189
+ // ── PASSO 5: Alertas WhatsApp ──────────────────────────────────────────────
190
+ sep('5. Alertas WhatsApp (opcional)');
191
+ console.log(chalk.gray(' Receba alertas de erros e match quality direto no WhatsApp.\n'));
192
+
193
+ const { wantsWhatsapp } = await inquirer.prompt([
194
+ {
195
+ type: 'confirm',
196
+ name: 'wantsWhatsapp',
197
+ message: 'Deseja ativar alertas via WhatsApp?',
198
+ default: true,
199
+ },
200
+ ]);
201
+
202
+ let whatsapp = {};
203
+ if (wantsWhatsapp) {
204
+ console.log(chalk.gray('\n Como configurar: acesse callmebot.com e adicione o bot no WhatsApp.'));
205
+ console.log(chalk.gray(' Envie "I allow callmebot to send me messages" para +34 644 35 78 48\n'));
206
+
207
+ whatsapp = await inquirer.prompt([
208
+ {
209
+ type: 'input',
210
+ name: 'phone',
211
+ message: 'Seu número com DDI (ex: +5511999999999):',
212
+ validate: v => /^\+\d{10,15}$/.test(v.trim()) ? true : 'Formato: +5511999999999',
213
+ filter: v => v.trim(),
214
+ },
215
+ {
216
+ type: 'password',
217
+ name: 'apiKey',
218
+ message: 'CallMeBot API Key:',
219
+ mask: '*',
220
+ validate: v => v.trim() ? true : 'API Key é obrigatória',
221
+ },
222
+ ]);
223
+ }
224
+
225
+ // ── GERAÇÃO DOS OUTPUTS ────────────────────────────────────────────────────
226
+ const spinner = ora('Gerando configurações...').start();
227
+ await sleep(600);
228
+ spinner.succeed('Configurações geradas!');
229
+
230
+ const domain = projeto.domain;
231
+
232
+ // Monta lista de secrets
233
+ const secrets = [];
234
+
235
+ if (creds.meta) {
236
+ secrets.push({ key: 'META_PIXEL_ID', value: creds.meta.pixelId, platform: 'Meta' });
237
+ secrets.push({ key: 'META_ACCESS_TOKEN', value: creds.meta.accessToken, platform: 'Meta' });
238
+ if (creds.meta.testCode) {
239
+ secrets.push({ key: 'META_TEST_CODE', value: creds.meta.testCode, platform: 'Meta (homologação)' });
240
+ }
241
+ }
242
+
243
+ if (creds.google) {
244
+ secrets.push({ key: 'GA4_MEASUREMENT_ID', value: creds.google.measurementId, platform: 'Google' });
245
+ secrets.push({ key: 'GA4_API_SECRET', value: creds.google.apiSecret, platform: 'Google' });
246
+ }
247
+
248
+ if (creds.tiktok) {
249
+ secrets.push({ key: 'TIKTOK_PIXEL_ID', value: creds.tiktok.pixelId, platform: 'TikTok' });
250
+ secrets.push({ key: 'TIKTOK_ACCESS_TOKEN', value: creds.tiktok.accessToken, platform: 'TikTok' });
135
251
  }
252
+
253
+ if (whatsapp.phone) {
254
+ secrets.push({ key: 'CALLMEBOT_PHONE', value: whatsapp.phone, platform: 'WhatsApp' });
255
+ secrets.push({ key: 'CALLMEBOT_API_KEY', value: whatsapp.apiKey, platform: 'WhatsApp' });
256
+ }
257
+
258
+ secrets.push({ key: 'SITE_DOMAIN', value: domain, platform: 'Worker' });
259
+
260
+ // Webhooks
261
+ const webhookUrls = {};
262
+ const webhookSecrets = [];
263
+ if (plataformas.includes('hotmart')) {
264
+ webhookUrls.hotmart = `https://${domain}/webhook/hotmart`;
265
+ webhookSecrets.push({ key: 'WEBHOOK_SECRET_HOTMART', platform: 'Hotmart', note: 'Gere uma senha forte qualquer' });
266
+ }
267
+ if (plataformas.includes('kiwify')) {
268
+ webhookUrls.kiwify = `https://${domain}/webhook/kiwify`;
269
+ webhookSecrets.push({ key: 'WEBHOOK_SECRET_KIWIFY', platform: 'Kiwify', note: 'Gere uma senha forte qualquer' });
270
+ }
271
+ if (plataformas.includes('ticto')) {
272
+ webhookUrls.ticto = `https://${domain}/webhook/ticto`;
273
+ webhookSecrets.push({ key: 'WEBHOOK_SECRET_TICTO', platform: 'Ticto', note: 'Chave HMAC configurada no painel Ticto' });
274
+ }
275
+
276
+ // ── EXIBIR RESULTADO ───────────────────────────────────────────────────────
277
+ console.log('\n');
278
+ sep('CONFIGURAÇÃO PRONTA');
279
+
280
+ console.log(chalk.green.bold('\n Projeto: ') + chalk.white(projeto.projectName));
281
+ console.log(chalk.green.bold(' Domínio: ') + chalk.white(domain));
282
+ console.log(chalk.green.bold(' Produto: ') + chalk.white(projeto.productType));
283
+ console.log(chalk.green.bold(' Ads: ') + chalk.white(adsPlataformas.join(', ')));
284
+
285
+ // Comandos de secrets
286
+ sep('Comandos para configurar os secrets');
287
+ console.log(chalk.gray(' Execute dentro da pasta server-edge-tracker:\n'));
288
+
289
+ for (const s of secrets) {
290
+ const masked = s.value.length > 4 ? s.value.slice(0, 4) + '*'.repeat(Math.min(s.value.length - 4, 8)) : '****';
291
+ console.log(chalk.cyan(` wrangler secret put ${s.key}`));
292
+ console.log(chalk.gray(` # ${s.platform} — valor: ${masked}\n`));
293
+ }
294
+
295
+ if (webhookSecrets.length > 0) {
296
+ console.log(chalk.yellow(' # Secrets de webhook (gere senhas e configure abaixo + no painel da plataforma):'));
297
+ for (const ws of webhookSecrets) {
298
+ console.log(chalk.cyan(` wrangler secret put ${ws.key}`));
299
+ console.log(chalk.gray(` # ${ws.platform}: ${ws.note}\n`));
300
+ }
301
+ }
302
+
303
+ // URLs de webhook
304
+ if (Object.keys(webhookUrls).length > 0) {
305
+ sep('URLs de Webhook para configurar nas plataformas');
306
+ for (const [plat, url] of Object.entries(webhookUrls)) {
307
+ console.log(chalk.green.bold(` ${plat.charAt(0).toUpperCase() + plat.slice(1)}:`));
308
+ console.log(chalk.white(` ${url}\n`));
309
+ }
310
+ }
311
+
312
+ // Checklist
313
+ sep('Próximos passos');
314
+ const steps = [
315
+ 'Executar todos os wrangler secret put acima',
316
+ 'Executar as migrations D1 (schema.sql → migrate-v7.sql)',
317
+ 'Executar: wrangler deploy',
318
+ ...(Object.keys(webhookUrls).length > 0 ? ['Configurar as URLs de webhook nas plataformas de venda'] : []),
319
+ 'Configurar Worker Route no Cloudflare: ' + domain + '/*',
320
+ 'Testar o endpoint: https://' + domain + '/health',
321
+ ...(adsPlataformas.includes('meta') && creds.meta?.testCode ? ['Testar eventos no Meta Events Manager com o Test Event Code'] : []),
322
+ ];
323
+
324
+ steps.forEach((step, i) => {
325
+ console.log(chalk.cyan(` [${i + 1}] `) + chalk.white(step));
326
+ });
327
+
328
+ // Salvar config (sem tokens reais)
329
+ const configOutput = {
330
+ generatedAt: new Date().toISOString(),
331
+ domain,
332
+ projectName: projeto.projectName,
333
+ productType: projeto.productType,
334
+ adsPlataformas,
335
+ checkoutPlataformas: plataformas,
336
+ webhookUrls,
337
+ secretKeys: secrets.map(s => s.key),
338
+ whatsappAlertsEnabled: !!whatsapp.phone,
339
+ };
340
+
341
+ const outputPath = join(dir, 'cdp-edge-setup.json');
342
+ try {
343
+ writeFileSync(outputPath, JSON.stringify(configOutput, null, 2), 'utf8');
344
+ console.log(chalk.gray(`\n Configuração salva em: ${outputPath} (sem tokens)\n`));
345
+ } catch {
346
+ // não crítico se não conseguir salvar
347
+ }
348
+
349
+ sep();
350
+ console.log(chalk.green.bold('\n Setup concluído! Passe os comandos acima para o agente instalar.\n'));
136
351
  }
137
352
 
138
353
  function sleep(ms) {
@@ -592,3 +592,92 @@ Para suporte, consulte:
592
592
 
593
593
  *CDP Edge Premium Tracking Intelligence - Integração Completa (Quantum Tier)*
594
594
  *Versão 1.0.0 - Atualizado em 2026-03-27*
595
+
596
+ ---
597
+
598
+ ## Pipeline de Melhoria Contínua Automática (Fase 5)
599
+
600
+ A Fase 5 não adiciona novos eventos de tracking — ela fecha o ciclo de dados para que cada evento coletado melhore automaticamente a qualidade dos próximos.
601
+
602
+ ### Arquitetura do pipeline
603
+
604
+ ```
605
+ Browser (cdpTrack.js)
606
+
607
+ └─ POST /track
608
+
609
+ ├─ [Auto-Enrich] Antes do dispatch Meta CAPI:
610
+ │ Worker consulta user_profiles por userId
611
+ │ → recupera email/fbp/fbc ausentes do perfil
612
+ │ → evento vai para Meta com Advanced Matching completo
613
+
614
+ ├─ [Dispatch Meta CAPI]
615
+ │ → Grava match_quality_log (has_email, has_fbp, etc.)
616
+
617
+ ├─ [LTV Prediction]
618
+ │ → Usa ltv_model_weights (se modelo treinado disponível)
619
+ │ → Fallback para heurística
620
+
621
+ └─ [D1 Writes]
622
+ → leads, user_profiles, match_quality_log
623
+
624
+ Cron semanal (Worker scheduled)
625
+
626
+ ├─ Treina regressão logística → ltv_model_weights (is_active=1)
627
+ │ → cached em KV para ~0ms no próximo /track
628
+
629
+ ├─ Analisa match_quality_log (janela 2h)
630
+ │ → email_rate < 40% → alerta CallMeBot
631
+ │ → fbp_rate < 30% → alerta CallMeBot
632
+ │ → composite < 45% → alerta CallMeBot
633
+
634
+ ├─ Verifica experimentos A/B LTV
635
+ │ → variação bate controle por ≥5pp → auto-winner declarado
636
+ │ → alerta WhatsApp com prompt ativado
637
+
638
+ └─ Export Customer Match
639
+ → leads high_intent → GET /export/customer-match
640
+ → CSV para Google Ads (SHA-256 hashed)
641
+ ```
642
+
643
+ ### Novas tabelas D1 criadas na Fase 5
644
+
645
+ | Tabela | Migration | Conteúdo |
646
+ |---|---|---|
647
+ | `ltv_model_weights` | `migrate-v7.sql` | Pesos do modelo treinado (trained_at, is_active, accuracy, weights_json) |
648
+ | `match_quality_log` | `migrate-v7.sql` | Flags por evento: has_email, has_fbp, has_phone, has_fbc, was_email_recovered |
649
+
650
+ **View:** `v_match_quality_24h` — agrega match quality das últimas 24h para consulta rápida.
651
+
652
+ ### Migration completa atualizada (incluindo Fase 5)
653
+
654
+ ```bash
655
+ wrangler d1 execute cdp-edge-db --file=schema.sql --remote
656
+ wrangler d1 execute cdp-edge-db --file=migrate-v6.sql --remote
657
+ wrangler d1 execute cdp-edge-db --file=schema-segmentation.sql --remote
658
+ wrangler d1 execute cdp-edge-db --file=schema-bidding.sql --remote
659
+ wrangler d1 execute cdp-edge-db --file=schema-ab-ltv.sql --remote
660
+ wrangler d1 execute cdp-edge-db --file=schema-fraud.sql --remote
661
+ wrangler d1 execute cdp-edge-db --file=schema-indexes.sql --remote
662
+ wrangler d1 execute cdp-edge-db --file=migrate-v7.sql --remote
663
+ ```
664
+
665
+ ### Endpoints novos para monitoramento
666
+
667
+ | Endpoint | O que monitora |
668
+ |---|---|
669
+ | `GET /api/fraud/stats` | Fraude 24h + qualidade de sinal |
670
+ | `GET /api/segmentation/list` | Clusters ML ativos com métricas de LTV |
671
+ | `GET /api/bidding/status` | Bids recomendados por segmento × plataforma |
672
+ | `GET /api/ltv/ab-test/results` | Acurácia por variação de prompt LTV |
673
+ | `GET /export/customer-match` | Export CSV de leads high-intent para Google Ads |
674
+
675
+ ### Impacto esperado no funil
676
+
677
+ | Componente | Mecanismo | Resultado |
678
+ |---|---|---|
679
+ | Advanced Matching Meta | Auto-Enrich recupera email/fbp de sessões anteriores | EMQ sobe → atribuição mais precisa |
680
+ | LTV Score | Modelo treinado em dados reais do funil | Bids mais precisos → menor CPA |
681
+ | Match Quality Alerts | Degradação detectada automaticamente | Fix em horas, não em dias |
682
+ | A/B Auto-Winner | Melhor prompt LTV ativado automaticamente | LTV scores mais precisos sem revisão manual |
683
+ | Customer Match | Leads high-intent exportados semanalmente | Audiência Google sempre atualizada |