Skip to main content

Financial engine

Every number in the UI comes from a pure, deterministic engine (src/engine). The UI only formats the results.

Money and dates​

  • Money is stored as integer minor units (bigint) with a currency code. There is never floating-point money, and you can't mix currencies implicitly.
  • Rounding is centralised and follows the rounding policy in Settings.
  • Dates are calendar-only (IsoDate), with no time-zone drift.
  • Day-count conventions: Actual/360, Actual/365, 30/360.

Modules​

ModuleResponsibility
amortizationFrench, constant-amortization and interest-only schedules, including fixed→variable resets
ratesFixed, variable (index + spread) and mixed rates
prepaymentPrepayments with reduce payment or shorten term, and prepayment penalty rules
cashflowOne authoritative formula that closes each account's period
simulationRuns period by period: applies events in a fixed order, expands recurring income and expenses, debits loan payments
metricsTotal, available and minimum liquidity, runway, reserve breaches, effort rate, interest drag, savings trend
optimizationPrepayment optimisation (engine-level)

Recurring items​

Income and expenses support the frequencies daily, weekly, biweekly, monthly, quarterly, semiannual and annual. Each has a start date and an optional end date. The engine also supports inflation rules (annual or monthly-compounded indexation) on recurring items.

Design invariants​

  • Conservation: cash-flow periods and transfers neither create nor destroy money
  • Currency: arithmetic between different currencies throws an error instead of silently mixing them
  • Determinism: the same inputs always produce identical outputs, with events sorted by (date, type priority, id)

Each engine module has unit tests next to it (Vitest, npm test).