v2.28.3
Security
- Closed a mass-assignment gap in the recurring-income update endpoint — a crafted payload could set internal fields such as the owning user (integrity only, no data disclosure). Update keys are now allowlisted like the other endpoints.
Fixed
- Auto-derived budgets (#269) now behave correctly and consistently everywhere: frequency math fixed (semi-annual was over-counted 6×, semi-monthly halved, custom schedules counted monthly, one-time bills counted every month), bill start/end dates respected, past months untouched — and the dashboard Budget Remaining hero, Budget Progress/Breakdown widgets, Budget Health score and budget alerts now apply the same recurring fallback as the Budget view.
- Recurring income summaries: semi-monthly income was counted at half its value; one-time income at full value every month until received. Transfers page monthly totals had the same gaps.
- Live forecast cache: invalidation never matched the stored key (changes like toggling "exclude from forecast" appeared to do nothing for up to 5 minutes), and the key now respects shared-account visibility.
- Editing a bill's amount without updating its split template is rejected when the stored splits no longer match; setting a split template via the API clears the bill-level category.
- Multi-account import partial failures (e.g. a deleted destination account) are reported instead of masquerading as full success, and balances are always recomputed for already-imported rows.
- Import preview parity: repeated bank transaction IDs (OFX FITIDs) within one file are flagged as the duplicates they are, including for accounts the import will create.
- The scheduled-transactions background job now derives balances from the ledger (last remaining hand-computed balance delta).
- Marking a bill paid warns specifically when linking the selected transaction failed.
See the full changelog for details.