Trackrr
Gestão de despesas pessoais com orçamento mensal por categoria — API REST + front Next.js.
Back-end (API)
- Express 5
- TypeScript
- Prisma 7
- PostgreSQL
- Zod
- JWT
- bcryptjs
- Pino
- Vitest
- Supertest
Front-end
- Next.js 16
- React
- TypeScript
- TanStack Query
- Zustand
- Axios
- Zod
Full-screen para maior qualidade.
Contexto
Trackrr é um sistema de gestão de despesas pessoais com controle de orçamento mensal por categoria. O usuário cadastra categorias, registra despesas e define um teto por categoria. O dashboard mostra gasto vs. orçamento em tempo real, sempre derivado a partir das despesas — nunca armazenado. Exportação em PDF (via @react-pdf/renderer no client) e CSV (sem lib, gerado em código direto).
O back-end segue arquitetura em camadas estrita com Express 5, Prisma 7 e PostgreSQL. Valores monetários usam Decimal(12,2) serializado como string no JSON. Suíte de testes executa 79 testes em ~1 segundo com Prisma mockado, sem dependência de banco.
O front-end usa Next.js 16 com TanStack Query para estado de servidor e Zustand exclusivamente para auth. Autenticação dual: JWT no header via interceptor Axios + cookie espelho para o middleware edge. Organização por feature, não por tipo de arquivo.
Decisões técnicas
API · Arquitetura em camadas estrita
A aplicação segue Routes → Controllers → Services → Repositories, com cada camada possuindo uma única responsabilidade. Controllers não acessam o Prisma, services não manipulam req/res, e repositories não contêm regras de negócio. Dependências fluem em uma única direção.
Repositories podem ser mockados para testar services em isolamento; o Prisma client pode ser mockado para testar rotas end-to-end. Regras de negócio ficam nos services, validações nos schemas, e mudanças de persistência não vazam para o restante do sistema.
API · Decimal para valores monetários
Todos os campos monetários usam Decimal(12,2) no Prisma e são serializados como string no JSON (“12.50” em vez de 12.5). Evita problemas de precisão do IEEE 754 — 0.1 + 0.2 === 0.30000000000000004 em JavaScript — que acumulam erros em operações sobre orçamento.
Serializar como string preserva a precisão até o consumidor, que pode optar pela representação adequada ao seu contexto (libs como decimal.js no front-end, BigInt para cálculos exatos, ou conversão para float quando precisão não é crítica).
API · Estratégia de testes com Prisma mockado
A suíte (Vitest + Supertest) executa 79 testes em ~1 segundo sem dependência de banco em execução. O Prisma client é mockado via vi.mock, e cada teste configura explicitamente o comportamento dos métodos consumidos. Cobertura inclui rotas, middlewares, services, mappers — toda a stack acima da camada de persistência.
Trade-off: bugs de SQL ou migrations quebradas não são detectados aqui. A camada complementar seria testes de repository contra Postgres real (testcontainers) no pipeline de CI.
Front · Zustand para auth, TanStack Query para o resto
Estado de UI e estado de servidor são tratados por ferramentas distintas. Server state usa TanStack Query — cache, invalidação, refetch e dedup de requests em flight.
Zustand entra só onde Query não cabe: o par { token, user } da auth, que precisa ser síncrono, persistir em localStorage e ser lido fora de componente (interceptor do Axios). Server state e client state ficam em camadas distintas.
Front · Arquitetura por feature, não por tipo
features/expenses/ agrupa tudo da feature: api.ts, hooks.ts, schemas.ts, types.ts, components/. A pasta app/ fica fina — cada página é composição desses hooks e components.
Regra: features não importam umas das outras. Qualquer coisa transversal vai para shared/. O blast radius de qualquer mudança fica contido na pasta da feature.
Front · PDF gerado no client, não no servidor e com lazy import
Caminho mais fácil seria adicionar Puppeteer/Playwright na API Express e renderizar PDF no back — pixel-perfect, qualquer CSS funciona, mas o custo seria muito alto.
@react-pdf/renderer no client: componentes JSX viram PDF binário direto no navegador, sem rasterizar DOM (que é o que html2canvas faz, e fica pixelado). API fica desacoplada do formato — se amanhã precisar exportar para Excel ou Markdown, é só adicionar outro módulo em features/export/, sem mexer no back.
Rodar localmente
Necessário: Docker e Git instalados.
mkdir trackrr-local && cd trackrr-local
git clone https://github.com/odgiedev/trackrr
git clone https://github.com/odgiedev/trackrr-api
cp trackrr/.env.example trackrr/.env
cp trackrr-api/.env.example trackrr-api/.env
# Terminal 1 — API
cd trackrr-api && docker compose up
# Terminal 2 — Front
cd trackrr && docker compose up