Ir para o conteúdo

Dashboard e Pages Functions

Frontend React (Vite) publicado no Cloudflare Pages, protegido por Cloudflare Access. Não tem banco próprio: lê o KV VEGGI_DATA que o robô preencheu.

Item Valor
Projeto Pages veggi-meta
Domínio oficial https://dashmeta.grupoveggi.com.br
Build npm run build (Vite) → pasta dist/
Login Cloudflare Access — team veggidocs.cloudflareaccess.com
Dependências react, react-dom, recharts — só três

A porta dos fundos está fechada

functions/_middleware.js só deixa passar o host dashmeta.grupoveggi.com.br. Qualquer acesso por veggi-meta.pages.dev ou por URL de preview recebe 403.

Nunca remova o _middleware.js

É ele que impede os dados de vazarem pela URL pública do Pages, que não tem login. Sem ele, os números da operação ficam abertos na internet.

Pages Functions

Arquivo Rota O que faz Secret
_middleware.js (todas) Porteiro: só o domínio oficial passa —
api/data.js GET /api/data Serve o KV latest —
api/ad-toggle.js POST /api/ad-toggle Liga/desliga anúncio, conjunto ou campanha na Meta. Body {id, status}. Exige o header Cf-Access-Jwt-Assertion META_TOKEN
api/refresh.js POST /api/refresh Botão "🔄 Atualizar agora" — dispara o robô sem esperar o cron UPDATE_KEY

O app chama /api/data na mesma origem, então a chamada passa pelo Access. Fallback local: /data.json.

O UPDATE_KEY do Pages é outro cofre

Existe um secret de mesmo nome no Worker robô. São dois cofres distintos e precisam do mesmo valor. Se o botão "Atualizar agora" responder erro, é este que falta:

npx wrangler pages secret put UPDATE_KEY --project-name=veggi-meta

Atalho: definir-chave-dashboard.bat.

As telas

Arquivo Tela Régua
src/App.jsx (1.179 linhas) Abas B2B: Resumo · Gráficos · Campanhas · Anúncios · Recomendações Negociação no CRM
src/B2C.jsx (1.852 linhas) Mundo B2C completo, independente Pedido faturado na VTEX
src/diario.jsx Aba Diário — o que mudou nos últimos 7 dias Degradação, não retorno
src/Saldo.jsx Cartão de saldo da conta + projeção de duração Usado pelos dois mundos
src/ui-perf.jsx Peças compartilhadas (gráficos, sparkline, leitura de público) —
src/lib/analytics.js Normalização e classificação — usada também pelo robô —
src/lib/diario.js Régua do Diário: fadiga, público, estrutura (lógica pura) —

A aba Anúncios tem sub-abas: 🌳 Estrutura (árvore campanha→conjunto→anúncio com botões pausar/ativar), 🎯 Por conjunto, 📊 Por anúncio (ranking com semáforo ciente do objetivo) e 📈 Gráficos. Filtros globais: Conta, Campanha, Status, Período. Tema claro/escuro.

A aba Diário tem régua própria

O Diário não olha dinheiro

Com ciclo de venda de 15 a 20 dias, uma semana não tem tempo de mostrar venda. O Diário existe para ver degradação (criativo, público, estrutura). Retorno é a aba Anúncios.

Decisões de projeto que parecem estranhas e não são:

  • Janela fixa de 7 dias contra os 7 anteriores, terminando ontem. Não usa o filtro de período do topo. Hoje está incompleto, e a Meta reajusta os números de um dia por até ~72h.
  • Frequência só existe em janela fechada. Pedir frequency com time_increment: 1 devolve impressões÷alcance de um dia — quase sempre ~1,0, ou seja, inútil. Por isso são duas chamadas separadas, DAILY_FIELDS e JANELA_FIELDS. Não juntar as duas.
  • Abaixo do piso de volume, o painel diz "não dá pra concluir" em vez de mostrar variação percentual bonita e falsa. Cada mexida relevante num conjunto reinicia o aprendizado da Meta.
  • Frequência ≥ 3 vale sozinha. Nesse patamar a Meta já ficou sem gente nova. Vira "Público saturado", e a ação é ampliar o público, não trocar criativo.

As quatro hipóteses do Diário

As ações são opostas entre si, por isso a distinção importa:

Hipótese Sinais Ação
Criativo reprovado Não converte, mas os irmãos do mesmo conjunto convertem Troca a peça
Público ruim Não converte e os irmãos também não Mexe na segmentação ou pausa
Criativo fadigando Converte, frequência subiu e CTR caiu Peça nova com a mesma promessa
Público pra renovar Converte, frequência subiu e CTR firme Amplia o público, não troca o criativo

As duas primeiras só se distinguem olhando os vizinhos — nenhuma métrica do próprio anúncio separa. Anúncio sozinho no conjunto: o painel admite que não sabe e ensina o teste, em vez de chutar.

Deploy

cd "C:\Projetos\veggi-ads-dashboard"
npm run build
npx wrangler pages deploy dist --project-name=veggi-meta --branch=main --commit-dirty=true

Atalho: publicar-online.bat. Depois, F5 com Ctrl+Shift+R no domínio oficial.

Diagnóstico

Sintoma Causa provável e ação
Dashboard abre mas sem dados O robô não rodou ou falhou. Ver Robô updater e conferir a chave latest no KV
Erro 403 ao abrir Acesso por veggi-meta.pages.dev ou URL de preview. Use o domínio oficial — é o _middleware.js funcionando
Botão "Atualizar agora" dá erro Falta o secret UPDATE_KEY no Pages (cofre diferente do Worker). Rodar definir-chave-dashboard.bat
Pausar/ativar anúncio não funciona META_TOKEN do Pages inválido ou sem escopo ads_management
Aba Diário vazia, resto OK A série diária roda em bloco try próprio de propósito: se a Meta falhar ali, só o Diário fica sem dado
Mudança publicada não aparece Cache do navegador. Ctrl+Shift+R. Se persistir, conferir Implantações no painel do Pages
Aba B2C sem pedidos, mas com gasto Anúncios criados à mão no Gerenciador nascem sem UTM. Só os criados pelo Consultor já vêm etiquetados