Long Run Club
Our marathon training leaderboard.
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
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).