Radar¶
O Radar de Oportunidades é um scorer de oportunidades multivariado, sincronizado com a nuvem, para produtos descobertos em um marketplace (ClickBank Marketplace). Ingere snapshots de marketplace continuamente e pontua cada produto num único Opportunity Score entre 0 e 100, para que operadores ranqueiem o que vale receber tráfego.
Não existe API de afiliado para listagem automática. O ClickBank não expõe
GET /products/listpara afiliados —products-v2.jsoné seller-only. O feed automatizado server-side (online_feedviaMARKETPLACE_FEED_URL) é um stub que registraskipped_no_sourceaté que o ClickBank exponha arquivo autenticado. O caminho oficial para inteligência real é o agente de captura no servidor do operador (Chrome logado, diário, ~1,2k ofertas —docs/operations/capture-agent-linux.md), com o browser scraper assistido e o import CSV/JSON manual como alternativas. Verdocs/integrations/clickbank.md§ Fontes (verificado 2026-08-20/23).
O que faz¶
- Cloud sync — sincroniza o marketplace online em background, mantendo o radar sempre atualizado sem refresh manual.
- Opportunity Score multivariado — combina vários sinais num único score 0–100:
- Gravity — o indicador de demanda do marketplace.
- Payout inicial — quanto se pode ganhar por conversão.
- Quality tier — classificação de confiança do produto pela plataforma.
- Marcos de payout — elegibilidade e progressão em limiares de payout.
- Gravity sweet spot — produtos são destacados quando a gravity cai na faixa 20–180, equilibrando tração e administrabilidade.
Fórmula do Opportunity Score (v3, determinística)¶
radar-opportunity-v3.0.0 (packages/integrations/src/clickbank/opportunity-score.ts).
A IA nunca calcula este score; tudo é função pura das evidências:
| Componente | Pontos | Fontes (sem dupla contagem) |
|---|---|---|
| Economia | 0–22 | Payout primário = inicial (ou médio quando inicial ausente); payout médio só adiciona bônus fixo de upside (+2) quando corrobora valor superior |
| Recorrência/rebill | 0–5 | recurring_payout > 0 |
| Gravity fit | 0–15 | Bandas: sweet_spot 20–180 → 15; competitive 181–350 → 9; developing 10–19 → 7; unvalidated 1–9 → 2; hipercompetitiva >350 → 3; gravity 0/ausente → 0 (GRAVITY_ZERO_NO_EVIDENCE) |
| Qualidade do funil (+JV tools) | 0–15 | vsl/tsl/checkout_direct/hybrid + bônus por affiliate tools |
| Adequação ao canal | 0–15 | traffic_fit weak/moderate/strong |
| Potencial criativo | 0–10 | creative_potential |
| Compliance | −10 a 10 | LOW 10 · MEDIUM 5 · HIGH/UNKNOWN 0 · VERY_HIGH −10 |
| Tendência | 0–8 | up/stable/down |
| Busca Tier-1 | 0–7 | tier1_search_share |
score, completeness e confidence são conceitos separados: completude =
evidências conhecidas ÷ 14; confiança = peso ponderado ÷ 123. Dados ausentes reduzem
completude/confiança — nunca viram zero saudável. Cada score carrega
reason codes determinísticos (ex.: INITIAL_PAYOUT_HIGH,
GRAVITY_SWEET_SPOT, AVG_PAYOUT_UPSIDE_BONUS) exibidos na linha expandida do Radar.
Canal recomendado (reason codes)¶
classifyRecommendedChannel é uma regra ordenada e pura sobre
GOOGLE_SEARCH · META · YOUTUBE · NATIVE:
- Compliance HIGH/VERY_HIGH → NATIVE (
CHANNEL_NATIVE_COMPLIANCE_RISK); - Funil VSL/TSL com payout primário ≥ 40 → YOUTUBE;
- Checkout direto com evidência de intenção de busca → GOOGLE_SEARCH fundo de funil;
- Evidência de intenção de busca sem funil de vídeo → GOOGLE_SEARCH;
- Potencial criativo forte → META;
- Default conservador → META.
O canal fica persistido em score_breakdown.recommendedChannel com os reason codes em
channelReasonCodes. Compliance é detectado deterministicamente
(detectComplianceRisk: categoria/subcategoria + termos sensíveis no nome — termos
elevam um nível, nunca reduzem).
KPIs de resumo (determinísticos)¶
| KPI | Definição |
|---|---|
| Produtos no Radar | Total de snapshots trackeados no workspace. |
| Média Opportunity Score | Média dos opportunity_score, arredondada a inteiro, /100. |
| No Sweet Spot (20-180) | Contagem de snapshots com 20 ≤ gravity ≤ 180. |
| Maior Payout Inicial | Máximo dos initial_payout (USD). |
Nickname ClickBank & HopLink¶
O HopLink de afiliado é reconstruído deterministicamente a partir do par
(nickname do workspace, vendor da oportunidade) — nunca reaproveitado de URLs
importadas. O nickname fica em bv_affiliate_network_settings
(rede clickbank, 5–10 caracteres alfanuméricos) e pode ser configurado em:
- Conexões (primeiro item do checklist, card "Redes de Afiliados");
- Radar — o chip de status no topo mostra
Afiliado ClickBank: "nick"ou abre o modal rápido ao clicar. Clicar em Copiar HopLink sem nickname configurado abre o mesmo modal e, após salvar, copia o link imediatamente.
Layout da página Ofertas (Radar)¶
A página (menu Ofertas) prioriza escolher e lançar:
- Header compacto + KPIs;
- Status do agente de captura (último sinal, completa/parcial, nº de ofertas, ou a ação necessária — ex.: "Sessão do ClickBank expirou");
- Banner da última sincronização: ignora runs
skipped_no_source, marca capturas parciais e mostra erros de leitura e linhas inválidas (nunca some com dados em silêncio); - Tabela com filtros e paginação. Primeira ação de cada linha: Lançar (ou Continuar quando já existe uma preparação aberta para a oferta); Copiar HopLink e Espionar ficam ao lado. A linha expandida (Card de Inteligência) tem o mesmo botão único;
- Abaixo da tabela, recolhidos: Histórico de capturas e Motor de Decisão (SHADOW).
A leitura pagina em lotes de 1.000 (.range(), ordem opportunity_score desc,
id asc) — o catálogo inteiro aparece, sem o corte de 1.000 linhas do PostgREST
(apps/web/src/lib/radar/load-radar-data.ts).
Captura do Marketplace¶
Caminhos de entrada¶
| Caminho | Rota | Autenticação |
|---|---|---|
| Agente diário (servidor Linux/Mac) | POST /api/agent/capture/import (+ /report, /ping) |
token bvcap_… do agente (Conexões) |
| Agente antigo | POST /api/cron/marketplace-capture-import |
CRON_SECRET (só com um workspace) |
| Upload pelo navegador (dialogs de captura/import) | POST /api/radar/capture-import |
sessão do operador (sem o limite de 1 MB de Server Action) |
Todos usam o mesmo handler (lib/capture-agent/import-handler.ts): recalcula o
hash canônico, aplica a política de parcial (aceita com ≥ 100 itens e ≥ 50%
da última completa; upload manual sempre aceita), grava o run e registra toda
recusa como run failed com motivo (que dispara o aviso no Telegram).
Modos do dialog¶
O dialog "Capturar do Marketplace" oferece dois modos (repassados ao driver
via bridge POST /start {mode,pages} e injetados como window.__bvConfig):
| Modo | Comportamento |
|---|---|
| Catálogo completo | Varre todas as páginas (~1.250 ofertas) + passada por categorias para enriquecimento. Recomendado 1×/dia. |
Top oportunidades (top) |
Só as primeiras N páginas do ranking (1/2/4/10 ≈ 50–500 itens), sem passada por categorias. Sincronização ultrarrápida. |
Checkbox adicional client-side: importar somente Sweet Spot (gravidade 20–180) — filtro determinístico aplicado antes do server action.
Captura resiliente (Fase 1)¶
- Normalização testável: strings, números (
1,234.56e1.234,56), URLs e registros passam pela unidade compartilhadapackages/integrations/src/marketplace/normalize.ts— reutilizada pelo dialog, pelo import manual e pelo server action autoritativo; o bloco embutido no scraper é pinado por contrato (scraper-normalize.contract.test.ts). Ausência de evidência permanecenull/undefined— nunca zero saudável. - Retry & completude: até 3 tentativas por página com backoff exponencial +
jitter (no driver, no bridge POST e na paginação DOM). Páginas tentadas,
concluídas e perdidas são registradas; capturas com páginas perdidas terminam
com status
partial, nunca sucesso silencioso. - Envelope de captura:
expectedPages,completedPages,lostPages, itens recebidos/válidos/inválidos, statuscomplete|partial, URL de origem, timestamp e hash canônico (sha256 sobre itens ordenados por identidade — independente da ordem). O servidor recalcula o hash e rejeita envelope alterado. - Proveniência: cada snapshot persiste
vendor_domain,source_url,capture_statusecapture_meta; a trilha fica embv_marketplace_sync_runs(statuspartialpara capturas incompletas). - UX: o dialog segue a máquina de estados bridge → capturing → review → imported. A fase de revisão mostra percentual real, página atual/total, válidos/ inválidos, páginas perdidas, falhas sanitizadas e hash resumido. Captura parcial exige confirmação explícita antes de habilitar a importação; reimportar não duplica (upsert idempotente por rede+identidade+dia).
Correção de paginação (2026-08): leitura multilíngue do total
(results/resultados, formato MUI x-y of/de z) e seletores resilientes de
"próxima página" (EN/PT + MUI TablePagination + KeyboardArrowRight). Parser
puro testado em packages/integrations/src/clickbank/marketplace-pagination.ts.
Heurísticas de Seleção Cirúrgica de Produtos (5 Minutos)¶
Para selecionar produtos com alta probabilidade de lucro e menor risco de queima de capital, o Radar adota as seguintes regras de validação:
- Curva de Volume vs Tempo (Google Trends & Keyword Planner):
- Produtos em Ascensão / Platô Estável: Alta prioridade. Ofertas com buscas crescentes ou consolidadas no topo geram conversões consistentes.
- Produtos em Queda / Curva de Morte: Evitar. O leilão de CPC continua caro enquanto o volume de vendas desaba.
- Filtro de Tráfego de Compradores vs Ruído de Afiliados:
- Descontar buscas originadas no Brasil ou países não-compradores (geralmente afiliados espionando a oferta).
- Validar se o volume de buscas está concentrado nos países Tier-1 (EUA, Canadá, Reino Unido, Austrália).
- Sweet Spot de Gravidade (20 a 180):
- Gravidade < 10 (ou zero/ausente): Sem validação comprovada no marketplace — nunca tratamento saudável.
- Gravidade 20 a 180 (Sweet Spot): Validação real de mercado, alta conversão e leilão de CPC acessível.
- Gravidade 181 a 350: Concorrida — CPC sobe, exigência de diferenciação maior.
- Gravidade > 350: Hiperconcorrência, saturação de criativos e CPC inflacionado.
- Unit Economics & Calculadora de Breakeven CPC:
- $\text{Breakeven CPC} = \text{Payout Inicial} \times \text{CVR Estimado (1.5\%)}$.
- $\text{Lance Alvo (Target CPC Max)} = \text{Breakeven CPC} \times 0.60$ (para garantir 40% de margem de lucro líquido).
- Classificação de Funil & Recomendação de Presell:
- Identifica se o produtor usa VSL, TSL ou Checkout Direto, e indica automaticamente o template ideal (
zero-fuga-popup,product-bundlesoureview).
O Opportunity Score Determinístico¶
Cada snapshot em bv_marketplace_snapshots carrega:
| Campo | Significado |
|---|---|
gravity |
Demanda e momentum do marketplace (0/ausente = banda unknown). |
initial_payout |
Comissão da primeira compra (USD). |
avg_payout |
Payout médio por venda — evidência distinta, sem dupla contagem com o inicial. |
recurring_payout / rebill_rate |
Potencial de faturamento recorrente. |
avg_percent_per_sale |
Comissão média percentual. |
opportunity_score + score_breakdown |
Score total (0-100), Breakeven CPC, Presell Recomendada, canal recomendado e reason codes. |
Conversão Radar → Oferta enriquecida (Fase 3)¶
Salvar a oferta (automático no Lançar, ou pelo menu da linha) executa em um fluxo:
- valida snapshot + workspace no servidor (recarrega a linha — não confia em dados do browser);
- cria a oferta de forma determinística e idempotente por produto
(
offers.marketplace_identity_key=external_offer_idou vendor, em minúsculas) — capturas diárias geram snapshots novos, mas a oferta é a mesma; - gera HopLink ClickBank ou link rastreável sem expor secrets;
- dispara o enriquecimento IA estruturado;
- persiste avatar (dores/desejos/obstáculos), mecanismo único, promessa principal, ângulos e restrições de compliance;
- registra modelo, auditoria e status.
A falha da IA não desfaz nem corrompe a oferta: ela fica com
enrichment_status='failed', erro sanitizado em enrichment_error e botão
"Tentar enriquecimento novamente" no card Brief Estruturado da Oferta.
Colunas novas: jv_page_url, affiliate_terms_url, official_domain,
sales_page_url, tracking_link_template, avatar, core_mechanism,
main_promise, angles, compliance_restrictions, enrichment_status,
enrichment_model, enriched_at, enrichment_error
(migration 20260824010000_brandvelia_offer_enrichment.sql, additive-only,
ainda não aplicada ao banco remoto).
CTA principal: Lançar — salva a oferta se preciso, cria ou retoma a
preparação aberta da mesma oferta (start_launch, nunca duplica) e abre
/app/campaigns/wizard?launch_id=<uuid>. Com preparação aberta o botão vira
Continuar. "Espionar" também termina em Lançar, levando os anúncios gerados
para o passo 3.
Painel do Motor de Decisão (SHADOW)¶
O Radar embute o painel Motor de Decisão (SHADOW):
- Capital materializa o snapshot de capital do workspace (
S0/Cp/L/Ca, fórmulacapital/v1). Inputs desconhecidos produzemCa = null + motivo— o painel mostra gate e motivos, nunca um zero falso. - Scores v2 calcula o Opportunity Score v2 (
opportunity/v2) em shadow: amostra apenas cohorts cuja janela de refund fechou; pesos fixos (50% cobertura de conversão + 50% economia líquida normalizada, saturação USD 1.000). Resultados vão para snapshots imutáveis com hash estável. - Alertas determinísticos: alertas replay-safe derivados de fatos (ex.
CAPITAL_BLOCKED,ATTRIBUTION_UNKNOWN) com severidade e reason codes.
Todos os números vêm de materializações SQL; a UI nunca calcula dinheiro. Veja Motor de Decisão.