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 on Docker Compose or as a native Electron desktop app
- 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, 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 Docker-managed backend
The install.sh script sets up everything from scratch β Homebrew, Docker Desktop, Bun, dependencies, and a .app launcher:
git clone https://github.com/EraPartner/Vision.git
cd Vision
./install.shAfter installation, double-click the Launch Vision.command shortcut or run:
bun run electron:prodDocker Desktop must be running. On first launch, Vision generates
.envwith a secure random password automatically.
git clone https://github.com/EraPartner/Vision.git
cd Vision
cp .env.example .env
# Generate a secure password and set it in both fields in .env
openssl rand -hex 32
docker compose up -dOpen http://localhost:3002 in your browser.
docker compose down # stop
docker compose down -v # stop and remove all datagit clone https://github.com/EraPartner/Vision.git
cd Vision
bun install
cp .env.example .env # edit as needed
bun run docker:dev # start Postgres + backend via Compose
bun run dev # start frontend + backend in watch mode| Service | URL |
|---|---|
| Frontend | http://localhost:5174 |
| Backend API | http://localhost:3002 |
Vision/
βββ apps/
β βββ frontend/ # React 18 + 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/
β βββ 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 dev # frontend + backend in watch mode (concurrent)
bun run backend # backend only
# 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
# Linting
bun run lint # frontend ESLint
bun run lint:backend # backend ESLint
# Testing
bun run test # backend Vitest suite
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
# Database (Alembic / PostgreSQL)
bun run db:upgrade # apply all pending migrations
bun run db:downgrade # revert one migration
bun run db:current # show current revision
bun run db:history # show migration history
bun run db:stamp # stamp DB at head without running migrations
bun run db:revision # create a new autogenerate migration
# Docker
bun run docker:dev # start Compose dev stack
bun run docker:dev:down # stop dev stack
bun run docker:dev:rebuild # rebuild and restart dev stack
bun run docker:clean # start clean Compose stack (fresh build)
bun run docker:clean:down # stop clean stack
bun run docker:clean:reset # wipe volumes + restart clean stack
bun run docker:logs # tail app logs
# Electron
bun run electron:dev # desktop dev mode
bun run electron:prod # desktop production mode
bun run electron:clean # desktop with clean Compose override
# i18n
bun run generate-locales # compile i18n source β locale files
bun run validate-locales # check locale completeness
bun run sync-nl # sync Dutch locale from English source
# Types
bun run generate:types # regenerate TypeScript types from openapi.yaml| Layer | Technology |
|---|---|
| Frontend | React 18, TypeScript, Vite, Tailwind CSS, Radix UI, shadcn/ui, TanStack Query, TanStack Table |
| Backend | Node.js (Bun runtime), Express |
| Database | PostgreSQL 18 (Alpine), Alembic migrations |
| Desktop | Electron |
| AI | Ollama (local LLM) |
| Testing | Vitest (frontend + backend) |
| Packaging | Docker Compose, GitHub Actions release workflow |
| API spec | OpenAPI 3.x (openapi.yaml) |
| Adapter | File |
|---|---|
| Belfius | belfius.js |
| Revolut | revolut.js |
| KBC | kbc.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 |
Copy .env.example to .env and fill in the required values.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
β | PostgreSQL connection string |
POSTGRES_PASSWORD |
β | DB password for Compose setup |
LOG_LEVEL |
β | debug / info / warn / error (default: warn) |
ENABLE_LOGGING |
β | Toggle logging output (true / false) |
The Electron launcher generates
.envautomatically on first run with a securely randomized password. You only need to create it manually for Docker-only deployments.
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.