ROADMAP.md
Rama main · réplica de lectura del repositorio original.
# Roadmap — Croesus
**Open-source** net worth tracking application: a consolidated view of all
assets (financial, real estate) and liabilities (debts), with fine-grained
modeling of French tax-advantaged accounts, an emergency fund, and YNAB-style
budget envelopes.
Two target usage modes:
- **Self-hosted**: deployed with Docker, accessible from a browser,
multi-device.
- **Standalone desktop** (Windows/Linux/macOS): either with an embedded local
database, or connected to a remote self-hosted instance.
## Tech stack
- **Backend**: Python — **FastAPI** (REST API + Pydantic validation),
**SQLAlchemy + Alembic** (ORM + migrations, compatible with both PostgreSQL
*and* SQLite from the same models — key for the local desktop mode),
**numpy-financial / pandas** for advanced financial calculations (XIRR, IRR,
loan amortization, projections)
- **Frontend**: **Vue 3 + Vite** (SPA) + **Nuxt UI** (works in plain Vue,
outside of Nuxt) + Tailwind CSS
- **Desktop**: **Tauri** — wraps the Vue frontend; on first launch, choose
between:
- *Local*: Tauri starts a compiled FastAPI sidecar (PyInstaller) backed by a
local SQLite database
- *Remote*: the app points directly at an existing self-hosted instance,
with authentication
- **Self-hosted**: Docker Compose (FastAPI + Postgres); reverse proxy
(Traefik, Caddy, nginx...) is up to the deployer — see
[docs/REVERSE_PROXY.md](./docs/REVERSE_PROXY.md)
- **Auth**: OIDC SSO support, once v1 is stable, plus classic login for
desktop's remote mode
- **Package management**: `uv` (Python), `pnpm` (JS/TS)
## Key concepts
- **Account**: a tax wrapper or asset container (PEA, life insurance, French
regulated savings accounts, brokerage account, checking account, real
estate, SCPI, crypto...). Has one or more valuations over time.
- **Asset**: a line item inside a brokerage account (stock, ETF, crypto...)
with quantity and cost basis. Optional — an account can be valued directly
without line-item detail (e.g. a euro-denominated life insurance fund).
- **Liability**: a debt (mortgage, consumer loan...) that is deducted from net
worth.
- **Emergency fund**: a target goal attached to an account, with progress
tracking.
- **Budget envelope**: a named allocation bucket (e.g. "Vacation", "Home
renovation"), independent of account type — a distinct concept from tax
wrappers.
## Phase 0 — Foundations (done)
- [x] Tech stack decision
- [x] Backend scaffold (FastAPI + SQLAlchemy + Alembic), Dockerfile — full
CRUD for Accounts/Valuations/Assets/Liabilities/Envelopes + a net worth
endpoint (computed with pandas)
- [x] Frontend scaffold (Vue + Vite + Nuxt UI), base structure — Dashboard/
Accounts/Liabilities/Envelopes pages, Pinia stores, API client
- [x] Desktop scaffold (Tauri), minimal shell pointing at the frontend —
`cargo check` validated on Linux ARM64
- [x] Self-hosted Docker Compose (backend + postgres + frontend), deployed
and tested end to end
- [x] v1 data model (Account, Valuation, Asset, Liability, Envelope)
## Phase 1 — v1: manual entry + dashboard
- [x] Account CRUD (all types: Checking, Regulated savings, PEA, Life
insurance, Brokerage, Crypto, Real estate, SCPI, Other)
- [x] Asset CRUD (portfolio line items) inside brokerage accounts — managed
per-account from the account detail panel
- [x] Manual entry of periodic valuations → historical tracking over time —
add/edit/delete from the account detail panel
- [x] Liability CRUD (loans, credit) with monthly payment and remaining
balance
- [x] Emergency fund: special account + target goal + progress bar
- [x] Budget envelopes: CRUD buckets + allocated/used amount
- [x] Dashboard: current net worth (assets − liabilities), evolution curve
over time, breakdown by account type / asset class — refreshes
automatically after any edit, no manual reload needed
- [x] Local desktop mode: FastAPI sidecar + embedded SQLite, packaged with
PyInstaller
- [x] Remote desktop mode: server URL configuration + authentication — a
Settings → Connection toggle points the desktop app at an existing
self-hosted instance instead of the local sidecar; classic
username/password login (single admin account, opt-in via
`ADMIN_USERNAME`/`ADMIN_PASSWORD` on the self-hosted side)
- [x] Generic OIDC SSO support (self-hosted + remote desktop mode) — works
with any provider (Authentik, Keycloak, etc.)
- [x] Docs: reverse proxy setup guide (Traefik, Caddy, nginx examples via
`docker-compose.override.yml`)
## Phase 2 — Automated pricing (done)
- [x] Automatic price fetching for assets with a symbol set: Yahoo Finance's
unofficial chart endpoint (stocks/ETFs/funds) + CoinGecko (crypto,
mapped ticker → CoinGecko id) — both keyless, no signup required.
Background refresh (APScheduler, configurable interval) plus a manual
"Refresh prices" action
- [x] Automatic brokerage account valuation from positions + prices — any
account with at least one asset gets its current valuation derived
automatically (Σ quantity × current price, falling back to cost basis)
on every asset change or price refresh, instead of manual entry
- [x] Local price history cache (avoid hammering the external API) — a
PriceCache table (source, symbol, price, fetched_at) dedupes external
calls across assets sharing a symbol and across refreshes close in time
## Phase 3 — Internationalization
- [x] UI language support (i18n) — externalize frontend strings, start with
French + English
- [x] Multi-currency — per-account currency, conversion to a reference
currency for the consolidated net worth view (supersedes the earlier
"EUR only" non-goal). Exchange rates from Frankfurter
(api.frankfurter.dev, ECB daily reference rates) — keyless, no signup
required, same convention as Phase 2's Yahoo Finance/CoinGecko pricing.
Cached locally (FxRateCache) the same way PriceCache avoids
re-hitting Yahoo/CoinGecko
## Phase 4 — Customizable dashboard
- [x] Drag-and-resize widget grid (12-column, snap-to-cell) replacing the
current fixed dashboard layout — add, remove, rearrange and resize
widgets, with an edit mode and a persisted per-instance layout
- [x] Widget catalog: stat tile, trend chart, breakdown donut, list, and a
debt/envelope payoff-status widget — each bound to a choice of data
source (net worth, total debt, envelopes remaining, emergency fund,
a specific account/liability balance, assets-by-class...) and a size
preset
- [x] Empty-dashboard state prompting the first widget to be added
## Phase 5 — Advanced analytics
All grouped under a new top-level **Insights** page.
- [ ] Performance against market — compare portfolio return (XIRR) against a
benchmark index (CAC 40, S&P 500, MSCI World...) over the same period,
with the ability to add a custom benchmark (symbol + expected annual
return) alongside the built-in ones
- [ ] Contribution vs. performance decomposition — split net worth growth
into money contributed vs. market/valuation effect
- [ ] Simple net worth projections — linear/compound projection from
existing valuation history (e.g. "at this savings rate, when do I
reach €X") — kept deliberately simple; see non-goals
- [ ] Tax-wrapper limit tracking — flag accounts approaching or at their
contribution ceiling (PEA €150k, Livret A, LEP, PER deductible envelope,
etc.), *and* flag wrappers the user is eligible for but hasn't opened
(e.g. an unused LEP)
- [ ] Debt payoff projections — debt-free date, remaining interest at the
current rate, and "what if I paid €X more/month" scenarios on a
liability's detail view
- [ ] Automated practice checks — a ranked feed of rule-based nudges derived
from existing data (no external advice/AI), graded alert / warning /
hint: tax wrapper at cap or left unused, envelope overspent, a single
holding over ~a third of total assets, stale valuations, underperforming
a benchmark, an oversized emergency fund, mortgage-rate-vs-investing
guidance. Stays within the "no automated financial advice" non-goal —
these are data-derived observations, not recommendations to act on
## Phase 6 — Household sharing (optional)
- [ ] Shared/household net worth — multiple users on one instance, with
some accounts shared and others kept private (supersedes the earlier
single-user non-goal). Per-account shared/private toggle, an invite
flow to add a household member, and a "mine" vs "household" net worth
scope switch usable throughout the app (dashboard, accounts, insights)
## Phase 7 — Data portability & reliability
- [ ] Import from spreadsheet/CSV or XLSX (bootstrapping from an existing
manual tracker) — column mapping step (date, value, currency columns)
rather than a fixed schema
- [ ] Export — CSV of every table, and/or a PDF net worth report (with or
without charts)
- [ ] Per-widget/per-chart sharing — download or share any single dashboard
widget or insights chart as a PNG/PDF snapshot, with a "hide amounts"
toggle that redacts figures (shapes/percentages stay) for safe sharing
- [ ] Encrypted backup export (passphrase-protected, AES-256), restorable
independently of the running instance
- [ ] Notifications — a weekly net worth summary, envelope-overspend
alerts, and a reminder when an account hasn't had a valuation
recorded in a while, with a configurable staleness threshold
(30/60/90 days) (supersedes the earlier "valuation staleness
reminders" wording — same idea, folded into a broader notifications
feature)
- [ ] Account security — two-factor authentication (authenticator app +
recovery codes) and visibility/revocation of active sessions,
alongside the existing password/OIDC login
## Phase 8 — Bank aggregation
- [ ] Powens (formerly Budget Insight) or Bridge API integration for
automatic sync of French bank accounts
- [ ] Bank connection token management, refresh, error handling
- ⚠️ Notable complexity: PSD2 accreditation for aggregators, API cost
depending on provider, handling user reconnection
## Non-goals (for now)
- Automated financial advice (projections stay simple — see Phase 5)
- Automated cross-platform builds (will come via CI/CD — GitHub Actions —
rather than locally from the Pi, which can't natively compile Windows/macOS
binaries)