cdp-edge 2.0.4 → 2.0.6
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/dist/commands/install.js +1 -1
- package/dist/commands/setup.js +326 -111
- package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +89 -0
- package/extracted-skill/tracking-events-generator/MELHORIAS-IMPLEMENTADAS.md +101 -0
- package/extracted-skill/tracking-events-generator/agents/devops-agent.md +11 -0
- package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +27 -0
- package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +1 -1
- package/extracted-skill/tracking-events-generator/knowledge-base.md +172 -0
- package/package.json +1 -1
- package/server-edge-tracker/INSTALAR.md +27 -3
- package/server-edge-tracker/SEGMENTATION-DOCS.md +69 -0
- package/server-edge-tracker/index.js +11 -0
- package/server-edge-tracker/migrate-v7.sql +64 -0
- package/server-edge-tracker/modules/dispatch/meta.js +16 -0
- package/server-edge-tracker/modules/intelligence.js +120 -3
- package/server-edge-tracker/modules/ml/logistic.js +195 -0
- package/server-edge-tracker/modules/ml/ltv.js +100 -0
- package/server-edge-tracker/modules/ml/matchquality.js +176 -0
- package/server-edge-tracker/schema-indexes.sql +7 -7
- package/server-edge-tracker/worker.js +395 -4
- package/server-edge-tracker/wrangler.toml +19 -6
package/dist/commands/install.js
CHANGED
|
@@ -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.
|
|
35
|
+
console.log(chalk.gray(' Customer Data Platform on the Edge · Global Edge Tracking · v2.0.6'));
|
|
36
36
|
console.log('');
|
|
37
37
|
console.log(chalk.gray('═'.repeat(68)));
|
|
38
38
|
console.log('');
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,138 +1,353 @@
|
|
|
1
|
-
|
|
2
|
-
* Setup Wizard
|
|
1
|
+
/**
|
|
2
|
+
* CDP Edge Setup Wizard — Guiado e não-técnico
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
40
|
+
// ── PASSO 1: Dados do projeto ──────────────────────────────────────────────
|
|
41
|
+
sep('1. Dados do Projeto');
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
//
|
|
71
|
+
// ── PASSO 2: Plataforma de vendas ──────────────────────────────────────────
|
|
72
|
+
sep('2. Plataforma de Vendas / Checkout');
|
|
46
73
|
|
|
47
|
-
const
|
|
74
|
+
const { plataformas } = await inquirer.prompt([
|
|
48
75
|
{
|
|
49
|
-
type:
|
|
50
|
-
name:
|
|
51
|
-
message: '
|
|
76
|
+
type: 'checkbox',
|
|
77
|
+
name: 'plataformas',
|
|
78
|
+
message: 'Quais plataformas de checkout você usa? (espaço para marcar)',
|
|
52
79
|
choices: [
|
|
53
|
-
{ name: '
|
|
54
|
-
{ name: '
|
|
55
|
-
{ name: '
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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 |
|