Um PWA que segue o seu plano alimentar. Você importa a planilha da sua dieta — a que o nutricionista mandou, ou uma que você mesmo montou a partir do template — e o app passa a guiar o dia: qual é a próxima refeição, o que comer nela, quanto de água em cada período, quando tomar o suplemento. Um toque marca como feito; outro abre a refeição linha a linha e troca o que você não comeu — pela substituição que o plano prevê, por um alimento do catálogo, ou pelo que você escrever.
Além disso é um diário de nutrição e um registro de treino completos, para o que não está no plano.
sua planilha .xlsx → Importar → o app guia o dia
├── Plano prévia com ├── refeição da vez, expandida
│ Café da Manhã 7h-8h erros e ├── [Comi] grava e lança no diário
│ 💧 ÁGUA 8h-12h avisos ├── [Trocar] troca item a item
│ 🥤 CREATINA após almoço ├── água por período (+200/+500ml)
├── Macros └── aderência: 3 de 4 refeições
└── Substituicoes
Não tem planilha ainda? O app tem um botão de baixar o template (.xlsx com
aba de instruções, ou três .csv). Preencha com a sua dieta e importe.
O importador aceita o que gente escreve de verdade: 7h00 - 8h00,
das 12h às 13h, Após almoço, ~400 kcal, 1600-1800 kcal,
750ml (3-4 copos de 200ml), 3L/dia. Deixar a coluna REFEIÇÃO em branco
continua o bloco de cima — é assim que uma refeição ganha vários alimentos.
Plano alimentar
- 📥 Importação de
.xlsxe.csv, com prévia antes de gravar qualquer coisa - 📄 Template baixável, gerado no build e validado pelo próprio importador
- 🕐 Linha do tempo do dia com refeições, períodos de água e suplementos
- 🔄 Troca por item, não pela refeição inteira: cada linha do prato tem a sua substituição, e trocar todas é trocar a refeição. Vem do seu plano, do catálogo (com medida caseira e caloria calculada) ou do que você escrever — e continua disponível fora do horário e depois de marcada
- ✅ Aderência diária às refeições, e o "Comi" lança no diário o que tem alimento casado — o que não tem, a tela diz que não entra no balanço
Nutrição
- 🎯 Meta de calorias (ou faixa, quando o plano define uma) e macros
- 🍽️ Diário livre por refeição, com favoritas e "repetir"
- 📚 Catálogo folheável: tabela TACO e os seus, com busca que ignora acento — "acucar" acha "Açúcar" — e filtro por categoria
- 🏷️ Ficha do alimento com fibra, sódio e as medidas caseiras da POF/IBGE, cada uma com o peso e a caloria que ela vale
- 💧 Hidratação por período do plano, ou total do dia sem plano
Treino
- 🗂️ Uma tela com cinco abas: Hoje, Rotina, Progresso, Calistenia e Exercícios — as perguntas que se faz sobre treino
- 📅 Rotina por dia da semana — segunda é peito, e o app sabe disso
- 🎯 Sessão guiada: as séries já vêm com carga e reps; um toque registra
▶️ Iniciar e finalizar são explícitos. O treino nasce rascunho, você monta os exercícios com calma, e só entra no histórico quando você finaliza — sair da tela ou fechar o app não termina nada. Registrar uma série inicia sozinho, para "esqueci de apertar Iniciar" não custar a duração- 🔴 Faixa do treino em curso em qualquer tela, com o tempo correndo e as séries feitas; um toque volta para a academia
- 📂 Treinos abertos listados no "Hoje", de qualquer dia — o treino que ficou aberto ontem à noite continua lá, retomável, finalizável ou descartável. Nada fecha sozinho
- 📈 Dupla progressão: bateu o topo da faixa em todas as séries, a carga sobe
- 🏋️ 5/3/1 disponível como prescrição de qualquer exercício da rotina
- ⏱️ Cronômetro de descanso sempre na tela: começa sozinho na série, vibra e bipa ao zerar, ajusta em ±15s e sobrevive a fechar o app — ele conta pelo relógio, não por um contador que morre com a aba. A sessão também
- 🆕 Treino avulso em qualquer dia, com nome, mesmo com outro já aberto — e exercício novo entra até num treino já registrado
- ➕ Exercício fora da rotina entra no meio do treino, já com a carga que o histórico dele manda
- 🏃 Cardio é um item do treino como qualquer outro — na rotina ou no meio da sessão —, com kcal estimada por MET e peso, e ajustável quando o dia foi mais curto que o plano
- 📈 Progresso numa tela só: sessões com o prescrito ao lado do realizado, carga por exercício ao longo do tempo, consistência contra a rotina e séries por grupo muscular na semana
Calistenia
- 🤸 Aba própria, e no dashboard uma linha só com o resumo do dia e o
+— as séries soltas (flexão, agachamento, prancha) continuam a dois toques - 🎯 Meta diária opcional por exercício, e ela nasce do que você já faz
- 📊 Volume equivalente pela fração do peso corporal, recorde de série única e a tendência contra a média das quatro semanas anteriores
- 🔥 A caloria estimada entra no balanço energético, ao lado do cardio — e não conta como dia de rotina na consistência do treino
Ficha de exercício
- 🧍 175 exercícios pré-cadastrados, com passo a passo da execução
- 🩻 Mapa muscular: um desenho só, acendendo o músculo que faz o trabalho e os que também entram — funciona offline, sem imagem de terceiro
- 🔎 Busca por apelido: "supino" acha "Supino reto com barra", "bench" também
- 🔗 "Ver execução" no Google e no YouTube, com o termo já montado
- ✍️ Os seus exercícios têm os mesmos campos — inclusive equipamento e MET, para cadastrar um cardio próprio
Análise
- 📊 Nutrição, peso e atividade por semana, mês, ano ou período escolhido
- ⚖️ Balanço energético entre o que foi ingerido e o que foi gasto
Plataforma
- 📲 PWA instalável, com service worker que se atualiza sozinho
- 🔐 O cliente não manda SQL: chama operações pelo nome, e o dono vem do token
- 📱 Aparelhos pareados por um código de cinco minutos, com token próprio que só serve para enviar treino, peso e água — e que morre quando você desconecta
- 🎨 Tema claro e escuro, seguindo o do sistema quando você não escolheu
- ♿ Paleta com contraste WCAG AA verificado em teste, alvos de toque de 44px
telas / componentes → hooks (TanStack Query) → repositories → Turso (libSQL)
↕
domain/ — lógica pura, sem framework
| Pasta | O que vive lá |
|---|---|
src/domain/ |
Regra de negócio pura: parsers do plano, TMB/TDEE, macros, e1RM, kcal por MET. Testada isolada. |
src/domain/prescricao.ts |
Como a carga de hoje é decidida: dupla progressão, carga fixa, 5/3/1, cardio. Puro. |
src/domain/calistenia.ts |
A série que acontece fora da sessão: volume pela fração do peso corporal, caloria por MET, recorde e sequência de dias. Puro. |
src/domain/consistencia.ts |
"Estou seguindo a rotina?" — treinos por semana e dias desde a última vez. Puro. |
src/db/catalogo-exercicios.ts |
Os 175 exercícios com grupo, secundários, apelidos e execução. Conteúdo versionado; as invariantes dele são teste. |
src/components/treino/mapa-muscular.tsx |
O boneco. Um desenho para o catálogo inteiro, dirigido pelos nomes de muscle_groups. |
src/repositories/ |
Todo SQL. A única camada que fala com o banco. |
src/hooks/ |
Wrappers do TanStack Query. |
src/lib/planilha.ts |
A única camada que conhece o formato do arquivo importado. |
src/lib/api.ts |
O banco visto pelo app: operações por nome, tipadas a partir dos próprios repositórios. Junta as chamadas do mesmo tique num lote. |
api/_lib/registro.ts |
O que o cliente pode pedir, e de quem é cada dado. Nada fora daqui é alcançável. |
api/_lib/tokens.ts |
Bilhetes assinados de sessão e de dispositivo, e o código de pareamento. |
api/_lib/ingest-core.ts |
O que o celular pode mandar, e como isso vira linha no banco sem duplicar. |
src/components/ui/ |
Design system: Card, Progress, Stat, Segmented, Page… |
src/design/ |
Verificação de contraste da paleta (roda como teste). |
src/db/schema.sql |
Schema completo. |
plan_item_swaps |
A troca de UMA linha da refeição, num dia. A chave é o item — é isso que permite trocar o prato inteiro. |
Tokens em oklch no src/index.css. Todo par texto/fundo é verificado em
contraste WCAG AA por src/design/palette.test.ts — mudar uma cor sem manter o
contraste quebra a suíte de propósito. Quatro níveis tipográficos, monoespaçado
só em número que alinha em coluna, e alvos de toque de 44px (WCAG 2.5.8).
| Camada | Escolha |
|---|---|
| UI | React 19, React Router 7 |
| Dados | TanStack Query 5 |
| Banco | Turso / libSQL, acessado direto do navegador |
| Estilo | Tailwind CSS 4, primitivos Base UI, fonte Geist |
| Planilha | read-excel-file (leitura, sob demanda), write-excel-file (build) |
| Build | Vite 8, TypeScript 6, vite-plugin-pwa |
| Testes | Vitest 4, Testing Library, jsdom |
Pré-requisito: Node ≥ 22.
npm install
# 1. Um banco. Escolha um:
# (a) local, sem nuvem e sem token
turso dev --db-file local.db --port 8090
# (b) Turso na nuvem
turso db create macronaut && turso db show macronaut --url
# 2. Configure
cp .env.example .env.local
# DB_URL=http://127.0.0.1:8090 (local)
# DB_TOKEN=dev-local (qualquer valor no local)
# 3. Schema + seeds (TACO, medidas POF, exercícios, tipos de atividade)
npm run db:setup
# 4. Seu usuário
npm run create-user -- --email voce@exemplo.com --senha ****
# 5. Rode
npm run devO login chama /api/login, que em produção é uma função serverless
(api/login.ts). Em desenvolvimento, npm run dev serve a mesma rota por um
plugin do Vite (vite-plugin-login-dev.ts), reaproveitando a mesma função
authenticate — não precisa de vercel dev para entrar no app.
| Script | O que faz |
|---|---|
npm run dev |
Servidor de desenvolvimento |
npm run build |
Gera o template, checa tipos e builda para dist/ |
npm run build:template |
Só o template — e valida o resultado pelo importador |
npm test |
Roda a suíte inteira |
npm run db:setup |
Aplica o schema e os seeds |
npm run create-user |
Cria um usuário |
npm run db:limpar |
Apaga os dados de uso, preservando login e catálogos |
npm run db:limpar apaga o que a pessoa registrou — diário, plano, treinos,
pesagens, água, conversas com a IA — e preserva o login, a TACO, as medidas
da POF e os 175 exercícios do catálogo. Recriar o banco levaria minutos de seed
para jogar fora conteúdo que não é de ninguém.
Ele é dry-run por padrão: sem --confirmar só conta e mostra a tabela.
npm run db:limpar # relatório, não apaga nada
npm run db:limpar -- --confirmar # executa
npm run db:limpar -- --email voce@exemplo.com --confirmar # só um usuário
npm run db:limpar -- --confirmar --sem-refeicoes # sem recriar as refeições padrãoPara outro banco que não o do .env.local (produção, por exemplo), passe as
variáveis na frente:
DB_URL=libsql://... DB_TOKEN=... node --experimental-strip-types scripts/limpar-dados.tsA regra do que é dado de uso e o que é conteúdo mora em
scripts/lib/limpar-dados.ts, e é o único código do repositório que apaga em
lote — por isso tem teste próprio, que povoa todas as tabelas que a limpeza
toca e confere o que sobrou.
O cliente não manda SQL, e não conhece o banco. O login devolve um bilhete
assinado (AUTH_SECRET, HMAC-SHA256) que vale 30 dias. O app chama operações
pelo NOME em /api/rpc; quem escolhe a consulta é o servidor, e o user_id
vem do token — forjar dono não é possível por construção.
Houve uma rota /api/db que aceitava SQL do cliente. Ela existiu enquanto os
19 módulos migravam, e foi removida no fim: enquanto estava lá, uma sessão
válida alcançava a linha de qualquer usuário.
O celular tem escopo próprio e ainda menor: o token dele vive dentro de um APK
distribuído e não expira por tempo, então ele fala só com /api/ingest — diz
"corri 30 minutos", e o servidor decide o que isso vira.
- ✅ Use um token do Turso restrito a este banco.
- ✅ Defina
AUTH_SECRET(32 bytes aleatórios) na Vercel. Sem ela o servidor recusa subir — um segredo com valor padrão é um segredo que ninguém troca. ⚠️ foodsefood_measuresnão têm coluna de dono. O catálogo de alimentos é compartilhado por desenho neste app, inclusive os que você cadastrou: qualquer sessão lê e edita. Dar posse a eles é mudança de produto, e está anotada no plano de migração.
- Proxy serverless para o token do Turso
- Repositórios no servidor: o cliente chama operações pelo nome, e o
user_idvem do token - Dono para o catálogo de alimentos (
foods,food_measures) - App Android: TWA + Health Connect, para o Samsung Health entrar sozinho
(o backend já está pronto — ver
docs/superpowers/specs/2026-08-31-samsung-health-design.md) - Edição de bloco do plano dentro do app (hoje a planilha é a fonte)
- Casamento automático dos itens do plano com o catálogo de alimentos
- Fila para as medidas caseiras da POF que esperam desambiguação
- Planos com variação por dia da semana
- Exportar / backup
MIT — veja LICENSE.