Skip to content

Latest commit

 

History

1,157 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Net Worth Tracker

Next.js React TypeScript Tailwind CSS Firebase Vitest License

Description

Net Worth Tracker is a full-featured personal finance application built for Italian investors. It provides comprehensive portfolio tracking, performance analytics, cashflow management, dividend monitoring, and long-term financial planning tools — all in a single dashboard.

The app integrates with Yahoo Finance for real-time price updates and includes advanced features like Monte Carlo simulations, FIRE (Financial Independence, Retire Early) projections, AI-powered performance analysis, and a dedicated AI assistant foundation via Claude. The UI is in Italian while the codebase follows English conventions.

Key Features

Portfolio Management

  • Overview that answers before it counts — the Panoramica opens with a one-sentence verdict on the month ("Agosto sta andando bene." / "Agosto è in calo, nonostante il mercato."), generated from your data and never claiming what the data can't support, followed by a grid of tiles that each answer one question with a short reading above the figures: net worth with trend and a "Mercato" line (the price effect on what you held — your own buys and sells never count as return), liquidity split, this month's cashflow with an end-of-month spending projection, composition, costs with the instruments that weigh most, up to three goals, spending and income by category, and your largest positions
  • Multi-asset tracking across stocks, ETFs, bonds, crypto, real estate, commodities, pension funds, and cash — added via a guided two-step dialog: pick the asset type first, then fill in only the relevant fields for that type
  • Multi-currency support: assets priced in USD, GBP, CHF, etc. are automatically converted to EUR for all portfolio calculations using live Frankfurter exchange rates; LSE pence (GBp) normalized to GBP automatically
  • Automatic price updates via Yahoo Finance (all assets) and Borsa Italiana (Italian bonds with ISIN)
  • Ticker display alias: give any investment a short, readable label (e.g. "CL2" instead of "CL2.MI") shown everywhere across the app instead of the raw ticker — automatic price updates keep using the real ticker underneath, unaffected
  • Bond coupon scheduling: automatic coupon generation with step-up rate tiers and final premium (Premio Finale) support — full BTP Valore compatible
  • Average cost tracking with 4-decimal precision, including a built-in multi-broker PMC calculator for positions spread across multiple brokers
  • Operations register (Registro operazioni): record explicit Buy / Sell / Adjustment operations on each tracked investment (stocks, ETFs, bonds, crypto, commodities), with an optional settlement account whose balance updates automatically — operations are net-worth-neutral (money simply moves between the asset and your cash). A per-asset "Movimenti" view lists your full operation history alongside realized P&L, total return, and money-weighted return (XIRR); each sale row also shows its realized gain/loss as a percentage and the average cost (PMC) at the moment of that sale. A sale shows an estimated realized-P&L preview before you confirm. For tracked investments, quantity and average cost are managed through the register, so editing an asset can never overwrite its cost basis. The register also powers "Capitale investito" and "Plusvalenze realizzate" on Performance and the total-return breakdown on Dividends (see below)
  • Fondo Pensione (Previdenza): track your Italian complementary pension as a manually-valued asset — no ticker, valued from your statement, with its own equity/bond mix. A dedicated Previdenza page lets you record contributions (TFR, employer, or a voluntary payment debited from a linked cash account, with a one-tap delete that reverses it), see an estimated annual IRPEF tax saving, and — if you're eligible for the "extra-deducibilità" recovery regime — track your unused deduction plafond. An existing tracked investment can be converted into a pension fund without losing its value or history. If you track more than one person's pension fund in the same account (e.g. both spouses), add each as a family member in Settings — the tax-saving estimate is calculated once per person against their own income, instead of mixing everyone's contributions together. Your pension fund counts toward your true asset-class exposure on Allocazione (it's locked, not tradable, so no plan ever buys or sells it) and has its own read-only "Mostra previdenza complementare" look-through comparing the fund's mix against your combined portfolio; Storico shows it as a dedicated "Previdenza" band instead of folding it into Azioni/Obbligazioni; and Performance metrics (TWR, Sharpe, volatility, drawdown, ROI, CAGR) exclude it by default, since it's capital fed by contributions rather than market activity. Its own return is measured on the Previdenza page instead, split into the three things that actually move a pension fund: what you paid in, what your employer gave you, and what the market produced — the headline percentage is market performance only (employer contributions are pay, not investment return), with a separate figure that includes them, measured against the money you put in yourself. Pick the month your contributions became fully recorded in Settings; before it, contributions and growth are indistinguishable and no return is shown, and when nothing has moved inside the measured window the page says so rather than reporting a 0,00% that looks like a result. A year selector drives the contributions-by-nature breakdown, the tax recap and the history, so you can review a past year's deduction without losing sight of the fund's current value
  • Current vs target asset allocation visualization
  • Automatic Azioni/Obbligazioni targets (opt-in, Settings → Allocazione): enter your age and the risk-free rate and The Bull's rule of thumb (125 − age − rate × 5) sets the equity share. Obbligazioni take the formula's residual and stay there; every other class you allocate — materie prime, crypto, immobili, trend following, carry — is funded out of the Azioni side, so a satellite sleeve never eats into the defensive part of the portfolio. The summary line states all three figures, and the targets always total 100%
  • Asset allocation analysis built around one question — how much, am I in line, what to do: a hero with total allocated wealth and a balance verdict (classes off target + biggest gap), an adjustable drift threshold (±2% / ±5% / the 5/25 rule / custom), and a "Cosa faccio" block with three planners behind one switch: Ribilancia (a consolidated trade list, how much to buy/trim per class), Versa (a no-sell contribution planner: where new cash goes, drilling class → sub-category → the individual instrument to buy, following your specific-asset targets), and Preleva (the decumulation mirror: "I need €X, what do I sell?" — it draws first from whatever sits above target, so a withdrawal rebalances instead of distorting, down to the instrument and the position you'll be left holding). Plus a unified composition list with inline drill-down and per-row current-vs-target bars. Trade Republic-inspired, with COMPRA / VENDI / OK action chips; colors follow the selected theme
  • Per-asset allocation roles — not all wealth can be traded in slices, and the allocation math now knows it. Each asset is Ribilanciabile (normal), Non negoziabile (a locked pension fund or private equity: it is invested wealth, so it counts in your percentages and your true equity/bond exposure is right — but no plan ever buys or sells it, and the plans instead reach your target by moving what you can move), or Escluso dall'allocazione (the home you live in: not an investment, so it leaves the page entirely). Plans only ever propose amounts you can actually execute — a sell is capped at your tradable holdings — and the page flags any target left stranded with nothing tradable behind it
  • Leveraged & composite ETFs: set a leverage multiplier on an ETF (e.g. 2 for a 2x fund) and the allocation page reasons about your notional exposure — the real risk you carry — not just market value. When you hold leverage, the hero shows two numbers side by side (invested capital vs notional exposure) with a current-vs-target leverage indicator, the composition bar's labels sum to your leverage, and your per-class targets in Settings can sum above 100% to express a target leverage (shown as e.g. "Leva target 1,50×"). The Ribilancia / Versa / Preleva plans then reason over your actual instruments — buying €1 of a 2x fund moves more than €1 of exposure — instead of assuming plain purchases. With no leverage anywhere, everything looks exactly as before
  • Portfolio exposure breakdown: a collapsible section at the bottom of the Allocation page that aggregates underlying-company, sector, and ETF-issuer exposure across all your ETFs plus direct stocks. See your true exposure to a single company (e.g. Nvidia) when it's split across multiple ETFs, with click-to-expand calculation drill-down showing the formula per source ("X% di €Y = €Z") and a total per row. Data sourced server-side from Yahoo Finance and cached per user; the "Aggiorna" button forces a fresh server-side computation when needed
  • Current-year historical tables use a hidden previous-month baseline so January can show growth vs the previous December without rendering an extra visible column
  • Asset management table supports column sorting (Valore Totale, G/P%, Peso%, Nome, Classe) and a group-by-class toggle; the ticker shows under each asset's name and the per-asset performance columns (Δ month / YTD / since start) are revealed on demand via an "Andamento" toggle, keeping the default table free of horizontal scroll; every numeric cell is monospaced and all gain/loss colors follow the active theme. On mobile, assets render as cards with a 12-month price sparkline and an inline performance breakdown; the Gestione / Anno Corrente / Storico section switcher uses a segmented pill control so all three sections are visible at a glance
  • Holdings with no market quote — cash accounts, real estate, private equity and pension funds, plus anything you've switched off automatic updates for — carry a subtle row (and card) tint, so you can tell at a glance which values you're responsible for keeping up to date. It marks manual pricing, not illiquidity
  • The Patrimonio header shows the same total, monthly / YTD change badges and "Nuovo massimo storico" badge as the Overview's net-worth tile (the page itself will move to the Overview's verdict-and-tiles layout next)

