This release makes Securo genuinely usable on a phone and gives transactions a lifecycle. The transaction list becomes cards on small screens, the cash-flow calendar finally has a mobile path in and shows a day's details where you tapped instead of at the bottom of the month, and transactions can now be pending or posted, so a bill you know is coming stops polluting the totals of money that actually moved. Quarterly contracts can be modeled at last, payees can be cleaned up in bulk, and under the hood the entire backend dependency tree is now locked and installed with hash checking, so every build installs exactly the audited bytes.
Features
- Mobile transaction cards, and a pending/posted lifecycle. On screens narrower than 768px the transactions table becomes cards grouped by date under sticky headers: category icon, description, account and a color-coded amount, with the desktop table unchanged. Alongside the layout, transactions gain a
status: mark one pending when you enter it, post it when the money actually moves. The list and the export endpoint filter by All / Posted / Pending, dashboard period totals count only posted transactions, and the MCP transaction tool exposes the same parameter. The dashboard's recent-transactions widget got the same mobile treatment, and form fields in the transaction dialog are now visually distinct from the dialog backdrop in light mode. Contributed by @panga (#507) 🎉 - Quarterly recurring transactions. Insurance and similar contracts billed every three months could not be represented: the closest option was monthly, and the scheduler silently treated any unknown frequency as monthly, so this needed an explicit branch rather than a stored string. Quarterly occurrences advance by exactly three calendar months while preserving the intended day of month, with short-month clamping and later recovery: a recurrence anchored to the 31st lands on April 30 and comes back to July 31. Projections,
skip_first, pending generation, end dates, year boundaries and leap years are covered by regression tests, and the label is translated in every locale. Closes #495 reported by and contributed by @seraphblade2010 (#499) 🎉 - Bulk delete for payees. Importing statements accumulates payees you will never use, and deleting them meant opening each one. Select multiple rows and a
Delete (N)button appears; each row also gets a direct delete icon. Contributed by @jorishaenseler15 (#475) 🎉
Fixes
- The cash-flow calendar works on a phone. Mobile portrait had no way into calendar mode at all (the only path was typing the URL), and once there, picking a day rendered its details after the complete month list, a full scroll away from the day you tapped. The mobile overflow menu now offers List and Calendar with the active view indicated, and the selected day's details render as an inset card directly below the day's row, with the row-to-details relationship preserved for assistive technology. Desktop is unchanged. Contributed by @seraphblade2010 (#515) 🎉
- The recurring badge appears only on transactions actually linked to a recurrence. The badge was inferred by matching description and type, so importing three transactions that happen to share a description marked all three as recurring even when only one was linked. The badge and the recurring details in the transaction dialog now resolve through the stored
recurring_transaction_idalone. Closes #497 reported by and contributed by @seraphblade2010 (#498) 🎉 - Calendar weekday headers line up with the dates below them. The header row was built from a UTC-anchored reference week but formatted in the viewer's own timezone, so for anyone behind UTC the entire row shifted one column: at UTC−4, August 2026 showed the 1st under
FRIeven though it was a Saturday. The day cells were never wrong; only the labels lied. The builder now formats in UTC too, and a timezone regression test keeps it honest. Contributed by @DannyFeliz (#493) 🎉
Under the hood
- The backend dependency tree is locked and installed with hash checking. Until now every environment (CI, the Docker image, each dev machine) resolved dependencies independently from
pyproject.tomllower bounds, so two builds of the same commit could ship different libraries.backend/uv.lockis now the single source of truth: CI and the image export it at install time and feed it topip --require-hashes, which refuses any artifact that does not match the audited hash, and the image dropsuvafter installing. Local dev builds its venv straight from the lock withuv sync --all-extras. No exported requirements files are committed, deliberately, so automated lock updates cannot go stale against them. This lands part of what #187 asks for, reported by @paulo-paes (#511, #513) 🙏 - Renovate keeps dependencies moving without the drip. Weekly, batched non-major updates grouped per area, majors individual, monthly lock-file maintenance.
pgvector/pgvectormajors are excluded on purpose, because a Postgres major must never arrive at a self-hoster's data directory as an automated PR (#512) - A full typing pass across the backend. Models, services, APIs and migrations now type-check cleanly: proper
Mapped[...]annotations, corrected migration imports, defensive handling where annotations were hiding real edge cases, plus pytest 9 and pytest-asyncio 1.0. Contributed by @pjrm (#502, #501) 🎉 - The Helm chart validates on Artifact Hub again. The chart declared
artifacthub.io/category: finance, which is not one of Artifact Hub's accepted values, and one invalid annotation fails validation of the whole package. None of the accepted categories describe a personal finance app and omitting the field entirely invites an equally wrong prediction, so the chart now opts out of category prediction explicitly, and its icon is a proper PNG instead of a favicon
A special shout-out to @pjrm for driving the big quality push this cycle. Typing an entire backend (models, services, APIs and migrations) is monumental, patient work that pays out on every future change, and it is exactly the direction we intend to keep investing in: making Securo progressively easier, safer and more pleasant to contribute to.
Big thanks to @panga, @seraphblade2010, @pjrm, @DannyFeliz and @jorishaenseler15 for the code, and to @paulo-paes for the report that shaped the supply-chain work 💜
Full Changelog: v0.13.12...v0.14.0