TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
Plataforma de gerenciamento de tarefas com time-blocking, assistente de IA e muito mais.
Translation pending
ProductivityTypeScript · JavaScriptGitHub @Gustavo-Martins-CirinoOnlineOwner 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
Loading the full README. The saved excerpt is shown below.
Copiloto de rotina pessoal: tarefas, time blocking, gamificação e uma IA que propõe e age no app — sempre com confirmação do usuário. Não é mais um calendário passivo. Ele planeja o dia de trás pra frente a partir de um compromisso-âncora, aprende quanto tempo você leva de verdade em cada atividade e cobra check-in quando o horário passa. A visão completa está no ROADMAP.md. Aplicação Next.js única — não há servidor separado. Toda a lógica de servidor vive em Route Handlers do Next; o banco, a autenticação e o agendamento são do Supabase.Read the full README ↗
Copiloto de rotina pessoal: tarefas, time blocking, gamificação e uma IA que propõe e age no app — sempre com confirmação do usuário.
Não é mais um calendário passivo. Ele planeja o dia de trás pra frente a partir de um compromisso-âncora, aprende quanto tempo você leva de verdade em cada atividade e cobra check-in quando o horário passa. A visão completa está no ROADMAP.md.
Aplicação Next.js única — não há servidor separado. Toda a lógica de servidor vive em Route Handlers do Next; o banco, a autenticação e o agendamento são do Supabase.
frontend/ app Next.js (UI + rotas de API)
supabase/ scripts SQL por feature + templates de e-mail
Pré-requisitos: Node 20+, pnpm 11 e um projeto Supabase.
cd frontend
pnpm install
cp .env.example .env.local # preencha (ver abaixo)
pnpm dev # http://localhost:3000
pnpm test # suíte dos módulos determinísticos
Antes do primeiro login, rode os SQLs em supabase/ — ver Banco de dados.
pnpm test (Vitest) cobre os módulos determinísticos de lib/ — os que decidem
datas, XP, recorrência, parsing e formatação sem tocar em rede: admin, avatar-accessories,
avatar-calca (a cor da calça e a regra do terno, que vale no bonequinho 2D e no boneco 3D),
avatar-cabelo (o contorno ondulado do cabelo cacheado, que era sete discos soltos),
avatar-silhueta (as duas silhuetas do corpo e o que cada roupa faz com elas — o teste
compara RAZÕES, porque o defeito antigo era serem o mesmo desenho em dois tamanhos),
backward-plan, calendar-feed,
contraste (a conta da WCAG a partir do oklch — e o teste varre o globals.css do
ARQUIVO, porque medir no navegador já mentiu duas vezes aqui), calendar-scroll, calendar-warnings, focus-gradient,
foco-pontos (quanto o Modo Foco paga: os blocos de 5 min pagos pela DIFERENÇA, para um
tique atrasado não perder nem repetir bloco, e quando a tarefa concluída no foco dobra),
foco-sessao e sino-foco (o foco que sobrevive a recarregar, e o relógio por instante de fim),
foco-cenas (os ambientes pagos do Foco: o preço da tela é o MESMO do SQL, a respiração
guiada, uma estrela a cada 5 min — e a figura da Constelação nunca passando por trás do timer —,
o pôr do sol da Revoada que só desce, a grade das Sinapses que nunca passa do teto de células e
os neurônios dela fora do miolo do timer, e quando a rede na placa de vídeo passa para o modo leve),
auth-metodos (quais botões de login aparecem, e qual foi o último usado),
enquete (quando perguntar e quando ficar quieto — e que "agora não" cala a enquete
inteira, não só a pergunta recusada),
comece-por-aqui (a contagem guardada do card de primeiros passos, e que graduar é para sempre),
dashboard-metricas (as três perguntas de "Seus números" — e o agrupamento por dia e
hora locais, que é onde um toISOString() distraído jogaria toda noite de trabalho
para o dia seguinte),
foto-perfil (o recorte quadrado central, o que se aceita e o carimbo anti-cache),
gamification (anti-farm),
i18n (o dicionário pt/en: nenhum texto vazio, as duas línguas com as mesmas chaves, e a
varredura que pega "tradução de fachada" — a frase que ficou igual nos dois idiomas),
enfase (o negrito dentro da frase traduzida, e que marca sobrando não quebra a tela) e
locale-fixo (varre o AST de app/components/lib/hooks atrás de /
escritos à mão — o locale vazando por baixo de uma tela já traduzida, com as exceções
legítimas nomeadas uma a uma, motivo incluído),
(as sugestões da tela vazia da Neuro IA: sanear, tapar no teto de seis,
reconhecer o padrão — e que "nunca mexeu" e "apagou tudo" são estados diferentes),
(a data que a Neuro recebe: por extenso e em ISO,
com o mês já delimitado — "28/08" obrigava o modelo a adivinhar dia/mês),
(quando a Neuro recusa criar por já existir: mesmo título E mesmo dia, com
"na dúvida, cria" como critério de desempate),
(com quem o bloco novo choca ou fica colado — lido na vizinhança dele, no fuso
de quem usa e com os recorrentes expandidos: o dia UTC do servidor deixava cego tudo depois das
21h no Brasil), , (nome → iniciais e cor do avatar),
, (a paleta das notas: guarda a chave e não o hex nem o nome — o
nome mora no dicionário —, e cor órfã vira "sem cor" em vez de erro), (região ↔ formato de hora, e a ida e volta entre os dois),
(a resposta da Neuro entrando escrita no chat: duração fixa e ritmo
saindo do tamanho — é o que impede uma resposta longa de levar meio minuto para aparecer),
, , (inclusive que "não repete" vira NULO e
não a string "none", que o que sai de é lido por , e que
nenhuma opção carrega texto de interface — o nome de cada repetição mora no dicionário) e
. É onde a lógica sutil regride sem
ninguém ver. Componente e rota ficam de fora de propósito: exigiriam DOM e mock de
Supabase, e não é ali que mora o risco.
A animação também tem parte testável, quando a conta sai do olho e vira número:
coin-flight (a curva da moeda que voa até o contador de XP — o arco nunca mergulha por
baixo do header), frame-clock (o tempo que a cena 3D recebe do ticker do GSAP: acumulado
do zero e limitado, para que voltar de aba em segundo plano não faça a sala saltar),
neuro-sphere (a esfera da Neuro IA: distribuição pelo ângulo dourado, e o retorno das
partículas levando o mesmo TEMPO a 30, 60 ou 144 fps) e, no Escritório,
office-code-scroll e office-rain (a gota nunca escapa do vão do vidro).
O Escritório 3D tem um bloco à parte (office-bg, office-camera, office-celebration,
office-city, office-code-scroll, office-rain, office-snapshot, office-typing e
office-model). O office-model é de um tipo
diferente: ele mede a geometria da cena — se a mão do boneco pousa no teclado, se o
antebraço passa por cima da mesa. É o olho que falta, já que ninguém consegue ver um
render num teste. Rodam em Node puro: construir malhas do three.js não exige WebGL.
A loja cosmética do Escritório tem shop-sql: cruza o catálogo (lib/shop.ts) com os
insert dos .sql em supabase/ — item novo na loja sem a linha correspondente
no banco compilaria e apareceria na vitrine normalmente, e só falharia na hora da COMPRA
(ITEM_INEXISTENTE), sem nenhum teste de frontend pegando antes.
A config é vitest.config.mts — a extensão .mts é obrigatória, porque o Vite 7 é
ESM-only e o package.json não é type: module.
sharp, msedge-tts e esbuild precisam estar autorizados em
frontend/pnpm-workspace.yaml (allowBuilds). Sem isso o
pnpm install sai com exit 1 e o pré-check impede o pnpm dev de iniciar. O esbuild
é do Vitest: sem a aprovação, pnpm test não acha o binário nativo.node_modules entre pastas: os symlinks do pnpm são absolutos e quebram
(ex.: Cannot find module '@swc/helpers/...'). Rode pnpm install na pasta.Todas em frontend/.env.local (e nas envs do projeto na Vercel). O arquivo
frontend/.env.example tem o esqueleto completo.
| Variável | Para quê |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | URL do projeto Supabase |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Chave pública (aceita NEXT_PUBLIC_SUPABASE_ANON_KEY como fallback) |
SUPABASE_SERVICE_ROLE_KEY | Só no servidor. Bypass de RLS no dispatcher de push |
| Variável | Observação |
|---|---|
GROQ_API_KEY | Obrigatória. Sem ela a Neuro IA não sobe — o app avisa na tela. GROQ_MODEL opcional (llama-3.3-70b-versatile) |
NEURO_LIMITE_DIARIO · TRANSCRICAO_LIMITE_DIARIO | Opcionais. A cota da Neuro cresce com o nível (5/dia no nível 1, +1 por nível) até o teto NEURO_LIMITE_DIARIO (padrão 20), e há no máximo 3 mensagens por minuto; a transcrição tem teto fixo (padrão 40/dia). Contado por limite_ia.sql. Trocou de plano no Groq, sobe o teto aqui — sem SQL novo |
A mesma chave serve às duas coisas: o chat com ferramentas (criar/editar tarefas,
blocos e notas) e a transcrição de áudio (Whisper) do botão de microfone. A voz da
Neuro não usa provedor nenhum — é msedge-tts, local.
Não há provedor reserva, e é decisão, não pendência. Houve Gemini e Anthropic
aqui, numa lista de reservas que era um risco escondido: bastava o GROQ_API_KEY
faltar ou vir com um erro de digitação para o app inteiro rodar em outro modelo
sem ferramentas — a Neuro deixava de criar tarefas e continuava conversando
como se nada fosse. Quando o Groq recusa por cota, a tela diz quanto esperar (lido
do próprio 429) e o resto do app segue funcionando.
| Variável | Para quê |
|---|---|
NEXT_PUBLIC_VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY | Par VAPID do Web Push (npx web-push generate-vapid-keys) |
CRON_SECRET | Protege /api/push/dispatch. O mesmo valor vai dentro de push_cron.sql |
| Variável | Para quê |
|---|---|
OWNER_EMAIL | Seu e-mail. Libera /admin (feedbacks, usuários, erros, uso) e o painel de erros em Configurações. Sem ela /admin responde 404 para todo mundo, inclusive você |
| Variável | Para quê |
|---|---|
NEXT_PUBLIC_TURNSTILE_SITE_KEY | A Site Key do widget do Turnstile (pública). Sem ela, nenhum CAPTCHA aparece e o login segue como antes |
O login e o cadastro vão do navegador direto para o Supabase — um robô chama a API sem passar pela página, então só um CAPTCHA que o Supabase confere barra isso. Ligar tem ordem, e na ordem errada ninguém entra:
localhost, modo Managed).NEXT_PUBLIC_TURNSTILE_SITE_KEY na Vercel → novo deploy (variável
NEXT_PUBLIC_ entra no build). Conferir que o widget aparece em /login e que entrar funciona.Para testar local sem conta no Cloudflare: a chave de teste 1x00000000000000000000AA sempre
aprova, e a 2x00000000000000000000AB sempre recusa.
| Variável | Para quê |
|---|---|
NEXT_PUBLIC_OAUTH_PROVIDERS | Quais botões sociais aparecem em /login e /signup. Lista separada por vírgula: google, github, apple. Vazia ou ausente = nenhum botão, que é o padrão |
A ordem dos passos importa, e é fácil errar:
NEXT_PUBLIC_OAUTH_PROVIDERS.Invertendo, o botão aparece antes de funcionar — e falhar na tela de entrada é o jeito mais rápido de perder um usuário-teste. Por isso a env existe: sem ela o código não adivinha o que está configurado do outro lado.
O app/auth/callback/route.ts já trata o retorno (fluxo PKCE) e não precisa de mudança.
O Apple exige conta paga de Apple Developer (99 USD/ano); Google e GitHub são de graça.
| Variável | Para quê |
|---|---|
DEFAULT_TZ_OFFSET_MIN | Fuso de reserva para inscrição de push sem fuso próprio. Padrão 180 (Brasil, UTC−3) |
NEXT_PUBLIC_DEV_SUPABASE_REDIRECT_URL | Redirect de cadastro em desenvolvimento |
Não há ferramenta de migração: os scripts de supabase/ são rodados à mão no SQL Editor do Supabase (Dashboard → SQL Editor → New query → Run). Todos são idempotentes — reexecutar é seguro.
A ordem importa (há dependências entre eles). Do zero, rode nesta sequência:
1. Base — schema, tarefas, notas, realtime
fix_schema.sql · task_lists.sql · favorites.sql · notes.sql · day_notes.sql
reminders.sql · task_recurrence.sql · task_order.sql · task_meeting.sql · realtime.sql
notas_cor.sql
notas_cor.sql acrescenta a cor da nota (depende de notes.sql). Sem ele as notas
funcionam igual; só escolher uma cor falha, com um aviso dizendo qual arquivo rodar.
2. Gamificação e loja — gamification.sql cria o award_xp de que o resto depende
gamification.sql → xp_anticheat.sql → coins_shop.sql → foco_xp.sql · foco_cenas.sql · skins.sql · office_3d.sql · avatar_acessorios.sql · office_v4.sql · office_v5.sql · office_v6.sql · office_v7.sql
foco_xp.sql dá ao Modo Foco uma cota de XP própria (60/dia), fora do teto de 150 das
tarefas: +2 XP a cada 5 min focados e a tarefa concluída no foco valendo o dobro. Sem ele o
foco paga do mesmo jeito, só que pelo award_xp comum — dentro do teto de 150.
foco_cenas.sql põe na loja os nove ambientes pagos do Modo Foco (Correnteza 60 → Sinapses
600 moedas), comprados pela mesma buy_item do Escritório. Sem ele a vitrine e a prévia de 20 s
funcionam; só a compra recusa, avisando qual arquivo rodar, e não cobra nada. É idempotente:
ambiente novo entra rodando o arquivo de novo.
3. Copiloto de rotina
routine_profile.sql · routine_activities.sql · activity_log.sql
4. Social — cada um depende do anterior
friends.sql → social_v2.sql → friends_agenda.sql → friends_v3.sql → friends_v4.sql
friends_v4.sql é o que faz a lista de amigos desenhar o bonequinho de cada um: a RPC
my_friends passa a devolver avatar e acessórios de todo mundo de uma vez, em vez de a
tela fazer N chamadas a friend_office. Sem ele a lista ainda funciona — só volta a
mostrar a inicial no lugar do boneco.
5. Push — ⚠️ em push_cron.sql, substitua COLE_AQUI_O_CRON_SECRET pelo seu CRON_SECRET antes de rodar
push.sql → push_tz.sql → push_cron.sql
push_tz.sql guarda o fuso de cada aparelho. Sem ele, o dispatcher manda a notificação na
hora do Brasil para todo mundo — o lembrete aparece certo no app, só o push toca torto.
Quem já tinha push ligado antes precisa desligar e ligar de novo em Configurações: o
fuso é gravado na inscrição, então a inscrição antiga fica sem ele (e cai no padrão).
6. Foto de perfil — o bucket de Storage. Sem dependências
foto_perfil.sql
Cria o bucket avatars (público, 1 MB, só image/jpeg) e as políticas que amarram cada
arquivo ao dono pela primeira pasta do caminho (<uid>/perfil.jpg). Sem ele, Configurações
→ Perfil aceita escolher a imagem e falha no envio; o resto do app segue igual.
O endereço da foto não vira coluna: vai para o user_metadata do usuário, no mesmo
lugar em que o nome já mora, numa chave própria (foto_perfil). Não em avatar_url,
porque o Supabase mescla os dados do provedor no user_metadata a cada login social — ali
o próximo "entrar com Google" apagaria a foto escolhida.
7. Registro de erros e feedback — sem dependências, mas sem eles o /admin fica cego
error_log.sql · feedback.sql
error_log.sql guarda as falhas do navegador capturadas por /api/errors; feedback.sql,
o que chega pelo botão de feedback do app.
Os dois jeitos de o envio falhar têm a mesma solução — reexecutar
supabase/feedback.sql, que conserta sem apagar mensagem nenhuma:
| O que aparece | O que é |
|---|---|
Could not find the 'commit' column of 'feedback' | a tabela nasceu numa versão anterior e está sem colunas; o arquivo acrescenta o que falta |
violates check constraint "feedback_kind_check" | sobrou um CHECK antigo no kind, com uma lista de valores diferente da que o app usa hoje (bug/ideia/geral); o arquivo derruba o velho e recria o certo |
O segundo caso não vem deste repositório: nenhuma versão do feedback.sql criou esse
CHECK. Ele fica em bancos cuja tabela feedback foi criada à mão antes — e como
create table if not exists não mexe em tabela existente, ele sobrevivia a toda
reexecução. Agora o arquivo o derruba pela definição, não pelo nome, porque tabela
feita à mão pode ter batizado o constraint de outro jeito.
8. Integrações externas (só se for usá-las)
calendar_feed.sql
calendar_feed.sql liga o feed assinável (Configurações → "Assinar no Google/Outlook"). Sem dependências.
8b. Limite diário da IA por pessoa — sem dependências
limite_ia.sql
limite_ia.sql cria o contador que a Neuro e a transcrição consultam antes de ir ao Groq: a cota
do Groq é uma só para o app inteiro, e sem teto por pessoa uma conta esgota o dia de todos. Conta
por dia e por minuto. Sem ele, as duas rotas deixam passar e avisam no log ([cota-ia] ... não rodado); com a versão antiga dele (só por dia), vale o teto do dia. O teto vem da env.
9. Segurança do banco — por último, depois de todos os outros
seguranca_banco.sql
Fecha o que a auditoria de 09/10 achou aberto: o bucket avatars deixava qualquer um
listar as pastas (cujo nome é o id de cada pessoa) — a foto continua pública pela URL,
mas listar passa a ser só da própria pasta —, e as funções security definer deixam de
poder ser chamadas por quem não está logado (a purge_error_log fica só para o cron).
Também faz as funções futuras já nascerem fechadas — e é por isso que todo SQL rodado depois
dele pede rodar este de novo (ele é idempotente): é a reexecução que devolve a quem está
logado o direito de chamar a função nova. Sem ela, uma RPC nova responde "sem permissão"
(42501), e o app trata isso como falha, não como "função ainda não existe". Termina com uma conferência:
uma consulta que lista cada buraco que sobrar — tabela sem RLS, função sem search_path,
função chamável sem login, leitura aberta no bucket. Resultado vazio = tudo trancado.
Faxina do banco antigo (destrutivo; recomendado para quem tem um banco de antes de setembro)
faxina_legado.sql
Apaga o que sobrou de versões antigas e não existe em nenhum outro SQL desta pasta: o scaffold
FastAPI/Alembic (users, alembic_version), o bot do Telegram, a extensão de tempo de tela e a
função ai_consume com a tabela dela. Deixou de ser "opcional e inofensivo" em 17/10: a
ai_consume recebia o id da pessoa como parâmetro e qualquer conta logada a chamava com o id de
outra, e a alembic_version não tinha RLS. Nada no app depende delas, e quem começou do zero
nunca as teve (os if exists deixam rodar mesmo assim). Termina com uma conferência que tem de
voltar vazia. É o único script destrutivo da pasta; está separado dos outros por isso.
O caminho normal é o painel do dono em /admin (ver abaixo) — error_log guarda as
falhas do navegador por 30 dias. Direto pelo SQL Editor, se preferir:
select criado_em, origem, rota, mensagem, digest, commit_sha
from error_log order by criado_em desc limit 50;
/admin)Rota do próprio app com feedbacks, usuários (cadastro, último acesso, nível), erros
recentes e números de uso. O portão é do lado do servidor: quem não estiver logado
com o OWNER_EMAIL recebe 404 e nunca chega a receber os dados — não é só esconder da
tela. Lê tudo pela service role de propósito (a tabela feedback não tem policy de
select, e nenhum usuário deve ver dado de outro pelo app).
Não há link para /admin na navegação: é acesso por URL direta, para não anunciar a
existência do painel a quem usa o app.
http://localhost:3000/auth/callback
e o domínio de produção.token_hash para funcionar
cross-device — confirmar o e-mail no celular e voltar no desktop.Vercel, com a raiz do projeto apontando para frontend/. Replique as envs acima no
painel. O push depende do pg_cron do Supabase chamando /api/push/dispatch a cada
minuto — configurado por push_cron.sql, não por cron da Vercel.
security definer que valida amizade + flag."pt-BR""en-US"atalhos-neuroia-agoraia-duplicataia-conflitoicsiniciaisnivel-faixanota-corregiaorevelacao-respostaroutine-insightssaudacaotask-recurrenceregraParaBanconextOccurrencetime-format