Self-hosted personal finance for people who care about privacy, clarity, and control.
Track transactions, plan cash flow, manage investments, and chat with your data β all on your own infrastructure.
Most finance apps trade your privacy for convenience. Vision gives you both:
- Privacy-first β your financial data never leaves your environment
- Self-hosted β run the native Electron desktop app or the source stack with PostgreSQL 18
- Complete β transactions, budgeting, portfolio analytics, Belgian tax, AI chat, and net worth in one place
- Developer-friendly β TypeScript/React + Node.js/Express in a clean Bun monorepo with an OpenAPI spec
- Import CSV exports from Belfius, Revolut, KBC, SABB, Wise, ING, BNP Paribas, your own Vision backup, or a generic CSV mapper
- Fast filtering, search, and pagination via a materialized aggregations layer
- Deduplication, categorization rules, and recurring pattern detection
- Transaction splits and manual entry
- Attachments per transaction
- Export to CSV or Vision backup format
- Categories and recipients with rules, merging, and exclusions
- Planned/recurring payments with forecasting and execution history
- Dashboard widgets for account-level visibility and cash position tracking
- Saved chart configurations
- Track stocks, crypto, real estate, savings, bonds
- Price providers: Yahoo Finance, Binance, Kinesis, and custom JSON endpoints
- Currency conversion via ECB with fallback rate sources
- Net worth and performance over time with portfolio snapshots
- Market lookup and watchlist for decision support
- PDF report export (portfolio + tax summary)
- Local AI assistant powered by Ollama β no data sent to third-party LLMs
- Query your transactions, categories, and financial data in natural language
- Tool-augmented responses with structured result cards
- Modern UI built on Radix UI / shadcn patterns + Tailwind CSS
- English and Dutch (
nl) localization - Offline-resilient β online status detection gates market queries, disables refresh controls gracefully
- Secure backup/restore with AES-256-GCM encryption (per-backup salt)
- Desktop app via Electron with bundled PostgreSQL 18 and a native Bun backend
Install the release DMG. The application contains PostgreSQL 18, the migration runner, the Bun backend, the production frontend, and the browser used for PDF reports. A running Homebrew PostgreSQL service is not required.
To build the same application from source, first provide Bun, Node.js, a PostgreSQL 18.6 distribution from Postgres.app or Homebrew, and a Python build environment containing the pinned requirements and PyInstaller 6.22.2. The PostgreSQL service does not need to be started. Then run:
git clone https://github.com/EraPartner/Vision.git
cd Vision
./install.shAfter installation, open Vision from /Applications/Vision.app:
open /Applications/Vision.appVision creates a private, loopback-only database under its macOS application-data
directory on first launch. See
docs/guides/native-macos-runtime.md for
data migration and rollback.
For a fully isolated application with deterministic synthetic data, build and install Vision Demo:
./install-demo.sh
open "/Applications/Vision Demo.app"Vision Demo uses its own bundled native PostgreSQL runtime below
~/Library/Application Support/Vision Demo/native/vision_demo. It cannot access the real Vision
database. Restore its canonical dataset with
bun run demo:reset-native, then quit and reopen the Demo app.
Both macOS installers build the production frontend in a private temporary directory and remove
that staging directory on exit. They do not depend on, reuse, or clear the repository's shared
dist directory.
git clone https://github.com/EraPartner/Vision.git
cd Vision
bun install
bun run native:prepare # one-time native PostgreSQL/migration/PDF payload
bun run dev # start private PostgreSQL, backend, and frontendnative:prepare needs PostgreSQL 18.6 build files and the pinned Python build
dependencies, but it never starts the external PostgreSQL service.
| Service | URL |
|---|---|
| Frontend | http://localhost:8080 (auto-picks next free port if busy) |
| Backend API | http://localhost:3002 |
Vision/
βββ apps/
β βββ frontend/ # React 19 + TypeScript + Vite
β β βββ src/
β β βββ features/ # Feature modules (transactions, categories, imports, ai-chatβ¦)
β β βββ components/ # Shared UI components
β β βββ hooks/ # Custom React hooks
β β βββ stores/ # Client state (Zustand)
β β βββ locales/ # Generated i18n files (en, nl)
β βββ node-backend/ # Express API (Bun runtime)
β βββ src/
β βββ routes/ # REST endpoints
β βββ services/ # Business logic, price providers, bank adapters
β βββ repositories/ # Data access layer
β βββ integrations/ # Ollama AI client
β βββ middleware/ # Auth, logging, error handling
βββ packages/
β βββ shared-utils/ # Pure helpers (money, slugify, downsample) shared by backend + frontend
β βββ types/ # Shared TypeScript types (generated from openapi.yaml)
βββ packaging/
β βββ electron/ # Desktop wrapper
βββ alembic/ # PostgreSQL migrations
βββ i18n/source/ # i18n source files β compiled to apps/frontend/src/locales/
βββ scripts/ # Locale generation, validation, sync tooling
βββ docs/ # Obsidian knowledge base (ADRs, API docs, feature specs)
βββ openapi.yaml # REST API contract (source of truth for types)
βββ config/ # Alembic config
# Development
bun run native:prepare # one-time private PostgreSQL/migration/PDF payload
bun run dev # private PostgreSQL + watched backend + Vite
bun run backend # backend only; requires an explicit database config
# Building
bun run build # production frontend build (generates locales first)
bun run build:dev # dev-mode frontend build
bun run preview # preview production build
bun run dist # build + package Electron .app
bun run demo:reset-native # request a canonical synthetic Demo reset on next launch
# Linting & types
bun run lint # frontend ESLint
bun run lint:backend # backend ESLint
bun run typecheck # frontend TypeScript typecheck
# Testing
bun run test # backend Vitest suite
bun run test:db # backend suite with a private temporary PostgreSQL 18
bun run test:frontend # frontend Vitest suite
bun run test:all # backend + frontend (concurrent)
bun run test:coverage # frontend coverage report
bun run test:watch # backend watch mode
bun run test:e2e # frontend Playwright end-to-end tests
bun run test:e2e:visual # frontend visual-regression tests
# Database (Alembic / PostgreSQL)
bun run db:upgrade # apply all pending migrations
bun run db:downgrade # destructive maintenance only; never run on live data
bun run db:current # show current revision
bun run db:history # show migration history
bun run db:stamp # expert recovery only; does not run migrations
bun run db:revision # create a new autogenerate migration
bun run db:index-stats # report index usage stats
bun run db:precision-drift # check for numeric precision drift
bun run quotes:densify # backfill/densify asset price history
# Electron
bun run electron:dev # native desktop with isolated development data
bun run electron:prod # native desktop production shell
# i18n
bun run generate-locales # compile i18n source β locale files
bun run sanitize-locales # sanitize locale files without recompiling
bun run validate-locales # check locale completeness
bun run sync-nl # sync Dutch locale from English source
# Types & API
bun run generate:types # regenerate TypeScript types from openapi.yaml
bun run check-endpoint-matrix # verify docs endpoint matrix matches openapi.yaml| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript, Vite, Tailwind CSS, Radix UI, shadcn/ui, TanStack Query, TanStack Table |
| Backend | Node.js (Bun runtime), Express |
| Database | PostgreSQL 18.6; bundled for Electron and externally supplied for source development |
| Desktop | Electron |
| AI | Ollama (local LLM) |
| Testing | Vitest (frontend + backend) |
| Packaging | Native Electron DMG/ZIP and GitHub Actions release workflow |
| API spec | OpenAPI 3.x (openapi.yaml) |
| Adapter | File |
|---|---|
| Belfius | belfius.js |
| Revolut | revolut.js |
| KBC | kbc.js |
| ING | ing.js |
| BNP Paribas Fortis | bnp.js |
| SABB | sabb.js |
| Wise | wise.js |
| Vision backup | vision.js |
| Generic CSV mapper | generic.js |
| Provider | Asset class |
|---|---|
| Yahoo Finance | Stocks, ETFs, indices |
| Binance | Crypto |
| Kinesis | Precious metals (gold, silver) |
| Custom JSON endpoint | Any asset via configurable URL + path |
Native Vision generates database credentials in its restricted application-data directory. Do not
create a database URL for the packaged app. Copy .env.example to .env only for source
development provider keys and overrides.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Source only | PostgreSQL connection string |
LOG_LEVEL |
No | debug / info / warn / error (default: warn) |
ENABLE_LOGGING |
No | Toggle logging output (true / false) |
The native Electron runtime writes
runtime.envwith restrictive permissions and separate administrator, migration-owner, and application credentials.
The full REST API is documented in openapi.yaml. TypeScript types are generated from it:
bun run generate:types # β apps/frontend/src/types/generated.tsEndpoint categories: transactions, categories, recipients, imports, investments, portfolio, planned payments, splits, attachments, saved charts, aggregations, reports, market lookup, watchlist, settings, admin, AI chat.
- Fork and create a feature branch from
main - Write tests first (the project follows TDD) β run
bun run test:allbefore opening a PR - Run
bun run lintandbun run lint:backendto catch style issues - Open a pull request with a clear summary and rationale
When adding new adapters, endpoints, or env vars, update openapi.yaml, regenerate types, and update the relevant docs in docs/.
Tag-driven releases (vX.Y.Z) trigger GitHub Actions to build and push release artifacts (container images + Electron packages) and publish a GitHub Release.
Workflow: .github/workflows/release.yml
- Never commit real
.envfiles or secrets - Keep your deployment private and access-controlled
- Backups are encrypted with AES-256-GCM (per-backup random salt)
- Dependency and container images should be reviewed and updated regularly
- AI chat uses a local Ollama instance β no financial data leaves your network
Licensed under AGPL-3.0-only. See LICENSE.