cdp-edge 1.13.0 → 1.14.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.
@@ -0,0 +1,444 @@
1
+ # API de Segmentação Dinâmica ML — Documentação Completa
2
+
3
+ ## Visão Geral
4
+
5
+ API REST para segmentação dinâmica de leads via Machine Learning (K-means, DBSCAN, Hierarchical).
6
+
7
+ ---
8
+
9
+ ## Endpoints Disponíveis
10
+
11
+ | Método | Endpoint | Descrição |
12
+ |---|---|---|
13
+ | **POST** | `/api/segmentation/cluster` | Executar clustering K-means |
14
+ | **GET** | `/api/segmentation/list` | Listar todos os segmentos ativos |
15
+ | **GET** | `/api/segmentation/outliers` | Listar leads anômalos (outliers) |
16
+ | **PUT** | `/api/segmentation/update` | Atualizar recomendações de segmento |
17
+
18
+ ---
19
+
20
+ ## 1. POST /api/segmentation/cluster — Executar Clustering
21
+
22
+ Executa clustering K-means via Workers AI para criar segmentos de leads.
23
+
24
+ ### Request Body
25
+
26
+ ```json
27
+ {
28
+ "algorithm": "kmeans", // Opcional: 'kmeans', 'dbscan', 'hierarchical'
29
+ "n_clusters": 5, // Opcional: 3-10 (padrão: 5)
30
+ "vertical": "curso-online", // Opcional: vertical do cliente
31
+ "force": false // Opcional: forçar novo clustering
32
+ }
33
+ ```
34
+
35
+ ### Response
36
+
37
+ ```json
38
+ {
39
+ "success": true,
40
+ "cluster_id": 123,
41
+ "clustering_algorithm": "kmeans",
42
+ "n_clusters": 5,
43
+ "client_vertical": "curso-online",
44
+ "duration_ms": 12543,
45
+ "clusters": [
46
+ {
47
+ "cluster_id": 0,
48
+ "name": "Segmento 0 - Alto Valor + Alto Engajamento (SP)",
49
+ "size": 95,
50
+ "percentage": 0.25,
51
+ "characteristics": {
52
+ "avg_ltv": 497.50,
53
+ "avg_ltv_class": "High",
54
+ "avg_behavior_score": 75.3,
55
+ "avg_engagement_score": 82.1,
56
+ "avg_intention_level": 85.0,
57
+ "dominant_countries": ["BR", "AR"],
58
+ "dominant_states": ["SP", "RJ"],
59
+ "dominant_utm_sources": ["facebook", "google"],
60
+ "top_features": ["ltv", "behavior_score", "engagement_score"]
61
+ },
62
+ "centroid": {
63
+ "ltv_class": 0.75,
64
+ "behavior_score": 0.80,
65
+ "engagement_score": 0.85
66
+ },
67
+ "sample_leads": ["lead_451", "lead_892", "lead_1034"]
68
+ }
69
+ ],
70
+ "silhouette_scores": {
71
+ "overall": 0.62,
72
+ "by_cluster": [0.71, 0.58, 0.65, 0.60, 0.55]
73
+ },
74
+ "convergence": {
75
+ "iterations": 47,
76
+ "final_inertia": 1523.45
77
+ },
78
+ "generated_at": "2026-04-09T18:45:32.000Z"
79
+ }
80
+ ```
81
+
82
+ ### Exemplo de Uso (cURL)
83
+
84
+ ```bash
85
+ curl -X POST "https://seudominio.com/api/segmentation/cluster" \
86
+ -H "Content-Type: application/json" \
87
+ -d '{
88
+ "algorithm": "kmeans",
89
+ "n_clusters": 5,
90
+ "vertical": "curso-online"
91
+ }'
92
+ ```
93
+
94
+ ---
95
+
96
+ ## 2. GET /api/segmentation/list — Listar Segmentos
97
+
98
+ Lista todos os segmentos ativos com estatísticas detalhadas.
99
+
100
+ ### Query Parameters
101
+
102
+ | Parâmetro | Tipo | Descrição |
103
+ |---|---|---|
104
+ | `algorithm` | string | Filtro por algoritmo: `kmeans`, `dbscan`, `hierarchical` |
105
+ | `active` | boolean | Filtro por status: `1` (ativo) ou `0` (arquivado) |
106
+ | `limit` | number | Máximo de resultados (padrão: 10) |
107
+
108
+ ### Exemplo de Request
109
+
110
+ ```bash
111
+ curl "https://seudominio.com/api/segmentation/list?algorithm=kmeans&active=1&limit=10"
112
+ ```
113
+
114
+ ### Response
115
+
116
+ ```json
117
+ {
118
+ "success": true,
119
+ "count": 5,
120
+ "segments": [
121
+ {
122
+ "id": 45,
123
+ "cluster_id": 123,
124
+ "cluster_name": "Segmento 0 - Alto Valor + Alto Engajamento (SP)",
125
+ "clustering_algorithm": "kmeans",
126
+ "client_vertical": "curso-online",
127
+ "size": 95,
128
+ "percentage": 0.25,
129
+ "avg_ltv": 497.50,
130
+ "avg_ltv_class": "High",
131
+ "avg_behavior_score": 75.3,
132
+ "avg_engagement_score": 82.1,
133
+ "avg_intention_level": 85.0,
134
+ "dominant_countries": ["BR", "AR"],
135
+ "dominant_states": ["SP", "RJ"],
136
+ "dominant_features": ["ltv", "behavior_score", "engagement_score"],
137
+ "silhouette_score": 0.71,
138
+ "action_recommendations": [
139
+ "Priorizar remarketing em 24h",
140
+ "Criar lookalike audience de alto valor"
141
+ ],
142
+ "bid_recommendations": [
143
+ {"adset_id": "456", "recommended_bid": "R$ 18.50", "confidence": 0.85}
144
+ ],
145
+ "campaign_recommendations": [
146
+ {"creative": "VSL A", "audience": "Segmento 0"},
147
+ {"creative": "VSL B", "audience": "Segmento 0"}
148
+ ],
149
+ "is_active": true,
150
+ "created_at": "2026-04-09T18:45:32.000Z",
151
+ "updated_at": "2026-04-09T18:45:32.000Z"
152
+ }
153
+ ]
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ## 3. GET /api/segmentation/outliers — Listar Anomalias
160
+
161
+ Lista leads considerados outliers/anomalias (detecção DBSCAN).
162
+
163
+ ### Query Parameters
164
+
165
+ | Parâmetro | Tipo | Descrição |
166
+ |---|---|---|
167
+ | `confidence` | number | Threshold de confiança (padrão: 0.5) |
168
+ | `risk` | string | Filtro por nível: `high`, `medium`, `low` |
169
+ | `limit` | number | Máximo de resultados (padrão: 50) |
170
+
171
+ ### Exemplo de Request
172
+
173
+ ```bash
174
+ curl "https://seudominio.com/api/segmentation/outliers?confidence=0.3&risk=high&limit=20"
175
+ ```
176
+
177
+ ### Response
178
+
179
+ ```json
180
+ {
181
+ "success": true,
182
+ "outliers": [
183
+ {
184
+ "lead_id": "lead_451",
185
+ "email": "suspicious@example.com",
186
+ "first_name": "João",
187
+ "last_name": "Silva",
188
+ "ltv_class": "High",
189
+ "behavior_score": 98,
190
+ "engagement_score": 85,
191
+ "intention_level": 90,
192
+ "days_since_lead": 0,
193
+ "cluster_id": null,
194
+ "cluster_name": "Outlier",
195
+ "confidence": 0.12,
196
+ "distance_to_centroid": 0.89,
197
+ "is_outlier": true,
198
+ "outlier_reason": "behavior_score too high (> 95), instant lead, suspicious",
199
+ "risk_level": "high",
200
+ "risk_score": 88,
201
+ "should_block": true,
202
+ "actionable_reasons": [
203
+ "Comportamento extremamente ativo (possível bot)",
204
+ "Lead instantâneo com engajamento muito alto (suspicious)"
205
+ ],
206
+ "assigned_at": "2026-04-09T18:47:15.000Z"
207
+ }
208
+ ],
209
+ "statistics": {
210
+ "total_outliers": 20,
211
+ "by_risk_level": {
212
+ "high": 15,
213
+ "medium": 3,
214
+ "low": 2
215
+ },
216
+ "by_reason": {
217
+ "behavior_score too high (> 95)": 12,
218
+ "instant lead": 8,
219
+ "unusual geo": 0
220
+ },
221
+ "avg_confidence": 0.18
222
+ },
223
+ "generated_at": "2026-04-09T18:47:15.000Z"
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## 4. PUT /api/segmentation/update — Atualizar Segmento
230
+
231
+ Atualiza recomendações de ações, bids e campanhas de um segmento existente.
232
+
233
+ ### Request Body
234
+
235
+ ```json
236
+ {
237
+ "cluster_id": 45,
238
+ "action_recommendations": [
239
+ "Priorizar remarketing em 24h",
240
+ "Criar lookalike audience de alto valor",
241
+ "Enrichir creative com copy específico"
242
+ ],
243
+ "bid_recommendations": [
244
+ {"adset_id": "456", "recommended_bid": "R$ 20.00"},
245
+ {"adset_id": "789", "recommended_bid": "R$ 18.50"}
246
+ ],
247
+ "campaign_recommendations": [
248
+ {"creative": "VSL Segmentado", "audience": "Segmento 0"}
249
+ ],
250
+ "is_active": true
251
+ }
252
+ ```
253
+
254
+ ### Response
255
+
256
+ ```json
257
+ {
258
+ "success": true,
259
+ "cluster_id": 45,
260
+ "cluster_name": "Segmento 0 - Alto Valor + Alto Engajamento (SP)",
261
+ "updates_applied": {
262
+ "action_recommendations": 3,
263
+ "bid_recommendations": 2,
264
+ "campaign_recommendations": 1,
265
+ "is_active": true
266
+ },
267
+ "updated_at": "2026-04-09T18:50:23.000Z"
268
+ }
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Estrutura das Tabelas D1
274
+
275
+ ### ml_segments — Metadados dos Segmentos
276
+
277
+ ```sql
278
+ CREATE TABLE ml_segments (
279
+ id INTEGER PRIMARY KEY,
280
+ cluster_id INTEGER NOT NULL,
281
+ cluster_name TEXT NOT NULL,
282
+ clustering_algorithm TEXT NOT NULL, -- 'kmeans', 'dbscan', 'hierarchical'
283
+ client_vertical TEXT,
284
+ created_at TEXT,
285
+ updated_at TEXT,
286
+
287
+ -- Estatísticas
288
+ size INTEGER, -- Nº de leads
289
+ percentage REAL, -- % do total
290
+
291
+ -- Centróides (médias)
292
+ avg_ltv REAL,
293
+ avg_ltv_class REAL,
294
+ avg_behavior_score REAL,
295
+ avg_engagement_score REAL,
296
+ avg_intention_level REAL,
297
+
298
+ -- Características dominantes
299
+ dominant_countries TEXT, -- JSON: ["BR", "US"]
300
+ dominant_states TEXT, -- JSON: ["SP", "RJ"]
301
+ dominant_cities TEXT, -- JSON: ["São Paulo", "Rio"]
302
+ dominant_timezones TEXT, -- JSON: ["America/Sao_Paulo"]
303
+ dominant_utm_sources TEXT, -- JSON: ["facebook", "google"]
304
+ dominant_features TEXT, -- JSON: ["ltv", "behavior_score"]
305
+
306
+ -- Métricas de qualidade
307
+ silhouette_score REAL, -- 0-1 (quanto maior, melhor)
308
+ cohesion REAL, -- Similaridade intra-cluster
309
+ separation REAL, -- Distância inter-cluster
310
+ inertia REAL, -- Soma dos quadrados
311
+
312
+ -- Recomendações automáticas
313
+ action_recommendations TEXT, -- JSON array
314
+ bid_recommendations TEXT, -- JSON array
315
+ campaign_recommendations TEXT, -- JSON array
316
+
317
+ -- Metadados
318
+ is_active INTEGER DEFAULT 1,
319
+ min_data_points INTEGER,
320
+ epsilon REAL, -- DBSCAN
321
+ min_samples INTEGER, -- DBSCAN
322
+ max_depth INTEGER -- Hierarchical
323
+ );
324
+ ```
325
+
326
+ ### ml_segment_members — Associação Lead ↔ Segmento
327
+
328
+ ```sql
329
+ CREATE TABLE ml_segment_members (
330
+ id INTEGER PRIMARY KEY,
331
+ lead_id TEXT NOT NULL,
332
+ cluster_id INTEGER NOT NULL,
333
+ clustering_algorithm TEXT NOT NULL,
334
+ confidence REAL NOT NULL, -- 0-1 (quão perto do centroide)
335
+ distance_to_centroid REAL,
336
+ updated_at TEXT,
337
+ assigned_at TEXT,
338
+ is_outlier INTEGER DEFAULT 0,
339
+ outlier_reason TEXT,
340
+
341
+ -- Estado do lead no momento da atribuição
342
+ lead_ltv REAL,
343
+ lead_ltv_class REAL,
344
+ lead_behavior_score REAL,
345
+ lead_engagement_score REAL,
346
+ lead_intention_level REAL,
347
+
348
+ -- Características
349
+ lead_country TEXT,
350
+ lead_state TEXT,
351
+ lead_city TEXT,
352
+
353
+ UNIQUE(lead_id, cluster_id, clustering_algorithm)
354
+ );
355
+ ```
356
+
357
+ ---
358
+
359
+ ## Integração com Outros Agentes
360
+
361
+ ### Com LTV Predictor Agent
362
+
363
+ ```typescript
364
+ // Enricher predição LTV com segment_id
365
+ const enrichedLTV = {
366
+ original_prediction: 497.50,
367
+ segment_id: 123,
368
+ segment_name: "Alto Valor + Alto Engajamento (SP)",
369
+ adjusted_prediction: 612.30, // +23% baseado no segmento
370
+ confidence: 0.85
371
+ };
372
+ ```
373
+
374
+ ### Com Dashboard Agent
375
+
376
+ ```typescript
377
+ // Visualização de segmentos em gráficos
378
+ const segmentChartData = {
379
+ labels: ["Segmento 0", "Segmento 1", "Segmento 2"],
380
+ data: [95, 150, 120, 85, 50],
381
+ colors: ["#22c55e", "#3b82f6", "#1e40af", "#06b6d4", "#f59e0b"]
382
+ };
383
+ ```
384
+
385
+ ### Com Meta Agent
386
+
387
+ ```typescript
388
+ // Criar campanhas segmentadas por segmento
389
+ const segmentedCampaigns = [
390
+ {
391
+ adset_name: "Segmento 0 - Alto Valor",
392
+ audience: ml_segment_id_123,
393
+ creative: "VSL Personalizado Segmento 0",
394
+ bid_strategy: "high_bid"
395
+ }
396
+ ];
397
+ ```
398
+
399
+ ---
400
+
401
+ ## Troubleshooting Comum
402
+
403
+ ### Erro: "Dados insuficientes para clustering"
404
+
405
+ **Causa:** Menos de 100 leads nos últimos 6 meses
406
+
407
+ **Solução:**
408
+ - Aguardar mais dados acumularem
409
+ - Aumentar `max_data_age_months` para 12
410
+ - Usar `force=true` para clustering com menos dados
411
+
412
+ ### Erro: "Silhouette Score < 0.3"
413
+
414
+ **Causa:** Clusters não são bem separados
415
+
416
+ **Solução:**
417
+ - Aumentar `n_clusters` para 7-10
418
+ - Reduzir dimensionalidade (usar features mais importantes)
419
+ - Usar algoritmo `hierarchical` em vez de `kmeans`
420
+
421
+ ### Erro: "Workers AI timeout"
422
+
423
+ **Causa:** Prompt muito longo ou muitos dados
424
+
425
+ **Solução:**
426
+ - Reduzir leads por batch (max 500)
427
+ - Simplificar prompt (menos instruções)
428
+ - Aumentar timeout no wrangler.toml
429
+
430
+ ---
431
+
432
+ ## Roadmap Futuro
433
+
434
+ - [ ] DBSCAN Clustering completo (outliers avançado)
435
+ - [ ] Hierarchical Clustering (drill-down de clusters)
436
+ - [ ] Auto-feature selection (identificar features mais importantes)
437
+ - [ ] Clustering temporal (leads mudam de segmento ao longo do tempo)
438
+ - [ ] A/B testing automático de segmentos
439
+ - [ ] Dashboard visual de segmentos em gráficos interativos
440
+
441
+ ---
442
+
443
+ *API de Segmentação Dinâmica ML v1.0 — CDP Edge*
444
+ *Data: 9 de Abril de 2026*
@@ -0,0 +1,97 @@
1
+ -- Schema A/B Testing de Prompts LTV — CDP Edge Quantum Tier
2
+ -- Versão: 1.0
3
+ -- Data: 9 de Abril de 2026
4
+ -- Fase 3 Enterprise-Level
5
+
6
+ -- TABELA: Experimentos A/B
7
+ CREATE TABLE IF NOT EXISTS ltv_ab_tests (
8
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
9
+ name TEXT NOT NULL,
10
+ description TEXT,
11
+ status TEXT NOT NULL DEFAULT 'draft', -- 'draft', 'running', 'paused', 'completed'
12
+ winner_id INTEGER, -- FK para ltv_ab_variations.id
13
+ started_at TEXT,
14
+ completed_at TEXT,
15
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
16
+ min_sample INTEGER NOT NULL DEFAULT 100, -- Mínimo de assignments para declarar vencedor
17
+ confidence_threshold REAL NOT NULL DEFAULT 0.90 -- Nível de confiança estatística (90%)
18
+ );
19
+
20
+ -- TABELA: Variações de Prompt por Experimento
21
+ CREATE TABLE IF NOT EXISTS ltv_ab_variations (
22
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
23
+ test_id INTEGER NOT NULL REFERENCES ltv_ab_tests(id),
24
+ name TEXT NOT NULL, -- Ex: 'Variação A — Foco em Engajamento'
25
+ system_prompt TEXT NOT NULL, -- O prompt system enviado ao Workers AI
26
+ weight REAL NOT NULL DEFAULT 0.5, -- Peso de distribuição (0-1, soma deve = 1)
27
+ is_control INTEGER NOT NULL DEFAULT 0, -- 1 = variação controle (baseline)
28
+
29
+ -- Métricas acumuladas
30
+ total_assigned INTEGER NOT NULL DEFAULT 0,
31
+ total_purchases INTEGER NOT NULL DEFAULT 0,
32
+ sum_predicted_ltv REAL NOT NULL DEFAULT 0,
33
+ sum_real_revenue REAL NOT NULL DEFAULT 0,
34
+
35
+ -- Métricas calculadas (atualizadas por trigger ou batch)
36
+ avg_predicted_ltv REAL,
37
+ avg_real_revenue REAL,
38
+ conversion_rate REAL,
39
+ accuracy_score REAL, -- Quão próximo do valor real (1 - |predicted-real|/real)
40
+
41
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
42
+ );
43
+
44
+ -- TABELA: Assignments — qual variação foi usada para qual lead
45
+ CREATE TABLE IF NOT EXISTS ltv_ab_assignments (
46
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
47
+ test_id INTEGER NOT NULL REFERENCES ltv_ab_tests(id),
48
+ variation_id INTEGER NOT NULL REFERENCES ltv_ab_variations(id),
49
+ user_id TEXT NOT NULL,
50
+ email_hash TEXT, -- SHA256 do email (indexação sem PII)
51
+ predicted_ltv REAL,
52
+ predicted_class TEXT,
53
+ assigned_at TEXT NOT NULL DEFAULT (datetime('now')),
54
+
55
+ -- Preenchido quando purchase chega via webhook
56
+ converted INTEGER NOT NULL DEFAULT 0,
57
+ real_revenue REAL,
58
+ converted_at TEXT
59
+ );
60
+
61
+ -- Índices
62
+ CREATE INDEX IF NOT EXISTS idx_ab_tests_status ON ltv_ab_tests(status);
63
+ CREATE INDEX IF NOT EXISTS idx_ab_variations_test ON ltv_ab_variations(test_id);
64
+ CREATE INDEX IF NOT EXISTS idx_ab_assignments_test ON ltv_ab_assignments(test_id);
65
+ CREATE INDEX IF NOT EXISTS idx_ab_assignments_user ON ltv_ab_assignments(user_id);
66
+ CREATE INDEX IF NOT EXISTS idx_ab_assignments_email ON ltv_ab_assignments(email_hash);
67
+ CREATE INDEX IF NOT EXISTS idx_ab_assignments_conv ON ltv_ab_assignments(converted);
68
+
69
+ -- VIEW: Resumo de performance por variação
70
+ CREATE VIEW IF NOT EXISTS v_ab_test_performance AS
71
+ SELECT
72
+ t.id AS test_id,
73
+ t.name AS test_name,
74
+ t.status,
75
+ v.id AS variation_id,
76
+ v.name AS variation_name,
77
+ v.is_control,
78
+ v.weight,
79
+ v.total_assigned,
80
+ v.total_purchases,
81
+ CASE WHEN v.total_assigned > 0
82
+ THEN ROUND(CAST(v.total_purchases AS REAL) / v.total_assigned * 100, 2)
83
+ ELSE 0
84
+ END AS conversion_rate_pct,
85
+ CASE WHEN v.total_assigned > 0
86
+ THEN ROUND(v.sum_predicted_ltv / v.total_assigned, 2)
87
+ ELSE 0
88
+ END AS avg_predicted_ltv,
89
+ CASE WHEN v.total_purchases > 0
90
+ THEN ROUND(v.sum_real_revenue / v.total_purchases, 2)
91
+ ELSE 0
92
+ END AS avg_real_revenue,
93
+ v.accuracy_score,
94
+ t.winner_id = v.id AS is_winner
95
+ FROM ltv_ab_tests t
96
+ JOIN ltv_ab_variations v ON v.test_id = t.id
97
+ ORDER BY t.id, v.id;
@@ -0,0 +1,86 @@
1
+ -- Schema de Recomendações de Bids Automáticas — CDP Edge Quantum Tier
2
+ -- Versão: 1.0
3
+ -- Data: 9 de Abril de 2026
4
+ -- Complementa: schema-segmentation.sql
5
+
6
+ -- TABELA PRINCIPAL: Recomendações de Bids
7
+ CREATE TABLE IF NOT EXISTS bid_recommendations (
8
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
9
+ generated_at TEXT NOT NULL DEFAULT (datetime('now')),
10
+ vertical TEXT NOT NULL, -- 'infoproduto', 'ecommerce', 'saas'
11
+ platform TEXT NOT NULL, -- 'meta', 'google', 'tiktok', 'all'
12
+ period_days INTEGER NOT NULL DEFAULT 30, -- Janela de análise
13
+ target_roi REAL NOT NULL DEFAULT 3.5, -- ROI alvo
14
+
15
+ -- Segmento ML de origem (FK para ml_segments)
16
+ segment_id INTEGER,
17
+ segment_name TEXT,
18
+
19
+ -- Dados analisados
20
+ leads_analyzed INTEGER NOT NULL DEFAULT 0,
21
+ conversions_found INTEGER NOT NULL DEFAULT 0,
22
+ avg_ltv REAL, -- LTV médio do segmento
23
+ cpa_target REAL, -- CPA alvo calculado: avg_ltv / target_roi
24
+
25
+ -- Output: O Bid em si
26
+ recommended_bid REAL, -- Bid recomendado em BRL
27
+ bid_currency TEXT NOT NULL DEFAULT 'BRL',
28
+ confidence REAL NOT NULL DEFAULT 0, -- 0-1 (base: conversions / 100)
29
+ expected_roi REAL, -- ROI esperado com este bid
30
+
31
+ -- Rastreabilidade
32
+ reasoning TEXT, -- Explicação detalhada da lógica
33
+ ai_used INTEGER DEFAULT 0, -- 1 = Workers AI usado
34
+ alert_message TEXT, -- Ex: "Dados insuficientes (< 30 conversões)"
35
+
36
+ -- Fatores internos de cálculo (para auditoria)
37
+ platform_factor REAL, -- 0.75–0.90 por plataforma
38
+ confidence_adjustment REAL, -- 0.70–1.00 por nível de confiança
39
+ segment_multiplier REAL, -- 0.60–1.40 por tipo de segmento
40
+
41
+ -- Ciclo de vida
42
+ is_active INTEGER NOT NULL DEFAULT 1,
43
+ applied_at TEXT, -- Quando o usuário aplicou o bid
44
+ applied_campaign TEXT, -- ID da campanha onde foi aplicado
45
+ applied_result TEXT -- JSON: {clicks, conversions, real_roi}
46
+ );
47
+
48
+ -- Índices
49
+ CREATE INDEX IF NOT EXISTS idx_bid_recs_vertical ON bid_recommendations(vertical);
50
+ CREATE INDEX IF NOT EXISTS idx_bid_recs_platform ON bid_recommendations(platform);
51
+ CREATE INDEX IF NOT EXISTS idx_bid_recs_generated ON bid_recommendations(generated_at);
52
+ CREATE INDEX IF NOT EXISTS idx_bid_recs_active ON bid_recommendations(is_active);
53
+ CREATE INDEX IF NOT EXISTS idx_bid_recs_segment ON bid_recommendations(segment_id);
54
+ CREATE INDEX IF NOT EXISTS idx_bid_recs_confidence ON bid_recommendations(confidence);
55
+
56
+ -- VIEW: Recomendações Ativas (com dados dos segmentos)
57
+ CREATE VIEW IF NOT EXISTS v_active_bid_recommendations AS
58
+ SELECT
59
+ br.id,
60
+ br.generated_at,
61
+ br.vertical,
62
+ br.platform,
63
+ br.period_days,
64
+ br.target_roi,
65
+ br.segment_name,
66
+ br.leads_analyzed,
67
+ br.conversions_found,
68
+ br.avg_ltv,
69
+ br.cpa_target,
70
+ br.recommended_bid,
71
+ br.bid_currency,
72
+ br.confidence,
73
+ br.expected_roi,
74
+ br.reasoning,
75
+ br.alert_message,
76
+ br.ai_used,
77
+ -- Dados do segmento ML relacionado
78
+ ms.cluster_name AS ml_cluster_name,
79
+ ms.avg_behavior_score,
80
+ ms.avg_engagement_score,
81
+ ms.silhouette_score,
82
+ ms.size AS segment_size
83
+ FROM bid_recommendations br
84
+ LEFT JOIN ml_segments ms ON br.segment_id = ms.id
85
+ WHERE br.is_active = 1
86
+ ORDER BY br.generated_at DESC;