factcircuit
FactCircuit: an auditable claim-and-evidence verification loop with immutable provenance, staged checks, bounded retrieval, and reproducible evaluation.
O custo de produção de pratos feitos regionais brasileiros, medido a cada coleta.
Translation pending
DataTypeScript · PythonGitHub @indicepfOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
Índice do custo do prato feito brasileiro. Mede, coleta a coleta, quanto custa produzir cada um de 100 pratos regionais (5 regiões, ~115 ingredientes-base) a partir de preços reais do varejo online, e publica o resultado em um dashboard público. Produção: indicepratofeito.com.br Documentação técnica completa: docs/ (HTML, um arquivo por fase do projeto)Read the full README ↗
Índice do custo do prato feito brasileiro. Mede, coleta a coleta, quanto custa produzir cada um de 100 pratos regionais (5 regiões, ~115 ingredientes-base) a partir de preços reais do varejo online, e publica o resultado em um dashboard público.
Produção: indicepratofeito.com.br
Documentação técnica completa: docs/ (HTML, um arquivo por fase do projeto)
palavras_ok/palavras_nao), limpeza de preço, normalização para R$/g e dois filtros estatísticos (sanidade [mediana/4, mediana×4] e outliers por IQR). O preço do ingrediente na coleta é a mediana dos preços normalizados.custo = Σ (preço R$/g × quantidade da receita) + Σ custo fixo, para cada um dos 100 pratos (receitas na tabela receitas).Preços de campo entram por crowdsourcing: usuários fotografam etiquetas em /contribuir, a moderação aprova em /admin, e as leituras aprovadas calibram os descontos regionais e alimentam o blend manual×online (ver Modelo de preço).
GitHub Actions (cron semanal)
└─ pipeline/scraper_pf.py coleta via SerpAPI (Google Shopping)
└─ snapshot_pf.json artefato local da coleta
└─ pipeline/salvar_supabase.py grava em staging no Supabase
└─ aprovação humana em /admin (aba Coleta)
└─ calcular_custos_pratos (RPC) custo por prato + índice
└─ Next.js (Vercel) dashboard público
A coleta fica em staging (tabelas precos/resultados_brutos) e só entra no índice após aprovação no /admin. Coletas pendentes há mais de 5 dias são integradas automaticamente (pg_cron no Supabase).
| Camada | Tecnologia |
|---|---|
| Frontend | Next.js 16 (App Router) + React 19 + Tailwind CSS 4 |
| Gráficos e mapas | Recharts, react-simple-maps (d3-geo/topojson), Leaflet |
| Banco, auth e storage | Supabase (PostgreSQL, RLS, Auth, Storage) |
| Pagamentos | Asaas (assinaturas, webhook em /api/webhooks/asaas) |
| Coleta de preços | Python 3.11 + SerpAPI (engine google_shopping) |
| Automação | GitHub Actions (cron semanal) |
| Deploy | Vercel (GitHub integration) |
indice-pf/
├── app/ # Next.js App Router
│ ├── (site)/ # Páginas públicas: home, /metodologia, /sobre, /planos
│ ├── (app)/ # Área logada: /painel, /evolucao, /contribuir, /admin…
│ ├── (auth)/ # /entrar, /cadastro, /esqueci-senha, /completar-perfil
│ └── api/ # /api/assinatura, /api/geo, /api/webhooks/asaas
├── components/ # Componentes compartilhados
├── lib/ # Cliente Supabase, tipos, queries, formatação, export
├── public/ # Assets estáticos
├── pipeline/ # Pipeline de coleta (Python)
│ ├── scraper_pf.py # Coleta preços no Google Shopping (SerpAPI)
│ ├── salvar_supabase.py # Grava o snapshot no banco (staging)
│ ├── calcular_custos_pratos.py # Custo por prato + índice nacional
│ └── limpar_simulados.py # (legado) remoção de snapshots simulados
├── scripts/ # Ferramentas pontuais (tabela canônica, seed, correções)
├── data/ # Planilhas-fonte e relatórios de diagnóstico
├── supabase/
│ └── migrations/ # Migrações SQL (rodar em ordem no SQL Editor)
├── docs/ # Documentação técnica por fase (HTML)
└── .github/workflows/
└── scraper-semanal.yml # Automação da coleta
Pré-requisitos: Node 20+, Python 3.11+ (apenas para o pipeline).
Frontend:
npm install
npm run dev
Pipeline de coleta (opcional, requer chaves SerpAPI e service role do Supabase):
pip install requests python-dotenv
python pipeline/scraper_pf.py # coleta e gera pipeline/snapshot_pf.json
python pipeline/salvar_supabase.py # grava no Supabase (staging)
Ambos leem o .env.local da raiz.
Crie um .env.local na raiz (não é versionado):
| Variável | Usada por | Descrição |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | Frontend | URL do projeto Supabase |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Frontend | Chave anônima (pública; RLS protege os dados) |
SUPABASE_URL | Pipeline | URL do projeto Supabase |
SUPABASE_KEY | Pipeline | Service role key (nunca expor no frontend) |
SERPAPI_KEY … SERPAPI_KEY_4 | Pipeline | Contas SerpAPI (rotação automática quando a cota esgota) |
faltantes (default) — coleta só o que não veio nos últimos 6 dias e mescla ao último snapshot. Uso: reparar coleta incompleta.completo — coleta todos os ingredientes (mesmo modo do cron).pipeline/cache_serpapi.json) evita gastar cota em reexecuções no mesmo dia./admin (aba Coleta); continuam sendo tentados a cada coleta e entram sozinhos quando aparecem.Precedência do preço R$/g de cada ingrediente (implementada em calcular_custos_pratos e replicada em lib/queries.ts):
| Ordem | Condição | Preço usado |
|---|---|---|
| 1 | Tem custo_fixo | Valor fixo (flat por prato) |
| 2 | Manual recente e online | Média das duas medianas (blend 50/50) |
| 3 | Só manual recente | Mediana das leituras manuais |
| 4 | Só online (desta coleta ou última conhecida) | Mediana online |
| 5 | Sem online, manual antigo | Última leitura manual (fallback) |
"Manual recente" = leituras na janela de ±10 dias da data do snapshot; o valor é a mediana das leituras da janela. Leituras manuais são registradas em /admin e arquivadas com histórico (precos_manuais_hist).
Tabelas principais (Supabase/PostgreSQL, acesso com RLS):
| Tabela | Conteúdo |
|---|---|
snapshots | Uma linha por coleta (data, fonte, índice) |
precos | Estatísticas por ingrediente por coleta (mediana, média, mín, máx, DP) |
resultados_brutos | Cada produto coletado (título, loja, preço, link) — modal "Fontes" |
ingredientes | Catálogo de ingredientes-base (busca, unidade, regras de validação) |
pratos / receitas | 100 pratos e suas receitas (ingrediente × quantidade) |
custos_pratos | Custo por prato por coleta, com cobertura |
contribuicoes | Fotos de preço enviadas por usuários (crowdsourcing) |
profiles | Perfil do usuário (RLS: cada um lê/edita só o próprio) |
precos_manuais_hist | Histórico de leituras de preço manual |
snapshots e resultados_brutos são append-only — nunca deletar.
As migrações estão em supabase/migrations/, numeradas; rodar em ordem no SQL Editor do Supabase. São escritas de forma defensiva (IF NOT EXISTS).
| Rota | Acesso | Descrição |
|---|---|---|
/ | Público | Dashboard: índice nacional, mapa por região, explorador de pratos |
/metodologia, /sobre, /planos | Público | Páginas institucionais |
/entrar, /cadastro, /esqueci-senha | Público | Autenticação (Supabase Auth, e-mail + senha) |
/painel | Logado | Painel do usuário |
/contribuir | Logado | Envio de preços de campo (foto + geolocalização), modos único e lote |
/meus-envios, /perfil, /configuracoes | Logado | Contribuições e dados do usuário |
/assinar, /plano | Logado | Assinatura (Asaas) |
/evolucao | Admin | Histórico: série do índice, variação, ingredientes, calibração |
/contribuidores | Admin | Ranking mensal de contribuidores |
/admin | Admin | Moderação, coleta (aprovação/preços manuais), dados, pagamentos |
Acesso admin via profiles.is_admin; ações destrutivas exigem superuser e ficam registradas em log.
Workflow: .github/workflows/scraper-semanal.yml. Roda pipeline/scraper_pf.py e pipeline/salvar_supabase.py; a integração ao índice depende de aprovação no /admin. Tem concurrency para nunca haver dois runs simultâneos.
Secrets necessários no repositório:
SUPABASE_URL, SUPABASE_KEY (service role)SERPAPI_KEY, SERPAPI_KEY_2, SERPAPI_KEY_3, SERPAPI_KEY_4Para mudar a frequência da coleta, ajustar em conjunto: o cron do workflow, a cota SerpAPI disponível e os textos do site que citam a frequência.
Deploy contínuo via integração GitHub → Vercel: merge na main publica em produção. O .npmrc usa legacy-peer-deps. Headers de segurança (HSTS, CSP em report-only, X-Frame-Options etc.) em next.config.ts.
| Script | Função |
|---|---|
scripts/mapa_canonico.py | Mapa curado: 404 nomes de receita → ingredientes-base |
scripts/tripe_scraping.py | Termo de busca, unidade e regras de validação por ingrediente |
scripts/gerar_tabela_canonica.py | Gera data/tabela_canonica_ingredientes.xlsx (receitas consolidadas, 8 abas) |
scripts/seed_supabase.py | Popula ingredientes/pratos/receitas (idempotente, requer service role) |
scripts/gerar_sql_correcao.py | Recoleta ingredientes pontuais e gera SQL de correção |
Projeto privado e proprietário. Documentação detalhada de cada fase em docs/.