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.
翻譯準備中
尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 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.