Lista de presença, sorteio de times equilibrados e controle de pagamentos da sua pelada.
Translation pending
Sports & fitnessGitHub @thiagozoioOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
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 ↗A pelada organizada e paga em dia: lista de presença com lista de espera, sorteio de times equilibrados e controle de quem pagou, num link para o grupo do WhatsApp.
App web (PWA) em Next.js 16 + Supabase, hospedado na Vercel.
| Tela | O que faz |
|---|---|
/login | Login sem senha: link mágico ou código de 6 dígitos por e-mail |
/grupos | Peladas do usuário; criar nova pelada (30 dias grátis) |
/convite/[código] | Entrar na pelada pelo link do WhatsApp; pode assumir um cadastro feito pelo organizador |
/g/[id] | Próximo jogo: Vou / Não vou, lista de espera, prioridade de mensalista, sorteio de times e envio para o WhatsApp |
/g/[id]/jogadores | Cadastro de jogadores: posição, nível 1–5 (só o organizador vê), mensalista ou avulso |
/g/[id]/financeiro | Mensalidades e avulsos por mês, quem deve e mensagem de cobrança pronta |
/g/[id]/config | Ajustes, valores, chave Pix, link de convite e status da assinatura |
/admin | Para o dono do SaaS: lista de grupos e marcação manual do "pago até" |
/perfil | Nome e liga/desliga dos avisos no celular (com botão de teste) |
priority_hours (padrão 24h) antes do jogo passa na frente dos avulsos.src/lib/draw.ts): um goleiro por time, linha distribuída por nível e depois trocas que reduzem a diferença entre os times.groups.paid_until; 7 dias depois do vencimento o grupo fica só leitura (garantido pela RLS).Funciona no Android (Chrome) e no iPhone com o app instalado na tela de início (iOS 16.4+). O jogador ativa na tela da pelada ou no Perfil.
| Aviso | Quando | Para quem |
|---|---|---|
| Pelada amanhã / hoje | rotina diária às 10h (/api/cron/avisos, vercel.json) | quem ainda não respondeu |
| Times sorteados | quando o organizador sorteia ou usa os times fixos | cada jogador sorteado, com o nome do seu time |
| Abriu vaga | quando alguém desiste ou é tirado da lista | quem sobe da lista de espera |
| Mensalidade em aberto | dia 5, na rotina diária | mensalistas que não pagaram o mês |
| Assinatura vencendo | 3 dias antes, no dia, 1 dia depois e no último dia antes do só leitura | organizadores |
| Cobrar resposta / recado | botão "Avisar no celular" na tela do jogo | pendentes / todos |
Os aparelhos ficam em push_subscriptions; o envio usa a chave secreta do Supabase (src/lib/supabase/admin.ts) só no servidor. Sem as variáveis de push no .env, tudo isso fica escondido.
Para ligar: gere as chaves com npx web-push generate-vapid-keys e cadastre NEXT_PUBLIC_VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, SUPABASE_SECRET_KEY e CRON_SECRET (veja .env.example).
npm install
cp .env.example .env.local # preencha com os dados do Supabase
npm run dev
Testes e checagens:
npm test # sorteio, lista de espera, datas e assinatura
npm run typecheck
npm run lint
Crie um projeto na região South America (São Paulo).
No SQL Editor, rode os arquivos de supabase/migrations/ em ordem de data (ou supabase db push com a CLI).
Desde 30/10/2026 o Supabase não dá mais acesso automático da API a tabelas novas em
public. Toda migration que cria tabela precisa trazer, logo depois docreate table, o grant explícito (e só então osrevoke/grant update (...)de colunas):grant select, insert, update, delete on public.nova_tabela to authenticated, service_role;
Authentication > URL Configuration: Site URL = URL do app (ex.: https://sempanela.vercel.app) e adicione https://sempanela.vercel.app/** e http://localhost:3000/** em Redirect URLs.
Authentication > Email Templates, nos modelos Magic Link e Confirm signup, troque o corpo por algo assim (o link funciona até aberto em outro navegador, e o código serve para quem está no app instalado):
<h2>Seu acesso ao Sem Panela</h2>
<p><a href="{{ .RedirectTo }}&token_hash={{ .TokenHash }}&type=email">Entrar no Sem Panela</a></p>
<p>Ou digite o código: <strong>{{ .Token }}</strong></p>
Para virar admin, depois do primeiro login rode no SQL Editor:
update public.profiles set is_admin = true
where id = (select id from auth.users where email = '[email protected]');
O e-mail padrão do Supabase tem limite baixo de envios por hora; para produção configure um SMTP (ex.: Resend) em Authentication > SMTP Settings.
Link pessoal (WhatsApp). Em Jogadores, o organizador abre um jogador e toca em Enviar acesso pelo WhatsApp. O jogador toca no link, aperta Entrar e fica logado no celular, sem e-mail nem código. Regras:
SUPABASE_SECRET_KEY (Project Settings > API Keys > Secret key) no servidor. A conta criada usa um e-mail interno <id>@jogador.sempanela.app.br que não recebe mensagens.Entrar com Google. Crie um OAuth Client ID (tipo Web application) no Google Cloud Console com a URI de redirecionamento https://<projeto>.supabase.co/auth/v1/callback, cole o Client ID e o Secret em Authentication > Providers > Google no Supabase e ponha NEXT_PUBLIC_GOOGLE_LOGIN=1 na Vercel.
gru1, São Paulo, em Settings > Functions)..env.example em Settings > Environment Variables.main publica sozinho.supabase/migrations/ esquema, RLS e funções do banco
src/proxy.ts renova a sessão do Supabase a cada requisição
src/lib/ regras puras (sorteio, lista, datas, assinatura) + acesso a dados
src/app/ telas (App Router) e server actions
paid_until já é o ponto de integração: o webhook só precisa atualizá-lo).