Financial-View
Self-hosted personal finance and net-worth platform with banking, crypto and brokerage integration
Overview
Financial-View started in 2017 as a CSV analysis tool for bank transactions. In 2026 I rebuilt it from the ground up: the household ledger became a full personal finance and net-worth platform that I self-host and use daily. It brings together checking accounts, transactions, categories and budgets, and adds a consolidated net-worth view across cash, crypto (Binance, external wallets) and brokerage portfolios (Trade Republic, additional brokers). Technically it is a Spring Boot 4 backend (Java 25) structured along Domain-Driven Design, a Next.js 16 frontend with a strict BFF pattern (no token ever reaches the browser) and a read-only Python sidecar that encapsulates the fragile Trade Republic interface. Monetary amounts are modeled consistently as BigDecimal, data access is secured against cross-user access on three layers, and the interface is bilingual and dark-first.
The goal was not to port the old tool but to get it right: architecture tests enforce the layer boundaries from day one, the FinTS banking integration is strictly read-only (a source-code test guarantees it), and an integration audit logs every call to external market and banking APIs. The system grew across eight successive development waves, from accounts and categories to the hourly net-worth snapshot.
Tech Stack
Architecture Highlights
- BFF pattern: tokens live exclusively server-side in the encrypted httpOnly cookie, the browser never sees a token. Every request goes through a Next.js route handler that refreshes server-side and retries exactly once.
- Backend structured along Domain-Driven Design with hexagonal layers per bounded context, enforced from day one by an ArchUnit test suite (layering, repository pattern, user scoping).
- Money modeled consistently as a BigDecimal value object: float amounts are forbidden by an architecture test, sums are computed only via SQL, and values cross the API boundary as strings.
- Three-layer user scoping inside a single database: a ThreadLocal context from the JWT, an explicit user_id predicate in every repository, and a Hibernate filter as a safety net.
- Trade Republic offloaded into a read-only Python sidecar that decouples WAF token, WebSocket and 2FA from the Java backend and handles external calls fail-soft.
- A custom OKLCH design-token pipeline and Tailwind v4 in a CSS-first setup produce a consistent, dark-first theme including sRGB fallbacks for the charts.
Key Features
- Household ledger with accounts, transactions (manual, import, split), a recursive category tree and counterparties
- Rule-based auto-categorization with condition groups, preview and apply-to-existing
- Budgets and a dashboard with cashflow trend, top categories and concrete action items
- Net worth across cash, crypto (Binance, external wallets) and brokerage portfolios with hourly snapshots
- Trade Republic integration via a separate Python sidecar including 2FA login
- FinTS/HBCI banking and CSV import, both strictly read-only, with duplicate detection
- Trends and charts (balance, categories, monthly gradient) with editable notes
- Bilingual (German/English) with localized URLs, dark-first, plus an app-wide privacy switch for all amounts
Challenges & Solutions
- The unofficial Trade Republic interface keeps a session token valid for only about 290 seconds and cuts the refresh path roughly two hours after login: solved with a sidecar that refreshes proactively and reconnects the WebSocket.
- Monetary amounts have to stay consistent across three languages (Java, TypeScript, Python): a string representation throughout the boundaries, with BigDecimal interpretation happening only in the backend.
- Multi-tenancy inside a single database, after the Hibernate filter did not apply reliably everywhere: secured as defense-in-depth with an explicit user_id predicate plus the filter as a safety net.
- OKLCH colors render incorrectly in headless Chromium for SVG charts: separate sRGB fallback tokens fix the rendering issue.
- Banking must never move money: the FinTS integration is hard-limited to read operations, and a source-code test prevents any writing HBCI call.