TreeMap
무료 오픈소스 디스크 사용량 시각화 도구로, 사각형 트리맵·중복 파일 탐색·디스크 가득 예측·정리 시 파일을 휴지통으로만 이동한다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Lista de compras compartilhada com sincronizacao em tempo real. Next.js 16 + Supabase.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Lista de compras compartilhada. Quem está com a lista aberta vê os itens sendo marcados, adicionados e removidos na hora — sem recarregar nada. Next.js 16 (App Router) · Supabase (Postgres + Realtime + Auth) · Resend · hospedado na Vercel Ao trocar de domínio, três lugares precisam acompanhar, senão o login quebra: Site URL e Redirect URLs no Supabase, e o Sender email em SMTP Settings. Deploy: automático. Todo push em master publica em produção; cada Pull Request ganha uma URL de preview própria. Para publicar manualmente sem passar pelo Git, vercel deploy --prod na raiz do projeto.README 전문 보기 ↗
No ar: https://lista.rafarcs.com
Lista de compras compartilhada. Quem está com a lista aberta vê os itens sendo marcados, adicionados e removidos na hora — sem recarregar nada.
Next.js 16 (App Router) · Supabase (Postgres + Realtime + Auth) · Resend · hospedado na Vercel
| Peça | Onde |
|---|---|
| App | lista.rafarcs.com (CNAME → Vercel, projeto rcs14/lista-viva) |
| Banco e auth | Supabase ajcghzkmokmbnvkavozp |
Resend, domínio rafarcs.com verificado, remetente [email protected] |
Ao trocar de domínio, três lugares precisam acompanhar, senão o login quebra: Site URL e Redirect URLs no Supabase, e o Sender email em SMTP Settings.
Deploy: automático. Todo push em master publica em produção; cada Pull
Request ganha uma URL de preview própria. Para publicar manualmente sem
passar pelo Git, vercel deploy --prod na raiz do projeto.
Projetos novos na Vercel nascem com Deployment Protection ligada — o site fica atrás do login da Vercel e ninguém de fora consegue abrir. Desligue em Settings → Deployment Protection.
O código está pronto. Faltam três passos que só você pode fazer, porque envolvem criar a sua conta no Supabase.
Vá em supabase.com/dashboard → New project.
Escolha a região South America (São Paulo) para a latência do realtime ficar boa.
Anote a senha do banco (você não vai precisar dela aqui, mas guarde).
Na primeira vez, no painel do projeto: SQL Editor → New query, cole o
conteúdo inteiro de supabase/schema.sql e execute.
Depois disso, prefira o comando:
npm run db:push
Ele aplica o arquivo inteiro e lista as funções criadas, para confirmar que
tudo entrou. Precisa de um .env.db.local (fora do git) com
SUPABASE_DB_REF, SUPABASE_DB_PASSWORD e SUPABASE_DB_REGION — pegue em
Settings → Database. Essa credencial é só para migração; o app usa a
chave anon, sob RLS.
Existe porque colar um arquivo de trezentas linhas no editor já falhou uma vez: a seleção não pegou até o fim, a última função não foi criada, e o erro só apareceu no teste.
Isso cria as cinco tabelas, as políticas de RLS, os triggers e liga o
Realtime na tabela items. O arquivo é idempotente — pode rodar de novo
sem quebrar nada.
Em Project Settings:
Cole as duas em .env.local (crie a partir de .env.local.example):
NEXT_PUBLIC_SUPABASE_URL=https://seu-projeto.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
A chave anon é pública por natureza — quem protege os dados é o RLS, não o segredo da chave. Nunca coloque a service_role aqui.
Em Authentication → URL Configuration, adicione em Redirect URLs:
http://localhost:3000/auth/callback
Quando publicar, adicione também a URL de produção.
npm install
npm run dev
Abra http://localhost:3000.
A outra janela mostra o anel colorido no cartão, o toast com o avatar de quem mexeu e a linha de atividade no topo — sem recarregar.
Sem servidor de e-mail configurado, o Supabase limita os envios do link mágico. Para testar rápido, pegue o link direto em Authentication → Users → o usuário → Send magic link, ou use o Inbucket do ambiente local (
supabase start).
Sem SMTP próprio, o Supabase limita o envio a 2 e-mails por hora — o terceiro login da hora simplesmente não recebe o link. Para qualquer uso real isso precisa ser resolvido.
Crie a conta em resend.com.
API Keys → Create API Key, permissão Sending access. Copie a
chave (re_...), ela só aparece uma vez.
No Supabase: Authentication → Emails → SMTP Settings → ligue Enable Custom SMTP e preencha:
| Campo | Valor |
|---|---|
| Host | smtp.resend.com |
| Port | 465 |
| Username | resend |
| Password | a chave re_... |
| Sender email | [email protected] |
| Sender name | Lista Viva |
Authentication → Rate Limits → suba Rate limit for sending emails de 2 para algo como 100 por hora. O limite antigo continua valendo até você mudar isto, mesmo com o SMTP configurado.
Enquanto não houver domínio próprio: o remetente [email protected]
só entrega no e-mail dono da conta Resend. Endereços de terceiros são aceitos
pela API mas não chegam. Para testar mais de uma pessoa, use os apelidos do
Gmail ([email protected], [email protected]) — para o Supabase são
contas distintas, e tudo cai na mesma caixa de entrada.
Para publicar de verdade, registre um domínio, verifique-o no Resend
(Domains → adicionar → 3 registros DNS) e troque o Sender email para
algo como [email protected].
103 casos, verdes contra um Supabase real em ~45 s.
npm test # roda a suíte uma vez
npm run test:watch
A suíte fala com um Supabase de verdade, porque é exatamente isso que ela protege: políticas de RLS e configuração de Realtime não têm como ser testadas com mock — o mock passaria mesmo com a política errada.
| Arquivo | Protege |
|---|---|
tests/rls.test.ts | Isolamento entre pessoas: quem não é membro não lê, não escreve, não vê perfis. Triggers de perfil e de dona. Cascade. |
tests/convite.test.ts | Token do convite, acesso concedido, entrada repetida sem duplicar, saída revogando acesso. |
tests/realtime.test.ts | Os dois ajustes de banco mais fáceis de perder numa migração (ver abaixo). |
tests/seguranca.test.ts | Que os testes não conseguem apagar dados que não criaram. |
tests/erros-auth.test.ts | Tradução das mensagens de login. Função pura: roda sem banco nem credencial. |
tests/fila-offline.test.ts | Coalescência e projeção da fila offline. Também sem banco. |
tests/fila-reenvio.test.ts | A tradução de cada operação da fila na escrita correspondente, contra o banco. |
tests/service-worker.test.ts | Que o SW não guarda HTML autenticado nem intercepta o Supabase. Sem banco. |
tests/sugestoes.test.ts | Sugestões pelo histórico — inclusive que elas não vazam itens de listas alheias. |
tests/itens-unicos.test.ts | Um item, uma linha — inclusive com duas pessoas adicionando ao mesmo tempo. |
Dois achados da verificação inicial motivaram a suíte, porque quebram em silêncio — sem erro de build, sem exceção, sem log:
replica identity full na tabela items. Se sair, o payload de
DELETE passa a trazer só a chave primária, o filtro list_id=eq.… nunca
casa, e exclusões feitas por outra pessoa somem da tela de quem está
junto. O mesmo ajuste é o que faz o UPDATE trazer a linha antiga, base
para a interface dizer o que mudou.updated_by em items. Sem ele, uma mudança de quantidade seria
creditada a quem marcou o item por último, e a linha de atividade
passaria a mentir.Um using (true) colado por engano numa política também não quebra build
nem lint — só remove o isolamento entre famílias diferentes.
Os testes criam e apagam listas, itens e associações. Por isso as
variáveis têm nomes próprios (TEST_*) e não herdam nada do .env.local:
apontar o alvo precisa ser uma decisão consciente. Sem .env.test, a suíte
recusa rodar em vez de adivinhar.
Foi a escolha deste projeto: um Supabase separado custaria a última vaga do plano gratuito. Para que isso seja seguro, a disciplina é verificada por código, não confiada à memória de quem escrever o próximo teste:
[teste].apagarLista() recusa qualquer lista sem esse prefixo, com erro
explicando o porquê. Um teste futuro que tente apagar dado real falha.tests/seguranca.test.ts verifica essa recusa a cada execução.afterAll não rode.Para migrar a um projeto dedicado depois, basta trocar TEST_SUPABASE_URL
e TEST_SUPABASE_ANON_KEY — no .env.test e nos secrets do repositório.
supabase/schema.sql nele.cp .env.test.example .env.test e preencha.No CI, os mesmos valores vão como secrets do repositório. Se não existirem, o job de regressão é pulado em vez de falhar — assim um fork continua verde.
O plano gratuito do Supabase pausa um projeto depois de 7 dias sem
atividade. Uma lista de compras passa uma semana parada sem nada de
errado — e quando isso aconteceu, o host sumiu do DNS, o fetch do
navegador estourou, e a tela de login mandou conferir a internet.
.github/workflows/manter-acordado.yml roda todo dia às 06:17 UTC e faz
uma consulta de verdade: lê sem autenticar, entra com senha (o que
escreve no banco), consulta de novo sob RLS e encerra a sessão. Diário
dá seis dias de folga sobre o prazo de sete, margem de sobra para os
atrasos do cron do GitHub.
Ele também serve de vigia: se qualquer passo falhar, o GitHub manda e-mail para quem é dono do repositório. A mensagem de host inacessível diz o que fazer, com o link do painel.
Atenção: o GitHub desliga trabalhos agendados em repositórios sem commits por 60 dias. Avisa por e-mail antes, e reativar é um clique na aba Actions — mas se o aviso passar batido, a pausa volta.
Para conferir na hora: aba Actions → Manter o banco acordado → Run workflow.
tests/
setup.ts Trava: sem .env.test, nada roda
helpers.ts Sessões por pessoa, fixtures, inscrição em canal
rls.test.ts Isolamento entre pessoas
convite.test.ts Token, acesso, saída
realtime.test.ts Eventos, payload.old, DELETE filtrado
seguranca.test.ts Trava contra apagar dado real
erros-auth.test.ts Tradução dos erros (puro, sem rede)
fila-offline.test.ts Coalescência da fila (puro, sem rede)
fila-reenvio.test.ts Reenvio da fila contra o banco
service-worker.test.ts Regras do SW (puro, sem rede)
sugestoes.test.ts Sugestões e o que elas não podem vazar
itens-unicos.test.ts Fusão por nome, inclusive sob corrida
scripts/
db-push.mjs Aplica o schema.sql no banco
src/
proxy.ts Renova a sessão e protege as rotas
app/
entrar/ Login por link mágico
auth/callback/ Troca o code pela sessão
auth/sair/ Logout
listas/ Suas listas + criar lista
listas/[id]/ A lista aberta
j/[token]/ Entrar por convite
components/
Home.tsx Cartões de lista com progresso
ListaView.tsx Realtime, presença e ações otimistas
ItemRow.tsx Cartão do item + arrastar para excluir
ShareSheet.tsx Link de convite e participantes
lib/
supabase/client.ts Cliente do navegador
supabase/server.ts Cliente de servidor
types.ts
supabase/
schema.sql Tabelas, RLS, triggers, realtime
prototipo.html Protótipo de UI original (referência de design)
| Tabela | Para quê |
|---|---|
profiles | Nome e cor de cada pessoa. Criado por trigger no cadastro. |
lists | A lista. owner_id é quem criou. |
list_members | Quem participa de qual lista, e com que papel. |
items | O item. added_by, checked_by e updated_by alimentam a linha de atividade. |
list_invites | Token do link de convite, com prazo de sete dias. |
is_list_member() é SECURITY DEFINER. A política de list_members
precisa consultar list_members para saber quem é membro — o que faria o
Postgres entrar em recursão infinita. A função quebra o ciclo.
items tem REPLICA IDENTITY FULL. Sem isso, o payload de DELETE
do Realtime traz só a chave primária, e o filtro list_id=eq.<id> nunca
casaria — exclusões feitas por outra pessoa nunca chegariam na sua tela.
É também o que faz o UPDATE trazer a linha antiga, permitindo comparar
antes/depois e dizer o que mudou em vez de adivinhar pelo estado final.
21 checagens automatizadas passaram contra um projeto Supabase de verdade, cobrindo RLS entre usuários distintos, realtime, convite e cascade. O que elas mostraram de não-óbvio:
SUBSCRIBED do Realtime chega antes de a replicação estar
atrelada no Postgres. Medimos uma janela de ~3 s em que eventos se perdem.
Por isso ListaView busca o estado atual dos itens logo após inscrever —
sem isso, quem abre a lista enquanto outra pessoa mexe nela veria dado
velho até recarregar.payload.old chega completo nos UPDATEs, confirmando que o
REPLICA IDENTITY FULL está valendo — é o que sustenta a linha de
atividade dizer o que mudou.UPDATE, e quem está
do outro lado vê a quantidade final em vez de uma contagem.updated_by e diff já cobre)