← story.propek
STORY 20.3
20.3
PENDING
ACCEPTANCE CRITERIA (38/38)
Migration SQL cria a tabela com schema exato definido na arquitetura
Campos: `id` (BIGINT GENERATED ALWAYS), `event_date` (DATE), `campaign_ref` (TEXT), `ad_ref` (TEXT), `event_type` (TEXT — enum: `conversation_started`, `lead_qualified`, `handoff`, `deal_created`, `order_confirmed`), `count` (INTEGER DEFAULT 1), `metadata` (JSONB DEFAULT `{}`), `synced_at` (TIMESTAMPTZ DEFAULT NOW())
Constraint UNIQUE em `(event_date, campaign_ref, ad_ref, event_type)` para idempotência
Índices em `(event_date DESC)`, `(campaign_ref)`, `(event_type)`, `(event_date, campaign_ref)`
RLS habilitado: `service_role` tem acesso total; `authenticated` pode SELECT; `anon` sem acesso
Agente: @data-engineer
Script criado em `squads/traffic-ads/scripts/sync-traffic-events.js`
Conecta ao PostgreSQL local (`propek_bot`) em modo read-only (sem INSERT/UPDATE/DELETE)
Executa 5 queries de agregação (uma por `event_type`) para a data corrente
Faz upsert no Supabase (tabela `traffic_events`) via REST API (stdlib https, ZERO deps externas)
Zero PII no payload — apenas contadores agrupados por `campaign_ref + event_date + event_type`
Suporta argumento de data: `node sync-traffic-events.js --date 2026-04-01` (default: ontem)
Log local em `/var/log/sync-traffic-events.log` com resultado de cada run (linhas inseridas/atualizadas)
Cron entries documentadas em `squads/traffic-ads/docs/vps-cron.md` (08:00 e 20:00 BRT = 11:00 e 23:00 UTC)
Agente: @dev
Nenhum campo com dado pessoal (nome, telefone, CPF, email) é lido pelas queries de agregação
Todas as queries usam `COUNT(*)` — sem SELECT de campos de identificação
`metadata` só contém: `{avg_deal_value: N}` para `order_confirmed` — valor médio sem rastreabilidade
@cyber-chief confirma LGPD compliance antes do Task 5
Nova função `loadConversionData(date)` lê `traffic_events` do Supabase para a data
Nova função `calcNCAC(spend, ordersCount)` retorna nCAC ou `null` se ordersCount = 0
Regras de decisão implementadas usando constante `NCAC_RULES`:
Relatório diário inclui campo `nCAC Real` por campanha (ex: `3 pedidos | nCAC R$18,00`)
Se sem dados de conversão: campo exibe `"sem dados de conversão"` (sem erro)
Agente: @dev
Busca `traffic_events` dos últimos 7 dias por campanha via Supabase
Monta bloco de texto "Funil de Conversão por Campanha" no prompt para a IA
Bloco inclui: conversas iniciadas, leads qualificados, handoffs, deals criados, pedidos confirmados, nCAC real, CPC WhatsApp, taxa de conversão funil
IA recebe contexto suficiente para identificar qual campanha traz lead bom vs ruim
Agente: @dev
weekly-ai-analysis.js inclui instrução explícita no prompt para comparar campanhas por `order_confirmed / conversation_started` (taxa de conversão funil completo)
Relatório semanal gerado inclui seção "Qualidade de Lead por Campanha"
Agente: @dev
Zero PII no Supabase confirmado (nenhum campo de identificação pessoal na tabela `traffic_events`)
Credenciais PostgreSQL VPS (`DB_*`) ficam APENAS no `.env` do VPS — nunca no repositório
`SUPABASE_SERVICE_KEY` no VPS é chave diferente das usadas pelos scripts de tráfego no repo
RLS correto valida que anon não acessa `traffic_events`
Emitir gate PASS/FAIL antes de @qa
TIMELINE
31/03/2026
feat: Epic 20 — Traffic Manager Autonomo, 7 stories, 393+ testes, 4 security gates [Epic 20] [Story 6.1-sales-intelligence-bot]
7a8b92d