FloCafe
FloCafe is the free, local-first restaurant POS in the FloPOS ecosystem. Run orders, tables, kitchen display, and local data without a software subscription.
Encontre a oferta. Confira o histórico. Economize de verdade. Histórico de preços e menor preço atual dos produtos mais buscados na Black Friday.
Translation pending
CommerceTypeScript · CSSGitHub @agermanoiOnlineOwner 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
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Histórico de preços da Black Friday. O nome do site vem de NEXT_PUBLIC_SITE_NAME (padrão: Radar de Ofertas).
Site público que acompanha os produtos mais buscados da Black Friday em várias lojas, guarda o histórico diário e diz se o desconto é real ou “metade do dobro”. Monetização por links de afiliado (Lomadee, Amazon Associados, Mercado Livre, Awin…).
Stack: Next.js 15 (Vercel) · Supabase (Postgres) · GitHub Actions (coleta 2×/dia)
GitHub Actions ──(2x/dia)──> scripts/collect.ts ──> Supabase (offers + price_history)
│ │
Mercado Livre API ──────────┤ ▼
SerpAPI (Google Shopping) ──┤ Next.js na Vercel
Lomadee (afiliados) ────────┤ (home, /produto/[slug], /go/[id])
Raspagem (JSON-LD) ─────────┘
npm install
DEMO_DATA=1 npm run dev # http://localhost:3000 com 45 dias de dados fictícios
supabase/schema.sql.URL, anon key e service_role key.cp .env.example .env # preencha Supabase + as fontes que for usar
npm run seed # cadastra os 24 produtos de data/products.json
| Fonte | O que precisa | Custo |
|---|---|---|
| Mercado Livre | App em developers.mercadolivre.com.br com Redirect URI https://cacaofertas.com.br/admin/mercadolivre. ML_CLIENT_ID e ML_CLIENT_SECRET na Vercel e no GitHub. Depois, no painel: Mercado Livre → Conectar. (npm run ml:auth continua como alternativa.) | Grátis |
| SerpAPI | SERPAPI_KEY | ~720 buscas/mês com 24 produtos (plano pago) |
| Lomadee | LOMADEE_API_KEY com escopos products:read e shortener:write. Links de afiliado são gerados automaticamente. | Grátis |
| Raspagem | Coloque URLs de produto em products.scrape_urls (Table Editor do Supabase). Lê o JSON-LD das páginas. | Grátis |
Desde 2025 a busca do Mercado Livre exige token; o refresh token é de uso único e a coleta
salva o novo na tabela kv a cada execução. Se a coleta ficar mais de 6 meses parada, rode ml:auth de novo.
Teste a coleta: npm run collect (ou só um produto: npm run collect -- iphone-16-128gb).
AMAZON_ASSOCIATE_TAG=seutag-20ML_AFFILIATE_TEMPLATE com {url}.AFFILIATE_TEMPLATES={"kabum.com.br":"https://www.awin1.com/cread.php?awinmid=MID&awinaffid=ID&ued={url}"}/go/[id], que registra na tabela clicks e redireciona.NEXT_PUBLIC_SITE_URL, NEXT_PUBLIC_SUPABASE_URL,
NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, REVALIDATE_SECRET.Settings → Secrets and variables → Actions → crie os secrets usados em
.github/workflows/collect.yml (Supabase, fontes, afiliados) e também:
REVALIDATE_URL = https://seudominio.com.br/api/revalidateREVALIDATE_SECRET = o mesmo da VercelRoda às 09:17 e 21:17 (Brasília). Para rodar na hora: Actions → Coleta de preços → Run workflow.
Na semana da Black Friday, adicione mais horários no cron do workflow.
Acesse https://seudominio.com.br/admin e entre com a senha de ADMIN_PASSWORD.
GITHUB_REPO e GITHUB_TOKEN
(token fine-grained do repositório com permissão Actions: Read and write).Variáveis na Vercel: ADMIN_PASSWORD, ADMIN_SESSION_SECRET (texto longo aleatório), GITHUB_REPO, GITHUB_TOKEN
e SUPABASE_SERVICE_ROLE_KEY (o painel grava com ela, só no servidor).
Banco já criado antes do painel? Rode o supabase/schema.sql de novo: ele só acrescenta a coluna specs e atualiza a view.
O data/products.json agora serve só como lista inicial. npm run seed cadastra os que ainda não existem
e não mexe no que você editou pelo painel; npm run seed -- --atualizar sobrescreve tudo com o arquivo.
query: termo de busca nas APIs
must: termos obrigatórios no título ("a|b" = um ou outro)
exclude: termos que descartam o anúncio (capa, película, usado…)
min_price: abaixo disso é acessório ou golpe
popularity: ordem em “Os mais buscados”
"~codigo" em must/exclude: código de modelo, casa mesmo grudado em outro texto (~u8000f acha "UN55U8000FGXZD")
Para desligar um produto sem apagar: active = false no Supabase.
Edite pelo painel. A ficha salva no banco tem prioridade; sem ela, a página usa a de data/specs.json pelo slug.
Aparece na página do produto e vai para o JSON-LD (additionalProperty). Produto sem ficha só não mostra a seção.
lib/verdict.ts)Precisa de 5 dias de histórico (NEXT_PUBLIC_MIN_DAYS_FOR_VERDICT). Compara o menor preço atual
com a média dos 30 dias anteriores:
app/ páginas (home, produto, como-funciona), /go redirect, /api/revalidate, sitemap
components/ etiqueta de preço, gráfico, sparkline, catálogo com busca/filtro
lib/collectors/ mercadolivre, serpapi, lomadee, scraper
lib/match.ts filtro de anúncios (must/exclude/preço mínimo)
lib/verdict.ts regra do veredito
lib/mock.ts dados fictícios (DEMO_DATA=1)
scripts/ collect, seed, ml-auth
supabase/schema.sql tabelas, views e RLS
Componente components/AdSlot.tsx: só a div, com altura mínima reservada (sem CLS). Ligue o seu ad server pelo id.
| id da div | Página | Posição | Desktop | Mobile |
|---|---|---|---|---|
ad-home-topo | Home | logo após o destaque | 970x90, 728x90 | 320x100, 320x50 |
ad-home-lista-1 | Home | após a 6ª linha do catálogo | 728x90, fluid | 300x250, fluid |
ad-home-lista-2 | Home | após a 14ª linha | 728x90, fluid | 300x250, fluid |
ad-home-rodape | Home | antes do rodapé | 970x250, 970x90, 728x90 | 300x250, 320x100 |
ad-produto-topo | Produto | entre os números e o gráfico | 970x90, 728x90 | 320x100, 320x50 |
ad-produto-rodape | Produto | depois da tabela de ofertas | 336x280, 300x250 | 300x250 |
ad-conteudo-meio | Como funciona | no meio do texto | 336x280, 300x250 | 300x250 |
Nenhum anúncio fica entre o veredito e o botão "Ver na loja", para não competir com o clique de afiliado.
Cada div traz data-ad-slot, data-sizes-desktop e data-sizes-mobile. Exemplo com GPT:
googletag.defineSlot('/SEU_ID/radar/home-topo', [[970,90],[728,90]], 'ad-home-topo').
NEXT_PUBLIC_ADS=off remove todos; NEXT_PUBLIC_ADS_DEBUG=1 mostra o contorno de cada um.