Personal finance tracking app focused on clarity: track spending, income, credit card bills, and installments in the right month, with a mobile-first UI and a strong "you own your data" stance (imports/exports).
The product UI is primarily in pt-BR (see messages/pt-BR.json) with a secondary messages/en.json.
- Expenses, income, and transfers
- Credit card bills ("faturas") with closing/due dates
- Installments: one
transaction-> many monthlyentries - Budgets by category (monthly)
- Imports (CSV/OFX) and exports (CSV)
- PWA experience (Serwist)
- Next.js (App Router), React, TypeScript
- Drizzle ORM + Postgres (local Docker or Supabase)
- Tailwind CSS + shadcn/ui + Hugeicons
- Auth.js / NextAuth
- next-intl for i18n
- Vitest (unit) and Playwright (e2e)
Prereqs:
- Node + pnpm (repo uses
pnpm) - Docker (recommended for local Postgres)
- Install deps
pnpm install- Start Postgres (Docker)
docker compose -f compose.yml up -d- Configure env
cp .env.example .envMinimum for local auth:
NEXTAUTH_URL=http://localhost:3000NEXTAUTH_SECRET=...(generate withopenssl rand -base64 32)- Turnstile: you can use Cloudflare test keys from
.env.example
- Run migrations (local)
pnpm db:setup- Start the dev server
pnpm devpnpm lint
pnpm build
pnpm build:clean
pnpm test
pnpm test:run
pnpm test:coverage
pnpm test:e2e
pnpm db:migrate:local
pnpm db:seed
pnpm db:resetRequired secrets for production deployment and backups:
Database (migrations + backups):
SUPABASE_DB_DIRECT_URL- Direct connection URL with port 5432 (session mode, NOT pooler)- Format:
postgresql://postgres.<ref>:<password>@db.<ref>.supabase.co:5432/postgres
- Format:
Vercel (deployment):
VERCEL_TOKENVERCEL_ORG_IDVERCEL_PROJECT_ID
Cloudflare R2 (database backups):
R2_ACCOUNT_ID- Your Cloudflare account IDR2_BUCKET_NAME- Name of the R2 bucket for backupsR2_ACCESS_KEY_ID- R2 API token access keyR2_SECRET_ACCESS_KEY- R2 API token secret key
Backups run daily at 6am UTC (3am BRT) and are stored in R2 (free tier: 10GB storage).
- Money is stored as integer cents. Use
centsToDisplay()/displayToCents()fromlib/utils.ts. - Installments follow the pattern: a single
transactionsrow -> multipleentriesrows (one per month). - Schema lives in
lib/schema.ts. - Drizzle config:
drizzle.config.ts.
- Tests use Portuguese UI text selectors (not test IDs) to validate translations in production.
- Specs:
test/e2e/*.spec.ts.
This repo uses bd (beads) for issue tracking:
bd ready
bd show <id>
bd update <id> --status in_progress
bd close <id>
bd sync- Keep user-facing strings in
next-intlmessages (pt-BR is primary). - Prefer accessible selectors and Portuguese text in e2e tests.
- Avoid changing money units: always store cents.