A finance tracking app that parses bank PDF ledgers, categorizes transactions with smart suggestions, and displays data in an interactive dashboard.
- Privacy-first: All data stays local in a SQLite database
- Multi-user support: User authentication with secure session management
- Multi-workspace: Organize finances into separate workspaces with role-based access (owner, editor, viewer)
- Collaboration: Invite users to workspaces via username or email
- Multilingual: English and Portuguese UI with user locale preference
- Password reset: Reset your password via email
- Workspace backup/restore: Export and import workspace data
- Error handling: Structured error codes, session expiry detection, React error boundaries
- PDF parsing: Extract transactions from Novo Banco and CGD monthly statements (extensible to other banks)
- Smart categorization: Pattern-based category suggestions with user-defined categories
- Dashboard: View data by year, month, and category with charts
- Financial reports: Annual and monthly reports with visualizations
- Recurring detection: Automatic detection and management of recurring transactions
- Bank-agnostic architecture: Support for multiple banks with bank-specific patterns
- Frontend: React + TypeScript + Vite + react-i18next
- UI: Tailwind CSS + Recharts
- Backend: Node.js + Express
- Database: SQLite (better-sqlite3)
- PDF Parsing: pdfjs-dist
compasso/
βββ apps/
β βββ web/ # React frontend
β βββ api/ # Node.js backend
βββ packages/
β βββ shared/ # Shared types & constants
βββ data/ # SQLite database (gitignored)
βββ uploads/ # Temporary PDF uploads (gitignored)
- Node.js 18+
- npm 9+
# Install dependencies
npm install
# Build shared package
npm run build -w @compasso/shared# Run both frontend and backend in development mode
npm run dev- Frontend: http://localhost:5180
- Backend: http://localhost:5181
Create a .env file in the root or apps/api directory:
# Server configuration
PORT=5181
HOST=127.0.0.1
NODE_ENV=development
# CORS configuration (comma-separated origins for production)
ALLOWED_ORIGINS=http://localhost:5180,http://127.0.0.1:5180
# Database path (optional, defaults to ./data)
DATABASE_PATH=./data
# Email β optional, used for password reset emails (see below)
# Option 1: SMTP (any provider)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=user@gmail.com
SMTP_PASS=app-password
SMTP_FROM=noreply@yourdomain.com
# Option 2: Resend
RESEND_API_KEY=re_xxxxxxxxxxxx
EMAIL_FROM=noreply@compasso.appPassword reset emails require an email transport. Without configuration the app runs normally but password reset will not send emails. Configure one of the following options:
Works with Gmail, Mailgun, SES, self-hosted, or any SMTP server.
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587 # defaults to 587
SMTP_SECURE=false # true for port 465
SMTP_USER=user@gmail.com
SMTP_PASS=app-password
SMTP_FROM=noreply@yourdomain.comSMTP_FROM defaults to noreply@compasso.app if not set.
Uses the Resend REST API.
- Create an account at resend.com
- Generate an API key from the dashboard
- Verify a sending domain (or use the sandbox domain for development)
- Set the environment variables:
RESEND_API_KEY=re_xxxxxxxxxxxx
EMAIL_FROM=noreply@yourdomain.comEMAIL_FROM defaults to noreply@compasso.app if not set.
If both are configured, SMTP takes priority.
npm run build# Build and run with Docker Compose
docker compose up -d
# Rebuild after code changes
docker compose up -d --buildEnvironment variables are read from a .env file in the project root.
- Create an account: Register a new user account on the login page
- Create a workspace: Set up a workspace for your finances (one is created by default)
- Upload a statement: Go to the Upload page and select your bank, then drag & drop a PDF statement
- Review transactions: Review the parsed transactions and adjust categories as needed
- View dashboard: See your financial overview with charts and statistics
- Manage categories: Add custom categories and patterns for auto-categorization
- View reports: Access annual and monthly financial reports
- Track recurring: View and manage detected recurring transaction patterns
- Novo Banco (Portugal) - "Extrato Integrado" PDF format
- CGD (Caixa Geral de DepΓ³sitos) (Portugal)
The project uses a registry pattern β only 3 files need to be touched:
- Create a parser in
apps/api/src/parsers/<bank-slug>.ts(exports aBankParserDefinition) - Register it in
apps/api/src/parsers/registry.ts(1 import + 1 array entry) - Write tests in
apps/api/src/parsers/<bank-slug>.test.ts
See .github/BANK_PARSER_GUIDE.md for the full contributor guide.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/register | Create new user account |
| POST | /api/auth/login | Authenticate user |
| POST | /api/auth/logout | End user session |
| GET | /api/auth/me | Get current user info |
| PUT | /api/auth/profile | Update user profile |
| PUT | /api/auth/password | Change password |
| POST | /api/auth/forgot-password | Request password reset email |
| POST | /api/auth/reset-password | Reset password with token |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/workspaces | List user's workspaces |
| POST | /api/workspaces | Create workspace |
| GET | /api/workspaces/:id | Get workspace details |
| PUT | /api/workspaces/:id | Update workspace |
| DELETE | /api/workspaces/:id | Delete workspace |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/workspaces/:id/members | List workspace members |
| PUT | /api/workspaces/:id/members/:userId | Change member role |
| DELETE | /api/workspaces/:id/members/:userId | Remove member |
| POST | /api/workspaces/:id/invitations | Invite user to workspace |
| GET | /api/workspaces/:id/invitations | List pending invitations |
| GET | /api/invitations | My pending invitations |
| POST | /api/invitations/:id/accept | Accept invitation |
| POST | /api/invitations/:id/decline | Decline invitation |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/dashboard | Dashboard summary data |
| GET | /api/dashboard/years | Available years with data |
| GET | /api/reports/yearly | Annual financial report |
| GET | /api/reports/category-trends | Category trends report |
| GET | /api/reports/years | List available report years |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/transactions | List transactions (with filters) |
| GET | /api/transactions/export | Export transactions as CSV |
| POST | /api/transactions/confirm | Save parsed transactions |
| PUT | /api/transactions/:id | Update transaction category |
| DELETE | /api/transactions/:id | Delete transaction |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/upload | Upload and parse PDF |
| GET | /api/upload/banks | List supported banks |
| GET | /api/upload/ledgers | List uploaded ledgers |
| DELETE | /api/upload/ledgers/:id | Delete ledger |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/categories | List categories |
| POST | /api/categories | Create category |
| GET | /api/categories/:id | Get category with patterns |
| PUT | /api/categories/:id | Update category |
| DELETE | /api/categories/:id | Delete category |
| POST | /api/categories/:id/patterns | Add pattern to category |
| POST | /api/categories/:id/patterns/quick | Create quick pattern |
| DELETE | /api/categories/:id/patterns/:patternId | Delete pattern |
| GET | /api/categories/patterns/exists | Check if pattern exists |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/recurring | List recurring patterns |
| POST | /api/recurring/detect | Detect recurring patterns |
| PUT | /api/recurring/:id | Toggle pattern active status |
| GET | /api/recurring/:id/transactions | List pattern transactions |
| DELETE | /api/recurring/:id | Delete recurring pattern |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/backup/export | Export workspace data |
| POST | /api/backup/import | Import workspace data |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health | Health check |
# Run all tests
npm test
# Run tests with coverage
npm test -- --coverageTests use Vitest and cover parsers, services, middleware, and error handling.