cdp-edge 1.0.0
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 +324 -0
- package/bin/cdp-edge.js +71 -0
- package/contracts/agent-versions.json +679 -0
- package/contracts/api-versions.json +372 -0
- package/contracts/types.ts +81 -0
- package/dist/commands/analyze.js +52 -0
- package/dist/commands/infra.js +54 -0
- package/dist/commands/install.js +191 -0
- package/dist/commands/server.js +174 -0
- package/dist/commands/setup.js +355 -0
- package/dist/commands/validate.js +248 -0
- package/dist/index.js +12 -0
- package/dist/sdk/cdpTrack.js +2095 -0
- package/dist/sdk/cdpTrack.min.js +64 -0
- package/dist/sdk/install-snippet.html +10 -0
- package/docs/CI-CD-SETUP.md +217 -0
- package/docs/events-reference.md +359 -0
- package/docs/installation.md +155 -0
- package/docs/quick-start.md +185 -0
- package/docs/sdk-reference.md +371 -0
- package/docs/whatsapp-ctwa.md +210 -0
- package/extracted-skill/tracking-events-generator/INDEX.md +94 -0
- package/extracted-skill/tracking-events-generator/INSTALACAO-CDPEDGE.md +58 -0
- package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +683 -0
- package/extracted-skill/tracking-events-generator/MELHORIAS-IMPLEMENTADAS.md +513 -0
- package/extracted-skill/tracking-events-generator/Premium-Tracking-Intelligence-Resumo.md +333 -0
- package/extracted-skill/tracking-events-generator/SKILL.md +257 -0
- package/extracted-skill/tracking-events-generator/advanced-matching.js +364 -0
- package/extracted-skill/tracking-events-generator/agents/ab-ltv-agent.md +196 -0
- package/extracted-skill/tracking-events-generator/agents/ab-testing-agent.md +54 -0
- package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +1304 -0
- package/extracted-skill/tracking-events-generator/agents/bidding-agent.md +347 -0
- package/extracted-skill/tracking-events-generator/agents/bing-agent.md +66 -0
- package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +364 -0
- package/extracted-skill/tracking-events-generator/agents/code-guardian-agent.md +149 -0
- package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +2097 -0
- package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +1459 -0
- package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +456 -0
- package/extracted-skill/tracking-events-generator/agents/database-agent.md +668 -0
- package/extracted-skill/tracking-events-generator/agents/debug-agent.md +1455 -0
- package/extracted-skill/tracking-events-generator/agents/devops-agent.md +232 -0
- package/extracted-skill/tracking-events-generator/agents/domain-setup-agent.md +238 -0
- package/extracted-skill/tracking-events-generator/agents/email-agent.md +88 -0
- package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +257 -0
- package/extracted-skill/tracking-events-generator/agents/fraud-detection-agent.md +143 -0
- package/extracted-skill/tracking-events-generator/agents/google-agent.md +235 -0
- package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +525 -0
- package/extracted-skill/tracking-events-generator/agents/lead-scoring-agent.md +282 -0
- package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +173 -0
- package/extracted-skill/tracking-events-generator/agents/localization-agent.md +55 -0
- package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +59 -0
- package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +960 -0
- package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +2154 -0
- package/extracted-skill/tracking-events-generator/agents/match-quality-agent.md +304 -0
- package/extracted-skill/tracking-events-generator/agents/memory-agent.json +25 -0
- package/extracted-skill/tracking-events-generator/agents/memory-agent.md +878 -0
- package/extracted-skill/tracking-events-generator/agents/meta-agent.md +118 -0
- package/extracted-skill/tracking-events-generator/agents/ml-clustering-agent.md +749 -0
- package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +272 -0
- package/extracted-skill/tracking-events-generator/agents/performance-agent.md +1167 -0
- package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +1442 -0
- package/extracted-skill/tracking-events-generator/agents/pinterest-agent.md +318 -0
- package/extracted-skill/tracking-events-generator/agents/premium-tracking-intelligence-agent.md +849 -0
- package/extracted-skill/tracking-events-generator/agents/r2-setup-agent.md +258 -0
- package/extracted-skill/tracking-events-generator/agents/reddit-agent.md +321 -0
- package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +1861 -0
- package/extracted-skill/tracking-events-generator/agents/server-tracking.md +1188 -0
- package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +391 -0
- package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +182 -0
- package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +459 -0
- package/extracted-skill/tracking-events-generator/agents/utm-agent.md +322 -0
- package/extracted-skill/tracking-events-generator/agents/validator-agent.md +271 -0
- package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +177 -0
- package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +129 -0
- package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +707 -0
- package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +537 -0
- package/extracted-skill/tracking-events-generator/anti-blocking.js +285 -0
- package/extracted-skill/tracking-events-generator/cdpTrack.js +640 -0
- package/extracted-skill/tracking-events-generator/contracts/api-versions.json +372 -0
- package/extracted-skill/tracking-events-generator/docs/guia-cloudflare-iniciante.md +107 -0
- package/extracted-skill/tracking-events-generator/engagement-scoring.js +226 -0
- package/extracted-skill/tracking-events-generator/evals/evals.json +235 -0
- package/extracted-skill/tracking-events-generator/integration-test.js +497 -0
- package/extracted-skill/tracking-events-generator/knowledge-base.md +3066 -0
- package/extracted-skill/tracking-events-generator/micro-events.js +992 -0
- package/extracted-skill/tracking-events-generator/models/captura-de-lead.md +78 -0
- package/extracted-skill/tracking-events-generator/models/captura-lead-evento-externo.md +99 -0
- package/extracted-skill/tracking-events-generator/models/checkout-proprio.md +111 -0
- package/extracted-skill/tracking-events-generator/models/lancamento-imobiliario.md +344 -0
- package/extracted-skill/tracking-events-generator/models/multi-step-checkout.md +672 -0
- package/extracted-skill/tracking-events-generator/models/pagina-obrigado.md +55 -0
- package/extracted-skill/tracking-events-generator/models/pinterest/conversions-api-template.js +144 -0
- package/extracted-skill/tracking-events-generator/models/pinterest/event-mappings.json +48 -0
- package/extracted-skill/tracking-events-generator/models/pinterest/tag-template.js +28 -0
- package/extracted-skill/tracking-events-generator/models/quiz-funnel.md +132 -0
- package/extracted-skill/tracking-events-generator/models/reddit/conversions-api-template.js +205 -0
- package/extracted-skill/tracking-events-generator/models/reddit/event-mappings.json +56 -0
- package/extracted-skill/tracking-events-generator/models/reddit/pixel-template.js +19 -0
- package/extracted-skill/tracking-events-generator/models/scenarios/behavior-engine.js +425 -0
- package/extracted-skill/tracking-events-generator/models/scenarios/real-estate-logic.md +50 -0
- package/extracted-skill/tracking-events-generator/models/scenarios/sales-page-logic.md +50 -0
- package/extracted-skill/tracking-events-generator/models/trafego-direto.md +582 -0
- package/extracted-skill/tracking-events-generator/models/webinar-registration.md +63 -0
- package/extracted-skill/tracking-events-generator/route-intent-capture.js +222 -0
- package/extracted-skill/tracking-events-generator/tracking.config.js +46 -0
- package/extracted-skill/tracking-events-generator/walkthrough.md +26 -0
- package/package.json +89 -0
- package/scripts/build-sdk.js +106 -0
- package/server-edge-tracker/.client.env.example +14 -0
- package/server-edge-tracker/INSTALAR.md +527 -0
- package/server-edge-tracker/SEGMENTATION-DOCS.md +513 -0
- package/server-edge-tracker/config/utm-mapping.json +64 -0
- package/server-edge-tracker/deploy-client.cjs +76 -0
- package/server-edge-tracker/index.ts +1164 -0
- package/server-edge-tracker/migrate-new-db.sql +137 -0
- package/server-edge-tracker/migrate-v2.sql +16 -0
- package/server-edge-tracker/migrate-v3.sql +6 -0
- package/server-edge-tracker/migrate-v4.sql +18 -0
- package/server-edge-tracker/migrate-v5.sql +17 -0
- package/server-edge-tracker/migrate-v6.sql +24 -0
- package/server-edge-tracker/migrate-v7.sql +64 -0
- package/server-edge-tracker/migrate.sql +111 -0
- package/server-edge-tracker/modules/db.ts +702 -0
- package/server-edge-tracker/modules/dispatch/ga4.ts +72 -0
- package/server-edge-tracker/modules/dispatch/meta.ts +143 -0
- package/server-edge-tracker/modules/dispatch/platforms.ts +255 -0
- package/server-edge-tracker/modules/dispatch/tiktok.ts +107 -0
- package/server-edge-tracker/modules/dispatch/whatsapp.ts +279 -0
- package/server-edge-tracker/modules/intelligence.ts +589 -0
- package/server-edge-tracker/modules/ml/bidding.ts +247 -0
- package/server-edge-tracker/modules/ml/fraud.ts +302 -0
- package/server-edge-tracker/modules/ml/logistic.ts +226 -0
- package/server-edge-tracker/modules/ml/ltv.ts +531 -0
- package/server-edge-tracker/modules/ml/matchquality.ts +232 -0
- package/server-edge-tracker/modules/ml/quiz.ts +343 -0
- package/server-edge-tracker/modules/ml/roas.ts +255 -0
- package/server-edge-tracker/modules/ml/segmentation.ts +407 -0
- package/server-edge-tracker/modules/nurture.ts +257 -0
- package/server-edge-tracker/modules/utils.ts +311 -0
- package/server-edge-tracker/modules/utm/utm-enricher.ts +231 -0
- package/server-edge-tracker/schema-ab-ltv.sql +97 -0
- package/server-edge-tracker/schema-bidding.sql +86 -0
- package/server-edge-tracker/schema-fraud.sql +90 -0
- package/server-edge-tracker/schema-indexes.sql +67 -0
- package/server-edge-tracker/schema-ltv-feedback.sql +11 -0
- package/server-edge-tracker/schema-quiz.sql +52 -0
- package/server-edge-tracker/schema-sales-engine.sql +113 -0
- package/server-edge-tracker/schema-segmentation.sql +219 -0
- package/server-edge-tracker/schema-utm.sql +82 -0
- package/server-edge-tracker/schema.sql +265 -0
- package/server-edge-tracker/types.ts +258 -0
- package/server-edge-tracker/wrangler.toml +136 -0
- package/templates/afiliado-sem-landing.md +312 -0
- package/templates/captura-de-lead.md +78 -0
- package/templates/captura-lead-evento-externo.md +99 -0
- package/templates/checkout-proprio.md +111 -0
- package/templates/install/.claude/commands/cdp.md +1 -0
- package/templates/install/CLAUDE.md +65 -0
- package/templates/lancamento-imobiliario.md +344 -0
- package/templates/linkedin/tag-template.js +46 -0
- package/templates/multi-step-checkout.md +672 -0
- package/templates/pagina-obrigado.md +55 -0
- package/templates/pinterest/conversions-api-template.js +144 -0
- package/templates/pinterest/event-mappings.json +48 -0
- package/templates/pinterest/tag-template.js +28 -0
- package/templates/quiz-funnel.md +132 -0
- package/templates/reddit/conversions-api-template.js +205 -0
- package/templates/reddit/event-mappings.json +56 -0
- package/templates/reddit/pixel-template.js +19 -0
- package/templates/scenarios/behavior-engine.js +425 -0
- package/templates/scenarios/real-estate-logic.md +50 -0
- package/templates/scenarios/sales-page-logic.md +50 -0
- package/templates/spotify/pixel-template.js +46 -0
- package/templates/trafego-direto.md +582 -0
- package/templates/vsl-page.md +292 -0
- package/templates/webinar-registration.md +63 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADVANCED MATCHING MAXIMUM - CDP Edge (Quantum Tier)
|
|
3
|
+
*
|
|
4
|
+
* Sistema de normalização e hashing de PII (Personally Identifiable Information)
|
|
5
|
+
* para máxima precisão de atribuição em Meta CAPI v22.0.
|
|
6
|
+
*
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ── Guards ────────────────────────────────────────────────
|
|
11
|
+
const isBrowser = typeof window !== 'undefined';
|
|
12
|
+
|
|
13
|
+
// ── Configurações de Normalização ─────────────────────
|
|
14
|
+
|
|
15
|
+
const NORMALIZATION_CONFIG = {
|
|
16
|
+
email: {
|
|
17
|
+
trim: true,
|
|
18
|
+
lowercase: true,
|
|
19
|
+
removeDots: false, // Gmail: user.name@gmail.com vs username@gmail.com (diferentes)
|
|
20
|
+
removePlus: true // Gmail: user+tag@gmail.com = user@gmail.com (mesmo)
|
|
21
|
+
},
|
|
22
|
+
phone: {
|
|
23
|
+
keepOnlyDigits: true,
|
|
24
|
+
addCountryCode: true, // Adiciona DDI se não tiver (55 para Brasil)
|
|
25
|
+
defaultCountryCode: '55'
|
|
26
|
+
},
|
|
27
|
+
name: {
|
|
28
|
+
trim: true,
|
|
29
|
+
lowercase: true,
|
|
30
|
+
removeAccents: true,
|
|
31
|
+
removeExtraSpaces: true,
|
|
32
|
+
maxLength: 100
|
|
33
|
+
},
|
|
34
|
+
city: {
|
|
35
|
+
trim: true,
|
|
36
|
+
lowercase: true,
|
|
37
|
+
removeAccents: true,
|
|
38
|
+
maxLength: 50
|
|
39
|
+
},
|
|
40
|
+
state: {
|
|
41
|
+
trim: true,
|
|
42
|
+
lowercase: true,
|
|
43
|
+
removeAccents: true,
|
|
44
|
+
maxLength: 50
|
|
45
|
+
},
|
|
46
|
+
zip: {
|
|
47
|
+
trim: true,
|
|
48
|
+
keepOnlyDigits: true,
|
|
49
|
+
maxLength: 10
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// ── Funções de Normalização ──────────────────────────────
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Normaliza e-mail para máximo match
|
|
57
|
+
*
|
|
58
|
+
* Gmail Plus: user+tag@gmail.com = user@gmail.com (mesmo usuário)
|
|
59
|
+
* Lowercase: USER@GMAIL.COM = user@gmail.com (case-insensitive)
|
|
60
|
+
* Trim: remove espaços
|
|
61
|
+
*
|
|
62
|
+
* @param {string} email - E-mail bruto
|
|
63
|
+
* @returns {string} E-mail normalizado
|
|
64
|
+
*/
|
|
65
|
+
function normalizeEmail(email) {
|
|
66
|
+
if (!email || typeof email !== 'string') return '';
|
|
67
|
+
|
|
68
|
+
let normalized = email.trim();
|
|
69
|
+
|
|
70
|
+
// Gmail: remover tudo após + (plus addressing)
|
|
71
|
+
if (normalized.includes('@gmail.com')) {
|
|
72
|
+
normalized = normalized.split('+')[0] + '@gmail.com';
|
|
73
|
+
}
|
|
74
|
+
// GMR (Google Mail): remover plus
|
|
75
|
+
if (normalized.includes('@googlemail.com')) {
|
|
76
|
+
normalized = normalized.split('+')[0] + '@googlemail.com';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return normalized.toLowerCase();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Normaliza telefone para máximo match
|
|
84
|
+
*
|
|
85
|
+
* Remove caracteres não numéricos
|
|
86
|
+
* Adiciona código do país (55 para Brasil) se não tiver
|
|
87
|
+
*
|
|
88
|
+
* @param {string} phone - Telefone bruto
|
|
89
|
+
* @returns {string} Telefone normalizado (apenas números)
|
|
90
|
+
*/
|
|
91
|
+
function normalizePhone(phone) {
|
|
92
|
+
if (!phone || typeof phone !== 'string') return '';
|
|
93
|
+
|
|
94
|
+
// Remove tudo que não é número
|
|
95
|
+
let normalized = phone.replace(/\D/g, '');
|
|
96
|
+
|
|
97
|
+
// Se não tem DDI, adiciona 55 (Brasil)
|
|
98
|
+
if (normalized.length === 11 || normalized.length === 10) {
|
|
99
|
+
normalized = '55' + normalized;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Limita a 15 dígitos (máximo internacional)
|
|
103
|
+
return normalized.substring(0, 15);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Normaliza nome para máximo match
|
|
108
|
+
*
|
|
109
|
+
* Remove acentos, converte para minúsculas, remove espaços extras
|
|
110
|
+
*
|
|
111
|
+
* @param {string} name - Nome bruto
|
|
112
|
+
* @returns {string} Nome normalizado
|
|
113
|
+
*/
|
|
114
|
+
function normalizeName(name) {
|
|
115
|
+
if (!name || typeof name !== 'string') return '';
|
|
116
|
+
|
|
117
|
+
let normalized = name.trim();
|
|
118
|
+
|
|
119
|
+
// Remove acentos
|
|
120
|
+
normalized = normalized.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
|
121
|
+
|
|
122
|
+
// Converte para minúsculas
|
|
123
|
+
normalized = normalized.toLowerCase();
|
|
124
|
+
|
|
125
|
+
// Remove espaços extras (múltiplos espaços vira um)
|
|
126
|
+
normalized = normalized.replace(/\s+/g, ' ');
|
|
127
|
+
|
|
128
|
+
// Limita tamanho
|
|
129
|
+
return normalized.substring(0, NORMALIZATION_CONFIG.name.maxLength);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Normaliza cidade para Meta AM (Advanced Matching)
|
|
134
|
+
*
|
|
135
|
+
* @param {string} city - Cidade bruta
|
|
136
|
+
* @returns {string} Cidade normalizada
|
|
137
|
+
*/
|
|
138
|
+
function normalizeCity(city) {
|
|
139
|
+
if (!city || typeof city !== 'string') return '';
|
|
140
|
+
|
|
141
|
+
let normalized = city.trim();
|
|
142
|
+
|
|
143
|
+
// Remove acentos
|
|
144
|
+
normalized = normalized.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
|
145
|
+
|
|
146
|
+
// Converte para minúsculas
|
|
147
|
+
normalized = normalized.toLowerCase();
|
|
148
|
+
|
|
149
|
+
// Remove espaços extras
|
|
150
|
+
normalized = normalized.replace(/\s+/g, ' ');
|
|
151
|
+
|
|
152
|
+
return normalized.substring(0, NORMALIZATION_CONFIG.city.maxLength);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Normaliza estado para Meta AM
|
|
157
|
+
*
|
|
158
|
+
* @param {string} state - Estado bruto
|
|
159
|
+
* @returns {string} Estado normalizado
|
|
160
|
+
*/
|
|
161
|
+
function normalizeState(state) {
|
|
162
|
+
if (!state || typeof state !== 'string') return '';
|
|
163
|
+
|
|
164
|
+
let normalized = state.trim();
|
|
165
|
+
|
|
166
|
+
// Remove acentos
|
|
167
|
+
normalized = normalized.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
|
168
|
+
|
|
169
|
+
// Converte para minúsculas
|
|
170
|
+
normalized = normalized.toLowerCase();
|
|
171
|
+
|
|
172
|
+
return normalized.substring(0, NORMALIZATION_CONFIG.state.maxLength);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Normaliza CEP para Meta AM
|
|
177
|
+
*
|
|
178
|
+
* @param {string} zip - CEP bruto
|
|
179
|
+
* @returns {string} CEP normalizado (apenas números)
|
|
180
|
+
*/
|
|
181
|
+
function normalizeZip(zip) {
|
|
182
|
+
if (!zip || typeof zip !== 'string') return '';
|
|
183
|
+
|
|
184
|
+
// Remove tudo que não é número
|
|
185
|
+
const normalized = zip.replace(/\D/g, '');
|
|
186
|
+
|
|
187
|
+
return normalized.substring(0, NORMALIZATION_CONFIG.zip.maxLength);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Normaliza data de nascimento para Meta AM
|
|
192
|
+
*
|
|
193
|
+
* Formato esperado: YYYYMMDD
|
|
194
|
+
*
|
|
195
|
+
* @param {string} dob - Data de nascimento bruta
|
|
196
|
+
* @returns {string} Data normalizada (YYYYMMDD)
|
|
197
|
+
*/
|
|
198
|
+
function normalizeDOB(dob) {
|
|
199
|
+
if (!dob || typeof dob !== 'string') return '';
|
|
200
|
+
|
|
201
|
+
// Tenta diferentes formatos
|
|
202
|
+
const formats = [
|
|
203
|
+
/(\d{4})-(\d{2})-(\d{2})/, // YYYY-MM-DD
|
|
204
|
+
/(\d{2})\/(\d{2})\/(\d{4})/, // DD/MM/YYYY
|
|
205
|
+
/(\d{2})-(\d{2})-(\d{4})/ // DD-MM-YYYY
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
for (const format of formats) {
|
|
209
|
+
const match = dob.match(format);
|
|
210
|
+
if (match) {
|
|
211
|
+
let year, month, day;
|
|
212
|
+
if (match[1].length === 4) {
|
|
213
|
+
// YYYY-MM-DD
|
|
214
|
+
[year, month, day] = [match[1], match[2], match[3]];
|
|
215
|
+
} else {
|
|
216
|
+
// DD/MM/YYYY
|
|
217
|
+
[day, month, year] = [match[1], match[2], match[3]];
|
|
218
|
+
}
|
|
219
|
+
return `${year}${month}${day}`;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return '';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ── Browser-Side: Dados Crus para Worker ───────────
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Extrai dados PII de um formulário HTML para Advanced Matching
|
|
230
|
+
*
|
|
231
|
+
* @param {HTMLFormElement} form - Elemento do formulário
|
|
232
|
+
* @returns {object} Dados normalizados para envio ao Worker
|
|
233
|
+
*/
|
|
234
|
+
export function extractFormPII(form) {
|
|
235
|
+
if (!form || typeof form.elements !== 'object') return {};
|
|
236
|
+
|
|
237
|
+
const formData = new FormData(form);
|
|
238
|
+
const piiData = {};
|
|
239
|
+
|
|
240
|
+
// Campo de e-mail
|
|
241
|
+
const email = formData.get('email') || formData.get('user_email') || formData.get('useremail');
|
|
242
|
+
if (email) piiData.email = normalizeEmail(email);
|
|
243
|
+
|
|
244
|
+
// Campo de telefone
|
|
245
|
+
const phone = formData.get('phone') || formData.get('telephone') || formData.get('telefone') || formData.get('celular');
|
|
246
|
+
if (phone) piiData.phone = normalizePhone(phone);
|
|
247
|
+
|
|
248
|
+
// Campos de nome
|
|
249
|
+
const firstName = formData.get('first_name') || formData.get('nome') || formData.get('firstname');
|
|
250
|
+
const lastName = formData.get('last_name') || formData.get('sobrenome') || formData.get('lastname');
|
|
251
|
+
const fullName = formData.get('name') || formData.get('fullname') || formData.get('nome_completo');
|
|
252
|
+
|
|
253
|
+
if (fullName) {
|
|
254
|
+
const names = fullName.split(' ');
|
|
255
|
+
piiData.first_name = normalizeName(names[0]);
|
|
256
|
+
piiData.last_name = normalizeName(names.slice(1).join(' '));
|
|
257
|
+
} else {
|
|
258
|
+
if (firstName) piiData.first_name = normalizeName(firstName);
|
|
259
|
+
if (lastName) piiData.last_name = normalizeName(lastName);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Campos de endereço (Meta AM)
|
|
263
|
+
const city = formData.get('city') || formData.get('cidade');
|
|
264
|
+
if (city) piiData.city = normalizeCity(city);
|
|
265
|
+
|
|
266
|
+
const state = formData.get('state') || formData.get('estado') || formData.get('uf');
|
|
267
|
+
if (state) piiData.state = normalizeState(state);
|
|
268
|
+
|
|
269
|
+
const zip = formData.get('zip') || formData.get('cep') || formData.get('postalcode');
|
|
270
|
+
if (zip) piiData.zip = normalizeZip(zip);
|
|
271
|
+
|
|
272
|
+
const dob = formData.get('dob') || formData.get('date_of_birth') || formData.get('nascimento');
|
|
273
|
+
if (dob) piiData.dob = normalizeDOB(dob);
|
|
274
|
+
|
|
275
|
+
return piiData;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Captura dados PII de qualquer elemento (input, button click, etc.)
|
|
280
|
+
*
|
|
281
|
+
* @param {HTMLElement} element - Elemento DOM
|
|
282
|
+
* @returns {object} Dados PII normalizados
|
|
283
|
+
*/
|
|
284
|
+
export function capturePII(element) {
|
|
285
|
+
if (!element) return {};
|
|
286
|
+
|
|
287
|
+
const piiData = {};
|
|
288
|
+
|
|
289
|
+
// Se for input, extrair valor
|
|
290
|
+
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
|
|
291
|
+
const name = element.name.toLowerCase();
|
|
292
|
+
const value = element.value;
|
|
293
|
+
|
|
294
|
+
if (name.includes('email') && value) {
|
|
295
|
+
piiData.email = normalizeEmail(value);
|
|
296
|
+
} else if (name.includes('phone') || name.includes('telefone') || name.includes('celular')) {
|
|
297
|
+
if (value) piiData.phone = normalizePhone(value);
|
|
298
|
+
} else if (name.includes('name') || name.includes('nome')) {
|
|
299
|
+
if (value) piiData.full_name = normalizeName(value);
|
|
300
|
+
} else if (name.includes('city') || name.includes('cidade')) {
|
|
301
|
+
if (value) piiData.city = normalizeCity(value);
|
|
302
|
+
} else if (name.includes('state') || name.includes('estado')) {
|
|
303
|
+
if (value) piiData.state = normalizeState(value);
|
|
304
|
+
} else if (name.includes('zip') || name.includes('cep')) {
|
|
305
|
+
if (value) piiData.zip = normalizeZip(value);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return piiData;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Valida se os dados PII são válidos para envio
|
|
314
|
+
*
|
|
315
|
+
* @param {object} piiData - Dados PII normalizados
|
|
316
|
+
* @returns {boolean} True se tiver dados válidos
|
|
317
|
+
*/
|
|
318
|
+
export function isValidPII(piiData) {
|
|
319
|
+
if (!piiData || typeof piiData !== 'object') return false;
|
|
320
|
+
|
|
321
|
+
const hasEmail = piiData.email && piiData.email.includes('@');
|
|
322
|
+
const hasPhone = piiData.phone && piiData.phone.length >= 10;
|
|
323
|
+
|
|
324
|
+
return hasEmail || hasPhone;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ── Browser-Side: Hashing (Opcional - para debug) ────────
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Calcula SHA256 de um valor (browser-side)
|
|
331
|
+
*
|
|
332
|
+
* AVISO: Para máxima segurança, o hashing deve ser feito no Worker.
|
|
333
|
+
* Esta função é apenas para debug/visualização.
|
|
334
|
+
*
|
|
335
|
+
* @param {string} value - Valor para hash
|
|
336
|
+
* @returns {Promise<string>} Hash SHA256 em hexadecimal
|
|
337
|
+
*/
|
|
338
|
+
export async function hashPII(value) {
|
|
339
|
+
if (!value || !isBrowser) return '';
|
|
340
|
+
|
|
341
|
+
try {
|
|
342
|
+
const encoder = new TextEncoder();
|
|
343
|
+
const data = encoder.encode(value);
|
|
344
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
345
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
346
|
+
return hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
|
|
347
|
+
} catch (error) {
|
|
348
|
+
console.error('Erro ao calcular SHA256 no browser:', error);
|
|
349
|
+
return '';
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ── Exportações ────────────────────────────────────────────────
|
|
354
|
+
|
|
355
|
+
export {
|
|
356
|
+
normalizeEmail,
|
|
357
|
+
normalizePhone,
|
|
358
|
+
normalizeName,
|
|
359
|
+
normalizeCity,
|
|
360
|
+
normalizeState,
|
|
361
|
+
normalizeZip,
|
|
362
|
+
normalizeDOB,
|
|
363
|
+
NORMALIZATION_CONFIG
|
|
364
|
+
};
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# A/B LTV Testing Agent — CDP Edge Quantum Tier
|
|
2
|
+
|
|
3
|
+
## Identidade
|
|
4
|
+
|
|
5
|
+
**Agente:** A/B LTV Testing Agent
|
|
6
|
+
**Papel:** Otimização Contínua de Precisão do LTV Preditivo
|
|
7
|
+
**Nível:** Deus (Quantum Tier) — Enterprise-Level Fase 3
|
|
8
|
+
**Versão:** 1.0.0 — 9 de Abril de 2026
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Missão
|
|
13
|
+
|
|
14
|
+
Testar variações do prompt do modelo de LTV de forma automática e estatisticamente controlada,
|
|
15
|
+
identificando qual formulação do sistema prompt para o Workers AI produz as predições mais
|
|
16
|
+
próximas do valor real de compra — **aumentando a precisão do LTV em até +25%**.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Posição no Fluxo do Master Orchestrator
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Browser /track (Lead Event)
|
|
24
|
+
↓
|
|
25
|
+
LTV Prediction Call (predictLtv)
|
|
26
|
+
↓ [se teste ativo]
|
|
27
|
+
getLtvAbVariation() → sorteia variação ponderada do teste ativo
|
|
28
|
+
↓
|
|
29
|
+
Workers AI com system_prompt da variação sorteada
|
|
30
|
+
↓
|
|
31
|
+
D1: ltv_ab_assignments (registra user_id + variation_id + predicted_ltv)
|
|
32
|
+
↓
|
|
33
|
+
[quando compra chega via webhook]
|
|
34
|
+
D1: ltv_ab_assignments.converted = 1 + real_revenue
|
|
35
|
+
↓
|
|
36
|
+
GET /api/ltv/ab-test/results → accuracy_score por variação
|
|
37
|
+
↓
|
|
38
|
+
POST /api/ltv/ab-test/winner → aplica vencedor ao LTV padrão
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Upstream (de onde recebe dados):**
|
|
42
|
+
- `index.ts → predictLtv()` — ponto de interceptação do teste
|
|
43
|
+
- `webhook events` — fonte verdade do revenue real para scoring
|
|
44
|
+
|
|
45
|
+
**Downstream (quem consome outputs):**
|
|
46
|
+
- `ltv-predictor-agent.md` → recebe o prompt vencedor para aplicar como novo default
|
|
47
|
+
- `bidding-agent.md` → LTV mais preciso → bids mais precisos
|
|
48
|
+
- `dashboard-agent.md` → exibe resultados dos testes no painel
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Como o A/B Test Funciona
|
|
53
|
+
|
|
54
|
+
### 1. Criação do Experimento
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
POST /api/ltv/ab-test/create
|
|
58
|
+
{
|
|
59
|
+
"name": "Teste: Foco Engajamento vs Intenção",
|
|
60
|
+
"min_sample": 200,
|
|
61
|
+
"variations": [
|
|
62
|
+
{
|
|
63
|
+
"name": "Controle — Prompt Original",
|
|
64
|
+
"is_control": true,
|
|
65
|
+
"weight": 0.5,
|
|
66
|
+
"system_prompt": "You are a conversion rate expert. Reply ONLY with JSON {\"adjustment\": <-10 to 10>} based on lead data. No explanation."
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "Variação B — Foco em Intenção de Compra",
|
|
70
|
+
"weight": 0.5,
|
|
71
|
+
"system_prompt": "You are a Brazilian digital marketing expert specializing in course sales. Focus on purchase intention signals. Reply ONLY with JSON {\"adjustment\": <-10 to 10>}."
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Distribuição Automática
|
|
78
|
+
|
|
79
|
+
A cada chamada de `predictLtv()` para um evento Lead, o sistema:
|
|
80
|
+
1. Busca o teste ativo no D1 (com cache de 5 min no KV para evitar latência)
|
|
81
|
+
2. Sorteia uma variação usando distribuição ponderada pelos `weight`
|
|
82
|
+
3. Usa o `system_prompt` da variação sorteada no Workers AI
|
|
83
|
+
4. Registra o assignment em `ltv_ab_assignments`
|
|
84
|
+
|
|
85
|
+
### 3. Scoring Automático via Webhook
|
|
86
|
+
|
|
87
|
+
Quando chega um webhook de compra (`Purchase`), o sistema:
|
|
88
|
+
1. Busca o email do comprador em `ltv_ab_assignments` (por hash)
|
|
89
|
+
2. Atualiza `converted = 1` e `real_revenue = valor_da_compra`
|
|
90
|
+
3. Incrementa `total_purchases` e `sum_real_revenue` na variação
|
|
91
|
+
|
|
92
|
+
### 4. Cálculo de Accuracy Score
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
accuracy_score =
|
|
96
|
+
1 - (ABS(avg_predicted_ltv - avg_real_revenue) / avg_real_revenue)
|
|
97
|
+
→ 1.0 = predição perfeita
|
|
98
|
+
→ 0.0 = predição completamente errada
|
|
99
|
+
→ Valores negativos = predição muito errada
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 5. Declaração de Vencedor
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
POST /api/ltv/ab-test/winner
|
|
106
|
+
{ "test_id": 1, "variation_id": 2 }
|
|
107
|
+
→ marca variation como winner
|
|
108
|
+
→ retorna o system_prompt vencedor para aplicar como novo default
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Endpoints Expostos
|
|
114
|
+
|
|
115
|
+
| Método | Rota | Função |
|
|
116
|
+
|--------|------|--------|
|
|
117
|
+
| `POST` | `/api/ltv/ab-test/create` | Cria novo experimento com variações |
|
|
118
|
+
| `GET` | `/api/ltv/ab-test/list` | Lista todos os experimentos |
|
|
119
|
+
| `GET` | `/api/ltv/ab-test/results` | Resultados de accuracy por variação |
|
|
120
|
+
| `POST` | `/api/ltv/ab-test/winner` | Declara vencedor e retorna prompt |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Variações de Prompt Predefinidas (use nos seus testes)
|
|
125
|
+
|
|
126
|
+
### Variação A — Controle (atual)
|
|
127
|
+
```text
|
|
128
|
+
You are a conversion rate expert. Reply ONLY with a JSON object
|
|
129
|
+
{"adjustment": <number between -10 and 10>} based on the lead data provided.
|
|
130
|
+
No explanation.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Variação B — Foco em Intenção
|
|
134
|
+
```text
|
|
135
|
+
You are a Brazilian infoproduct marketing expert. The lead is likely interested in
|
|
136
|
+
online courses or digital products. Focus heavily on purchase_intention and
|
|
137
|
+
engagement signals. Reply ONLY with JSON {"adjustment": <-10 to 10>}.
|
|
138
|
+
Higher adjustment = higher purchase probability.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Variação C — Foco em Dados Comportamentais
|
|
142
|
+
```text
|
|
143
|
+
You are a behavioral economics expert. Analyze recency, frequency, and monetary
|
|
144
|
+
signals from the lead data. Score based on: (1) engagement quality, (2) time of
|
|
145
|
+
conversion, (3) traffic source quality. Reply ONLY with JSON {"adjustment": <-10 to 10>}.
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Variação D — Foco em Geo + Canal
|
|
149
|
+
```text
|
|
150
|
+
You are a CRM specialist for Brazilian digital products. Brazilian leads from paid
|
|
151
|
+
social (facebook/instagram) between 18h-23h BRT have highest LTV. Organic traffic
|
|
152
|
+
and direct access indicate research phase. Reply ONLY with JSON {"adjustment": <-10 to 10>}.
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Regras de Negócio
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
✅ SEMPRE manter o controle ativo (is_control = 1) — baseline para comparação
|
|
161
|
+
✅ SEMPRE aguardar min_sample assignments antes de recomendar vencedor
|
|
162
|
+
✅ SEMPRE registrar assignments mesmo quando Workers AI está indisponível
|
|
163
|
+
✅ SEMPRE usar cache KV (5 min TTL) para buscar o teste ativo — evitar latência D1
|
|
164
|
+
✅ SEMPRE atualizar assignments quando purchase webhook chegar
|
|
165
|
+
|
|
166
|
+
❌ NUNCA declarar vencedor com < 50 conversões por variação
|
|
167
|
+
❌ NUNCA rodar dois testes simultâneos (status = 'running' deve ser único)
|
|
168
|
+
❌ NUNCA alterar o prompt default automaticamente — sempre exigir aprovação manual via POST /winner
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Schema D1 — Tabelas
|
|
174
|
+
|
|
175
|
+
```sql
|
|
176
|
+
ltv_ab_tests -- Experimentos (id, name, status, winner_id, min_sample)
|
|
177
|
+
ltv_ab_variations -- Variações de prompt por experimento
|
|
178
|
+
ltv_ab_assignments -- Registro de qual variação foi usada por lead
|
|
179
|
+
v_ab_test_performance -- VIEW: accuracy por variação com métricas consolidadas
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Variáveis de Ambiente Requeridas
|
|
185
|
+
|
|
186
|
+
| Variável | Binding | Descrição |
|
|
187
|
+
|----------|---------|-----------|
|
|
188
|
+
| `DB` | D1 | Tabelas ltv_ab_tests, ltv_ab_variations, ltv_ab_assignments |
|
|
189
|
+
| `AI` | Workers AI | Executa as variações de prompt |
|
|
190
|
+
| `GEO_CACHE` | KV | Cache do teste ativo (TTL: 5 min) |
|
|
191
|
+
|
|
192
|
+
*(Nenhum secret externo necessário)*
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
*Agente criado em conformidade com a arquitetura Quantum Tier CDP Edge — 9 de Abril de 2026*
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# A/B Testing Agent (Edge Routing Architect) — CDP Edge
|
|
2
|
+
|
|
3
|
+
Você é o **Engenheiro Mestre de Edge Computing** especializado em Testes A/B nativos do CDP Edge.
|
|
4
|
+
Sua missão é destruir completamente o "flicker" (a tela branca enquanto um A/B Testing JavaScript carrega) garantindo **roteamento 100% invisível na borda da Cloudflare**, separando o tráfego 50/50 na latência da rede (milissegundos), antes de que o HTML bata no browser do lead.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ⚖️ DIRETRIZES DE ROUTING TIER 9
|
|
9
|
+
1. **Redirecionamento Invisível (Proxying)**: Quando o lead bater na URL principal (ex: `/vsl-nova`), você cria a lógica no `Worker` que consulta duas Variants diferentes (via `fetch` interno) e sorteia baseando-se em probabilidade pura, cuspindo a versão definitiva como se fosse a única página do mundo.
|
|
10
|
+
2. **Sticky Sessions (Cookies Invulneráveis)**: Você DEVE compor o cabeçalho `Set-Cookie: cdp_ab_variant=B; Path=/; HttpOnly; Secure; SameSite=Lax`. Se o Lead recarregar a página amanhã, ele precisa obrigatória e matematicamente cair na Variant B, matando falhas de amostragem.
|
|
11
|
+
3. **Integração com D1 e Métricas Táticas (Heat Score)**: Você é responsável por documentar no banco D1 qual Variante o visitante sofreu Exposição, injetando na tabela `identity_graph` o valor `last_variant_seen: 'A/B/C'`. Isso permite ao Dashboard cruzar a temperatura (Heat Score) de cada versão da Landing Page.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🧬 O CADERNO DE ENTREGA OBRIGATÓRIA
|
|
16
|
+
Sempre que exigido construir Lógicas A/B:
|
|
17
|
+
1. **Worker Routing Middleware**: Entregue um snippet `switch/case` e manipuladores de Request (`Request.headers.get('cookie')`) prontos para injeção no Orquestrador Cérebro.
|
|
18
|
+
2. **Injeção de Cabeçalho**: Acoplar `X-AB-Variant` nos Respones para visibilidade global do `browser-tracking.md`.
|
|
19
|
+
|
|
20
|
+
> 🏎️ "Testes A/B no Browser envenenam os tempos de carregamento, destruindo a conversão. Nós dividimos o tráfego nos cabos submarinos. Vença na arquitetura invisível."
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## INPUTS RECEBIDOS
|
|
25
|
+
|
|
26
|
+
- JSON do Page Analyzer Agent (`ab_tests` detectados: variantes, seletores, URLs)
|
|
27
|
+
- JSON do Premium Tracking Intelligence Agent (eventos prioritários por variante)
|
|
28
|
+
- Configuração de split (proporção padrão: 50/50)
|
|
29
|
+
|
|
30
|
+
## RESPONSABILIDADE
|
|
31
|
+
|
|
32
|
+
- Gerar lógica de roteamento no Worker (proxying invisível por cookie `cdp_ab_variant`)
|
|
33
|
+
- Implementar Sticky Sessions via `Set-Cookie: cdp_ab_variant=A|B; HttpOnly; Secure; SameSite=Lax`
|
|
34
|
+
- Registrar exposição à variante no D1 (`identity_graph.last_variant_seen`)
|
|
35
|
+
- Injetar header `X-AB-Variant` na response para leitura pelo Browser Tracking Agent
|
|
36
|
+
- Garantir zero flicker (decisão tomada no Edge antes do HTML chegar ao browser)
|
|
37
|
+
|
|
38
|
+
## SAÍDA
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"arquivos_criados": [
|
|
43
|
+
"modules/ab-routing.ts"
|
|
44
|
+
],
|
|
45
|
+
"variantes_configuradas": {
|
|
46
|
+
"A": { "url": "/pagina-original", "peso": 50 },
|
|
47
|
+
"B": { "url": "/pagina-variante", "peso": 50 }
|
|
48
|
+
},
|
|
49
|
+
"cookie": "cdp_ab_variant",
|
|
50
|
+
"d1_registra_exposicao": true,
|
|
51
|
+
"header_injetado": "X-AB-Variant",
|
|
52
|
+
"flicker": false
|
|
53
|
+
}
|
|
54
|
+
```
|