Front-end do controle de despesas pessoais. Next.js consumindo a API REST (trackrr-api). O usuário cadastra categorias, registra despesas e define orçamentos mensais por categoria; o dashboard mostra gasto vs. orçamento no mês selecionado, em barras ou pizza.
- Next.js 16 (App Router, React 19, Turbopack)
- TypeScript strict
- Tailwind CSS 4
- TanStack Query v5 (server state)
- Zustand (auth: token + user)
- React Hook Form + Zod (formulários)
- Axios com interceptors (JWT + 401 redirect)
- Recharts (dashboard)
- Lucide (ícones)
Organização por feature, não por tipo de arquivo:
src/
├── app/
│ ├── (auth)/ rotas públicas: /login, /register
│ └── (dashboard)/ rotas protegidas: /dashboard, /expenses, /categories, /budgets
├── features/
│ ├── auth/ api.ts, store.ts (Zustand), hooks.ts, schemas.ts, components/
│ ├── categories/
│ ├── expenses/
│ └── budgets/
├── shared/
│ ├── api/client.ts Axios + interceptors
│ ├── components/ Button, Input, Modal, Sidebar, Header, etc.
│ ├── lib/ format.ts, cn.ts, zod-pt.ts
│ ├── providers/ QueryProvider
│ └── types/ ApiResponse<T>, PaginatedResponse<T>, ApiError
├── proxy.ts Middleware do Next 16 (redirects de auth)
└── env.ts Validação de env via Zod
Regra: features não importam umas das outras. Tudo compartilhado vai para shared/.
Requer Docker e Docker Compose. A API (trackrr-api) precisa estar acessível.
cp .env.local.example .env.local
docker compose up --buildAplicação em http://localhost:3000.
Se a API roda no host (fora de container), o compose já adiciona host.docker.internal:host-gateway — aponte NEXT_PUBLIC_API_URL=http://host.docker.internal:3333.
| Variável | Default | Observações |
|---|---|---|
NEXT_PUBLIC_API_URL |
http://localhost:3333 |
URL base da API |
Validada em src/env.ts com Zod no boot. NEXT_PUBLIC_* é inlineado em build time — trocar a URL exige rebuild.
| Rota | Auth | Descrição |
|---|---|---|
/login, /register |
— | Autenticação |
/dashboard |
sim | Gasto vs. orçamento do mês (barras/pizza) |
/expenses |
sim | Lista e criação de despesas |
/categories |
sim | CRUD de categorias |
/budgets |
sim | Orçamentos mensais por categoria |
Estado: Zustand só para auth (token + user em localStorage, espelhado em cookie pro middleware). React Query para dados da API; mutations invalidam as keys relacionadas. Valores monetários chegam como string (Decimal) e só viram Number no display.
Contexto e trade-offs das principais escolhas (estado por feature, auth dual, dinheiro como string): devdiegofernandes.com/projects/trackrr
MIT