Performance Analytics

  • Comprehensive metrics across 4 sections (Returns, Risk, Context, Dividends) — each section leads with a dominant hero number (TWR, Sharpe, Net Cash Flow, YOC Net) followed by compact secondary rows; metric definitions accessible via inline popovers
  • Period selector (YTD / 1Y / 3Y / 5Y / All-time) uses a segmented pill control on mobile with spring animation; custom date ranges appear as a dismissible chip, not a permanent tab slot
  • Yield on Cost (YOC) and Current Yield calculations
  • Monthly returns heatmap and underwater drawdown chart (theme-aware colors, boosted contrast in dark themes); all metric values and benchmark comparison tooltips adapt correctly to all six color themes in both light and dark mode. Both read the same series: Max Drawdown, drawdown duration, recovery time and the Underwater chart all chain the monthly returns shown in the heatmap, so the chart is exactly the compounding of the months above it and the percentages don't shift as your contributions accumulate
  • Configurable calculation basis (Settings → Preferenze): performance metrics measure the portfolio you actively manage, so pension funds and assets excluded from your allocation (typically your home) are left out by default — either can be brought back in, and the page states which basis it is using. Leaving a hand-valued property out raises measured volatility and lowers Sharpe, because a value that never moves between updates quietly damps your measured risk
  • Honest measurement rules: the first snapshot of a period is the starting valuation, so the measured window opens the month after it and your first month's savings are never counted as return; below six months the headline states the period return instead of an annualized one (extrapolating a year from two months is a forecast, not a measurement); volatility and Sharpe show "—" rather than a number when fewer than three monthly returns are available, and they include every month — no hidden outlier filter that would let a real crash disappear from the metric meant to report it. The Money-Weighted Return (IRR) treats contributions as money paid in, discounted over the time it was actually invested
  • Evoluzione Patrimonio chart: one area (the capital that entered the portfolio — your net worth at the start of the period plus net contributions) under the net-worth line; the gap between the two is what the market produced, and the tooltip breaks each month into starting value, net contributions and market return. Contributions can legitimately go negative in a window where tracked spending outpaces tracked income, and the chart shows that honestly instead of hiding it
  • Rolling 12-month CAGR and Sharpe Ratio charts with 3-month moving average; always visible with an informative empty state when data is insufficient
  • Benchmark comparison: compare your portfolio against six model portfolios (60/40, All Weather, Buffett 90/10, Golden Butterfly, Permanent Portfolio, 100% ACWI) with an indexed growth-of-100 chart and a comprehensive risk/return table — TWR, Volatility, Sharpe, Sortino, Calmar, Max Drawdown, best/worst month, and positive/negative month counts; optional USD→EUR conversion via Frankfurter API
  • Progressive disclosure: methodology section collapsed by default; one-time guide strip for new users; "Avanzato" badge on technical metrics (TWR, IRR, Sharpe, YOC)
  • Animated metric cards: values count up on load and settle more naturally during period changes; staggered entrance cascade per section
  • Capitale investito: alongside the existing "Contributi netti" (external savings estimated from expense tracking), a companion figure shows what you actually bought minus sold through the operations register in the selected period — an info popover explains why the two numbers measure different things and will not match. Plusvalenze realizzate: a per-fiscal-year breakdown of realized gains/losses closed through the operations register, across all tracked investments
  • Dashboard KPI cards (Total Portfolio, Liquid Net Worth, Unrealized Gains, Taxes) animate their values on page load — numbers count up from zero once on mount; each card animates independently so the rest of the page stays stable during the animation
  • Dashboard hero trend chart has a period selector (3M / 6M / YTD / 1Y / 3Y / All), an all-time-high badge when your net worth reaches a new peak, and a "driven by" line showing which asset classes moved the most this month; a featured progress bar for your most relevant active goal appears alongside it when Goal-Based Investing is enabled
  • All major pages (Dashboard, Hall of Fame, History, Performance, Dividends) animate on load with staggered card entrances and smooth expand/collapse transitions; respects system "Reduce Motion" preference
  • All charts animate on load: bars grow up from baseline, lines draw in left to right, area fills expand, ranked composition bars grow to width — covers every page with data visualization (History, Performance, Cashflow, Dividends, FIRE, Monte Carlo, Goals)
  • AI-powered analysis using Claude with Extended Thinking and web search
  • AI Assistant organized around a single period axis — Month, Year, YTD, Total history, or Libera (free chat) in one selector, with the period picker right beside it. Selecting a period fills a live context card (net worth delta, cashflow, allocation changes, sub-category breakdown, target allocation vs current gap) before you ask, so you decide what to analyse with the numbers in front of you; in Libera mode you can optionally attach any period as context. After each answer the assistant proposes follow-up questions you can send with one tap. It remembers goals, preferences, risk profile, and stable facts across conversations — shown inline ("what it knows about you") and managed in a Memory panel — and surfaces a proactive "goal reached" banner when it detects from your data that a tracked target has been met. A "Allocazione vs target" prompt chip triggers an instant allocation-vs-target comparison with purchase priorities. On the spending side it receives an exhaustive breakdown of the selected period — every category with every sub-category used, each with its share of total spending, alongside spending by type (fixed / variable / debt) and income by category — so "how much did I spend on utilities inside Home last year?" is answered from data rather than refused. It also sees your full category/sub-category taxonomy, including categories with no activity, so it can suggest where to file a new expense or whether a new category is warranted. Conversations and Memory open as side panels on every screen size; responses stream as markdown (including tables) with full thread continuity. It also reads your Goal-Based Investing goals — assigned value, target, deadline, priority, suggested mix, and whether the current pace reaches the target, including the monthly contribution needed to close the gap and the value projected at the deadline (both labelled as projections, with the return they assume) — and when goal-driven allocation is on it reasons about the targets derived from those goals rather than the manual ones the app has stopped using. It can also propose a new goal: the reply renders as a card with the proposed name, target, deadline, priority and allocation, and nothing is saved until you press Conferma — the assistant never creates, edits or deletes a goal by itself. Web search for macro/geopolitical context (with a dedicated "searching the web" indicator and event citation) and behaviour preferences (response style, web context, automatic memory) in one place. Runs on Claude Sonnet 5. Controlled rollout via feature flag.
  • Fully responsive on mobile and tablet: dropdown period selector, stacked header, color-only heatmap view on small screens

Cashflow

  • Income, expense, and transfer tracking with custom categories and subcategories. Adding an entry starts with the type — Variable, Fixed, Debt/Installment, Income, or Transfer (move money between your own cash accounts) — picked from labelled cards, the same two-step flow as adding an investment in Patrimonio; the form that follows is titled and filtered for that choice, with advanced options (cost center, installments, recurrence) in a collapsible section. Recurrence is available on all three spending types — Fixed, Variable and Debt — and repeats monthly or yearly: a switch plus a Mensile | Annuale selector, a count that asks for months or years to match, and a line stating exactly how many entries will be created and the dates they will span before you save (up to 30 years of monthly payments, or 40 yearly ones). This is what lets a 17-year insurance premium or an annual subscription be projected forward the way a loan instalment always could. Income and transfers cannot recur — a transfer moves two accounts at once, and each occurrence would need its own pair of balance corrections. The whole series is created up front as real dated entries sharing a parent id, so it shows up in Cashflow and Analisi immediately and can be deleted in one action. Editing an existing entry skips the picker and keeps the type as a field inside the form, where the note explaining what a type change does to your balances lives. Transfers are net-zero: they debit the origin account and credit the destination automatically, and are excluded from all income/expense/savings/budget and performance metrics
  • The type of a saved entry can be changed across all five types, transfers included: the category re-attaches itself to the same-named one under the new type, the amount's sign and every linked account balance are corrected automatically (converting a transfer away reverses it on both accounts; converting an entry into a transfer asks for the destination account), and an inline note states what will change before you save. Bulk re-typing a whole category across the transfer boundary is refused instead — each row touches two accounts, so only the per-entry dialog can do it safely
  • Categories are identified by document, not by name, so the same name can live under two types (a "Casa" under Fixed and another under Variable) without their figures merging anywhere in the app — Analisi, Overview top-5, trend charts, cost centers, PDF export, periodic emails and the CSV importer all key by document. Where two do share a name, charts and lists spell out which is which — "Casa (Spese Fisse)" / "Casa (Spese Variabili)" — and leave unambiguous names alone
  • Analisi page (/dashboard/analisi): a standalone, entity-first analysis page. Every category and sub-category is a first-class object: click it anywhere — the ranked composition lists, the Sankey diagram, an anomaly chip, a year-comparison row, or the "Vai a categoria…" search (which also reaches entities with no spending in the period) — and its dossier opens in place: total for the selected period with its share of spending, a per-year table with signed year-over-year deltas (the current year compared like-for-like against the same months of last year) whose rows open on the change per sub-category — for "Casa" you read Condominio 300 € vs 250 € (+20,0%) and Elettricità 80 € vs 90 € (−11,1%) without leaving the page — monthly and trailing-12-month averages, a current-year projection, a 24-month trend with last year's dashed baseline, and the underlying transactions. The focused entity lives in the page link — a "condominio check" is a bookmark — and survives period switches (the multi-year blocks deliberately ignore the period axis: the period is a cursor, not a cage). Around it: a three-state period selector (current year / past year + optional month / full history, also in the link), a KPI trio with year-over-year pacing lines ("−13,3% vs 2025, stessi mesi"), anomaly detection vs the 6-month rolling average, a Top Expenses block, the 5-layer Sankey (flow view; category clicks open the dossier), and an always-visible Confronto Annuale with a selectable comparison year and a per-category delta ranking of what drove the change, "Nuova"/"Cessata" categories included. Savings-rate and long-term trends sit behind a "Mostra dettaglio" toggle. All windows are declared next to their figures, and all charts respect the "history start year" preference from Settings
  • Budget tab: create your own budgets per category or sub-category — only the budgets you create are shown — with an optional overall monthly spending ceiling that validates your category budgets stay within it. Each budget runs on a monthly or annual horizon (annual ones, e.g. holidays, are tracked year-to-date) and income categories can have separate income targets. Changes auto-save as you type (no Save button), paused while you're over the overall budget. Includes an end-of-month spending forecast, insights (top category, categories at risk, spend vs your usual pace by today, daily average) and threshold alerts (50/75/90/100% + forecast overrun) shown in-app and in your emails. Fully responsive on mobile
  • Cost Centers tab (opt-in): group expenses by object or project (e.g. "Automobile Dacia"). A period axis (this month / this year / last 12 months / all time) drives a total headline and a flat list of centers ranked by spend, each row showing its share of the period total. The same axis stays available inside a center's detail, and the figures that deliberately use a different window — the spending ceiling, the annual projection, the monthly chart — say so next to the number. Each center's detail leads with its period total and a change-vs-previous chip, breaks the cost down by category (list + stacked monthly chart) and splits fixed recurring cost from one-off spending. Optional per-center spending ceiling (monthly or annual, with a verdict + meter), projected annual cost, a cross-center comparison overlay, and archive/restore for finished centers
  • Bulk move transactions between categories/subcategories (cross-type supported)
  • CSV export
  • CSV import (Settings → Spese): migrate historical income/expense data from a CSV file (Italian or English headers, ;/,/tab delimiter, IT or EN number/date formats). Categories resolve by (name, type) — same-named categories of different types import side by side, a row without a type inherits the single existing namesake's type, and duplicates sharing both name and type attach to the oldest one with a note in the preview. Shows a full preview — valid rows, discarded rows with a reason, categories/subcategories that will be created, disclosures — before anything is written, and the whole import can be undone in one tap. Transfers aren't supported (a transfer needs origin/destination accounts a historical row can't provide) and account balances are never touched by the import

Dividends

  • Multi-currency dividend recording with automatic EUR conversion
  • Borsa Italiana scraping for Italian market data (dividends and bond prices)
  • Monthly calendar view with synchronized date focus and drill-down
  • Dividend statistics, contextual payment detail, and yield calculations
  • Total Return per Asset: table combining capital gain % and all-time net dividends received % (calculated at historical cost basis per payment, not diluted by later purchases) to show the true investment return per asset; card layout on mobile. For investments tracked in the operations register, the capital-gain figure is computed from your real buy/sell history — including fully-sold positions, shown with a "Chiusa" badge, and partial sells — instead of only unrealized price movement
  • Dividend Per Share Growth: year-by-year gross DPS history per equity asset with YoY% and CAGR columns; portfolio median growth rate shown as a summary; tap any asset on mobile to open a vertical year-by-year dialog

Historical Analysis

  • Automatic monthly portfolio snapshots (via Vercel cron)
  • Page opens with a hero block showing current net worth, total growth since tracking began, and estimated CAGR — with section navigation pills to jump to any chapter
  • Net worth evolution chart — colors theme-aware across the six color themes
  • Composition chapter: one card answering how your wealth is split, on two cuts of the same euro — Asset class or Liquid vs illiquid — chosen with a single selector. A 100%-stacked area shows how the mix drifted month by month (band thickness is the share, so the flat top edge is a permanent check that the parts add up), with a ranked breakdown underneath giving each class its value in euro, its share, and how that share moved against the same month a year earlier. Hovering a month opens that month's balance sheet: your total, then every class ranked, each with both its euro value and its percentage. Anything the monthly snapshots cannot attribute to a class is labelled "Non attribuito" rather than quietly dropped — which is how months recorded before the app tracked illiquid holdings separately stay honest about what they don't know. Each snapshot also records how your pension funds were split across asset classes that month, so the Previdenza band is separated from Azioni/Obbligazioni using the split that was true at the time: re-balancing your fund today does not rewrite the past, and the parts of the chart reconcile to your patrimonio exactly. Months recorded before this still fall back to your fund's current split, and the note on the chart says from which month the figure is measured rather than estimated
  • Doubling time analysis with geometric calculations and fixed milestone thresholds — promoted to the top of the page as the most distinctive analysis; summary cards show fastest doubling, average time, and progress toward the next milestone
  • Savings vs Investment Growth comparison (annual and monthly views)
  • Labor & Investments section: lifetime KPI cards for Earned from Work, Saved from Work, Investment Growth Gross/Net, plus positive/negative month counters and a monthly breakdown chart — shows a setup prompt linking to Settings when labor categories are not yet configured
  • Year-over-Year variation and raw monthly snapshot data available in a collapsible section (collapsed by default)
  • Per-instrument value breakdown ("Valore per Strumento"): pick any recorded month to see each individual holding's value that month (read straight from the saved snapshot, so currency/real-estate/price rules are already applied), select a subset of instruments to total their value and its share of the month, and chart that subset's combined value across every month on record. The trend chart's tooltip splits each month's change versus the previous month into a price effect (market movement) and a quantity effect (your buys and sells), so a drop reads as "sold" vs "market fell" at a glance

FIRE Planning

  • Single-answer FIRE calculator — a [2fr_1fr] hero answers "when?" at a glance: the projected FIRE calendar year (and your age at that year) in the base scenario, with a "% verso FI" chip, the remaining gap, FIRE Number and current withdrawal rate as supporting rows, and a sustainable passive income companion card (annual / monthly / daily, liquid vs illiquid, pension re-entry when the bridge model is active). A basis line under the hero declares the active assumptions (SWR, primary residence, pension lock)
  • Settings (withdrawal rate, primary residence, pension lock + RITA controls) live in one collapsible that stays closed once configured; historical charts (FIRE runway, cashflow vs passive income) are tucked into a "Dettaglio" section
  • Projection with two views, switched by a Scenari | Ventaglio pill: Scenari is the deterministic Bear/Base/Bull chart (three portfolio series plus a single dashed base-scenario FIRE target — Bear/Bull targets in the tooltip, which also names the pension-unlock step); Ventaglio is a Monte Carlo fan of the accumulation phase — 1,000 simulated paths with 10–90 and 25–75 percentile bands, the median, ~40 sample paths and the moving FIRE target, plus the cumulative probability of reaching FIRE by the projected year. Market returns and volatility are derived from your real portfolio allocation
  • Optional "capitale bloccato" setting with a pension bridge model: pension funds not yet unlockable leave the FIRE-eligible net worth (your total net worth, shown everywhere else, stays unchanged) and re-enter at their unlock year — estimated automatically from the Italian RITA rule (configurable INPS age, −5/−10 years) or from a per-fund unlock date. The FIRE Number becomes a bridge target, projections show the fund merging back as a visible step, and Coast FIRE, What If and Monte Carlo all respect the same setting
  • Coast FIRE tab — single-answer layout built on one question, "can I stop contributing?": the dominant number is your shortfall (or surplus) against the Coast FIRE Number, with an explicit verdict and the two figures it compares, beside a "if you stop today" card projecting your current patrimonio to your target age with no further contributions. Under it, a line declaring the assumptions in use, then a timeline of the inflows the calculation already discounts (your pension fund's unlock year and each state pension's start date, with amounts), one settings panel (collapsed once configured, reopening on unsaved edits or incomplete data), Bear/Base/Bull scenario cards, and the projection chart — whose tooltip names the pension-fund unlock step. Coverage phases, per-pension impact and the explanatory notes sit in a "Dettaglio" section. All chart colors theme-aware
  • Coast FIRE supports one or more state pensions with editable IRPEF brackets, exact pension start dates, scenario-specific real net conversion, a guided summary that separates target-age need, bridge years, and post-pension steady state
  • Multi-scenario projections (Bear / Base / Bull) with inflation adjustment
  • Per-scenario FIRE numbers with automatic savings stop at FIRE reached
  • Historical FIRE runway view with rolling 12-month expenses and separate total/liquid deltas
  • What If Analysis tab — stress-test your plan against life events (job loss, major purchase, savings/spending change, windfall) and see the before → after impact on both traditional FIRE and Coast FIRE; hosts the years-to-FIRE sensitivity matrix (how your timeline shifts as annual spending and savings vary). The job-loss event lets you select which income sources stop (by category and sub-category, e.g. a single partner's salary in a shared portfolio) and shows a step-by-step breakdown — missed savings vs portfolio drawdown — with each formula filled in from your own figures
  • Goal-Based Investing: allocate portfolio portions to financial goals (house, retirement, emergency fund, etc.) — now trajectory-led, not just progress bars. The hero gives a verdict (how many goals are behind, the nearest deadline) and an actionable "to set aside per month" total; goals are a single urgency-sorted flat list, each carrying an "In linea / In ritardo / Raggiunto" tag. Set a planned monthly contribution per goal and the app computes the contribution actually required to hit the target by its date, your projected completion date, and a glide-path projection chart (expected return inferred from the goal's recommended asset mix). A cross-goal contribution planner splits a new deposit across under-funded goals by gap × priority, a milestone timeline shows the order goals will be reached, and the "Non assegnato" figure expands to the holdings that still have free value. Tap any row to expand it inline (trajectory breakdown, projection chart, allocation comparison, assigned assets, edit/delete); two-tap inline delete confirmation prevents accidental removal. The AI Assistant can discuss these goals and propose new ones, which are created only on your explicit confirmation
  • Goal-Driven Allocation: optionally derive portfolio allocation targets as a weighted average of goal recommended allocations, with automatic fallback to manual targets
  • Fully responsive on mobile and tablet — tab navigation uses a dropdown on small screens, year-by-year projection table switches to a card layout

Monte Carlo Simulations

  • Trade Republic-inspired layout: Success Rate (probability of not depleting the portfolio) is the dominant hero metric, always visible before and after a simulation run
  • Settings split into core inputs (always visible) and market parameters (collapsible, auto-opens when values differ from defaults) — reduces cognitive load from 18 simultaneous fields to 6
  • Animated mode switcher between Single Simulation and Bear/Base/Bull Scenario Comparison with spring pill animation
  • 4 asset classes: Equity, Bonds, Real Estate, Commodities — editable return and volatility per class
  • Progressive percentile fan chart (p10/p25/p50/p75/p90) and final-value distribution histogram with staged bar reveal
  • Bear/Base/Bull scenario comparison with overlay chart (3 median lines + p10–p90 bands), side-by-side distribution histograms, and a 5-year-interval comparison table
  • All chart colors and tooltips theme-aware across all six color themes
  • Auto-fill allocation from real portfolio (crypto and cash excluded, normalized to 100%)
  • Scenario parameters (return, volatility, inflation per asset class) saved to Firestore per user
  • Fully responsive on mobile and tablet — percentile table switches to a card layout, scenario parameter cards stack vertically

Other

  • Periodic email summaries with AI commentary — Automatic portfolio recap emails sent at the end of each month, quarter (March/June/September/December), half-year (June 30 / December 31), and year (December 31), each with its own toggle. Emails include net worth change vs the previous period, asset class breakdown with allocation %, best/worst performing asset class (by Δ% and Δ€), income vs expenses with savings rate, full income and expense category breakdowns, top 5 individual expense transactions, dividends received, and a Confronti table comparing net worth, income, expenses, and savings against both the previous period and the same period one year earlier (net worth from end-of-period snapshots, cashflow from period totals). The AI-generated narrative is structured in six sections (overview, patrimony and investments, vs previous period, vs same period last year, income/expense changes with likely causes, takeaways) and reads the same complete data the in-app Assistant does: your full category → subcategory spending tree, income by category, current allocation with targets and gaps, your investment goals, plus the budget alerts of the month and an already-calculated split between what you saved and what the market moved. Its length scales with the period (500 words monthly, 700 quarterly and half-year, 900 yearly). Web search for macro context follows your Assistant preference — enable "contesto macro" if you want market events cited. Recipients shared across all email types; manual send buttons in Settings for on-demand previews. A separate opt-in weekly budget email is sent every Sunday with the status and progress of all your monthly and annual budgets plus a one-line AI summary; any category that has actually gone over its limit also lists the individual expenses behind the overrun (date, subcategory, note, amount). Powered by Resend (free tier sufficient for personal use)
  • Public demo mode — "Try the Demo" button on the login page and landing page auto-logs visitors into a shared read-only account. All mutation actions are disabled; the AI Assistant is fully blocked. Set NEXT_PUBLIC_DEMO_* env vars to enable; leave them empty to hide the CTA on self-hosted deploys
  • Color Themes — Six selectable color themes (Default, Solar Dusk, Elegant Luxury, Midnight Bloom, Cyberpunk, Retro Arcade) with per-user persistence in Firestore and localStorage. Theme selector in Settings → Aspetto with light/dark preview swatches. Switching dark/light mode plays a circle-reveal animation from the toggle. Charts update their palette to match the active theme
  • Dark mode — Full dark/light/system theme support. The header toggle cycles through three states: Light, Dark, and System (follows OS preference), using Sun, Moon, and Monitor icons. The same toggle is available on the public landing, login, and registration pages, so visitors can pick their mode before signing in. Every page, chart tooltip, and UI component is properly themed
  • Authentication flow — Login and registration screens follow the same visual language as the dashboard, with accessible focus states, 44px keyboard-reachable password toggles, autoComplete hints for browsers and password managers, and clearer in-place submit feedback including an inline password mismatch error on Register
  • Hall of Fame — Personal records dashboard with an all-time best hero block, monthly and annual ranking tables, current-period spotlight, and contextual notes. Mobile navigation shows one section at a time; desktop tables are full-height with no internal scroll
  • PDF Export — 7 configurable sections with custom year/month period selection; sections auto-disabled for past periods when historical data is unavailable
  • Settings — Trade Republic-inspired layout: the Allocation tab opens with a hero block showing the total allocation percentage, followed by a single unified flat list for all six asset classes (Equity, Bonds, Real Estate, Crypto, Commodities, Cash) — sub-categories expand inline without nested cards. Mobile tab navigation uses a segmented pill control (all five tabs visible at a glance). Unsaved-change feedback, smooth nested allocation editing, and inline two-tap confirmations for sensitive category actions

Quick Start

# Clone the repository
git clone https://github.com/GiuseppeDM98/net-worth-tracker.git
cd net-worth-tracker

# Install dependencies
npm install

# Copy and configure environment variables
cp .env.local.example .env.local
# Edit .env.local with your Firebase credentials (see Prerequisites below)

# Start development server
npm run dev
# → http://localhost:3000

For the full setup guide including Firebase configuration and Firestore security rules, see SETUP.md.

Prerequisites

  • Node.js 18.x or higher
  • Firebase project with Firestore + Authentication enabled (free tier is sufficient)
  • Vercel account (recommended for deployment and cron jobs) or Docker for self-hosting
  • Anthropic API key (optional — enables AI performance analysis)

Environment Variables

Copy .env.local.example to .env.local and fill in your values:

Variable Required Description
NEXT_PUBLIC_FIREBASE_* (6 vars) Yes Firebase client SDK configuration
FIREBASE_ADMIN_* or FIREBASE_SERVICE_ACCOUNT_KEY Yes Firebase Admin SDK (server-side)
CRON_SECRET Yes Secret for authenticating cron job requests
NEXT_PUBLIC_APP_URL Yes Your deployed application URL
NEXT_PUBLIC_REGISTRATIONS_ENABLED No Toggle new user registration (default: true)
NEXT_PUBLIC_REGISTRATION_WHITELIST_ENABLED No Enable email whitelist for registration
NEXT_PUBLIC_ENABLE_TEST_SNAPSHOTS No Enable test snapshot generation in Settings
ANTHROPIC_API_KEY No Enables AI-powered performance analysis
FRED_API_KEY No Enables period-accurate Sharpe/Sortino in benchmark comparison (ECB deposit facility rate history via FRED); falls back to user-configured rate if absent
RESEND_API_KEY No Enables automatic monthly portfolio summary emails (via Resend)
RESEND_FROM_EMAIL No Sender address for monthly emails (e.g. onboarding@resend.dev for personal use)
NEXT_PUBLIC_DEMO_USER_ID No Firebase UID of the shared demo account
NEXT_PUBLIC_DEMO_EMAIL No Email for demo auto-login (shown on landing page)
NEXT_PUBLIC_DEMO_PASSWORD No Password for demo auto-login

See .env.local.example for detailed comments on each variable.

Security Notes

  • NEXT_PUBLIC_FIREBASE_* values are client configuration, not server secrets. They are expected to be visible in the browser bundle.
  • Keep FIREBASE_ADMIN_*, FIREBASE_SERVICE_ACCOUNT_KEY, CRON_SECRET, and ANTHROPIC_API_KEY server-only.
  • Private App Router API routes are expected to verify Firebase ID tokens server-side. Scheduled cron flows authenticate separately with CRON_SECRET.

Architecture

┌─────────────────────────────────────┐
│          Next.js App Router         │
│  (SSR pages + API routes + cron)    │
├──────────┬──────────┬───────────────┤
│  React   │  React   │   API Routes  │
│  Pages   │  Query   │  (server-side)│
├──────────┴──────────┴───────────────┤
│           Service Layer             │
│  (Firestore, Yahoo Finance, AI,    │
│   scraping, metrics, PDF)           │
├─────────────────────────────────────┤
│  Firebase Auth  │  Firestore DB     │
└─────────────────┴───────────────────┘
         External APIs:
   Yahoo Finance · Frankfurter · Borsa Italiana · Anthropic · FRED

Key design patterns:

  • App Router with protected dashboard routes
  • Service layer (lib/services/) for all business logic
  • React Query for client-side data caching and mutations
  • Feature-based component organization (by domain, not by layer)
  • Shared layout system (PageContainer, PageHeader, PageTabBar) for consistent page structure
  • Timezone-aware date handling (Europe/Rome)

Tech Stack

Category Technology Purpose
Framework Next.js 16, React 19 SSR, routing, API routes
Language TypeScript 5 Type safety
Styling Tailwind CSS v4, shadcn/ui UI components and design system
Data React Query (TanStack) Client-side caching and server state
Backend Firebase (Firestore + Auth) Database and authentication
Animation framer-motion Page transitions and micro-interactions
Charts Recharts, @nivo/sankey Data visualization
Finance yahoo-finance2 Real-time price data
AI @anthropic-ai/sdk Performance analysis
PDF @react-pdf/renderer Export reports
Forms react-hook-form, zod Form handling and validation
Dates date-fns, date-fns-tz Timezone-aware date operations
Scraping cheerio Borsa Italiana dividend and bond price data
Testing Vitest · Playwright Unit testing (1922 tests) · browser E2E against the Firebase emulator (30 specs)

Development

Commands

npm run dev        # Start dev server with hot-reload
npm run build      # Production build
npm run start      # Start production server
npm run lint       # Run ESLint
npx knip           # Find unused files, exports, and dependencies (see knip.json)
npm test           # Run unit tests (single run)
npm run test:watch # Run tests in watch mode

# Local Firebase Emulator Suite (offline dev/testing — never touches production; requires a JDK)
npm run emulators      # Start Auth + Firestore emulators (data persists across restarts)
npm run emulators:seed # Seed a synthetic test account (once) — test@example.com / test1234
npm run dev:emulator   # Run the app against the local emulators

# Browser tests (needs the emulators above running; app served on :3100, so your dev server can stay up)
npm run test:e2e       # Playwright: desktop 1440px, mobile 390px, degraded-state scenarios
npm run test:e2e:ui    # Same, interactive runner

See SETUP.md → Step 6 for the full local-emulator guide (prerequisites, persistence, reset) and SETUP.md → Step 7 for the Playwright suite.

Vitest covers the pure utilities and services, where the logic lives. Playwright covers what only a real browser can see — the desktop: layout switch at 1440px, animated disclosures, deep links that must cold-load into the right state, whether a loading state ever flashes the wrong content, and whether a page overflows its viewport at 390px (measured on the elements, since the app shell's scroll container hides that from document.scrollWidth). Covered pages: Previdenza (including a project for the states a healthy fixture can never reach — a return that can't be trusted, a window where nothing moved, a fund with no history yet — seeded on their own account: npm run e2e:seed -- suspicious|idle|fresh), Analisi (its own fixture account too, with every expense dated January so exact assertions hold whatever month the suite runs in) and FIRE / Coast FIRE (a deterministic Coast fixture with custom expenses, two state pensions and a pension fund unlocking inside the projection's horizon). Note: the emulators need Java 21+ — see SETUP.md → Step 6.

Conventions

  • UI language: Italian
  • Code language: English (comments explain WHY, not WHAT — see COMMENTS.md)
  • Responsive breakpoint: desktop: (1440px) instead of Tailwind's default lg:
  • Radix UI imports: All components/ui/ primitives import from the radix-ui umbrella package with named imports ({ X as XPrimitive }) — not from individual @radix-ui/react-* packages
  • Radix Select: No empty string values — use sentinel values like __all__
  • Settings changes: Always update type definition + getter + setter together

Deployment

Vercel (recommended)

  1. Import the repository on vercel.com
  2. Add all environment variables from .env.local
  3. Deploy — cron jobs for snapshots and dividends are configured in vercel.json

Two cron jobs run daily at 18:00 UTC:

  • /api/cron/monthly-snapshot — Automatic monthly portfolio snapshots
  • /api/cron/daily-dividend-processing — Dividend data processing

For detailed instructions, see VERCEL_SETUP.md.

Docker (self-hosted)

Run the app on any VPS or server with Docker. Firebase still handles authentication and the database.

cp .env.local.example .env.local  # fill in your Firebase credentials
docker compose up -d --build

For the full guide including cron job setup and nginx/HTTPS configuration, see DOCKER.md.

Project Structure

net-worth-tracker/
├── app/                    # Next.js App Router
│   ├── api/                # API routes (17 endpoints)
│   ├── dashboard/          # Protected pages (8 sections)
│   ├── login/              # Auth pages
│   └── register/
├── components/             # React components (~116)
│   ├── ui/                 # shadcn/ui base components
│   ├── layout/             # Sidebar, header, navigation
│   ├── assets/             # Portfolio management
│   ├── performance/        # Metrics and charts
│   ├── cashflow/           # Income/expense tracking
│   ├── dividends/          # Dividend calendar and tables
│   ├── fire-simulations/   # FIRE calculator
│   ├── goals/              # Goal-based investing
│   ├── monte-carlo/        # Monte Carlo UI
│   ├── history/            # Historical analysis
│   ├── hall-of-fame/       # Rankings
│   └── pdf/                # PDF export (sections + primitives)
├── lib/
│   ├── services/           # Business logic (22 services)
│   ├── utils/              # Helpers (formatters, dates, auth)
│   ├── hooks/              # Custom React hooks
│   ├── constants/          # App config, colors, defaults
│   ├── firebase/           # Firebase client + admin setup
│   └── query/              # React Query key factory
├── types/                  # TypeScript definitions (9 files)
├── contexts/               # React contexts (AuthContext)
└── public/                 # Static assets

Contributing

Contributions are welcome! When contributing:

  1. Fork the repository and create a feature branch
  2. Follow the existing code conventions (Italian UI, English code)
  3. Read COMMENTS.md for the project's commenting philosophy
  4. Ensure npm run build passes before submitting a PR

If you work on this repo with an AI coding agent, point it at WORKFLOW.md first: it holds the standing session rules (one branch and one commit per session, never commit without explicit approval) and the guided-verification protocol used here — including how to drive the Firebase emulator and the authenticated Playwright fixtures instead of testing by hand.

Reporting Issues

Known Issues

  • Currency conversion depends on the Frankfurter API (falls back to 24h-cached rates); non-EUR assets created before the FX update will show native price as EUR until the next price refresh
  • Demo account requires manual setup: create a Firebase user, populate Firestore with realistic fake data, and set the three NEXT_PUBLIC_DEMO_* env vars

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).

This means you are free to use, modify, and distribute this software, but any modified version that is accessible over a network must also make its source code available under the same license.

See LICENSE.md for the full license text.

Screenshots

Screenshots recorded on the app with anonymized or synthetic data.

Dashboard & Portfolio

Portfolio overview Overview: the month's verdict over a grid of tiles — net worth, liquidity, cashflow, composition, costs, goals

Asset allocation Current vs target asset allocation

Cashflow

Cashflow Sankey 5-layer Sankey diagram of income and expenses

Cashflow drill-down 4-level drill-down into expense categories

Performance & History

Performance metrics ROI, CAGR, Sharpe Ratio, drawdown and more

Monthly heatmap Monthly returns heatmap

Net worth history Net worth evolution over time

FIRE & Simulations

FIRE calculator FIRE projections with Bear/Base/Bull scenarios

Monte Carlo Monte Carlo simulation with scenario comparison

Dividends & Hall of Fame

Dividend calendar Monthly dividend calendar with drill-down

Hall of Fame Monthly and annual performance rankings

Star History

Star History Chart

About

Track your net worth and investment portfolio with automatic price updates, asset allocation, expense tracking, and FIRE calculator. Modern alternative to spreadsheets. Next.js + Firebase + TypeScript.

Topics

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Contributors

Languages