github securo-finance/securo v0.13.10

11 hours ago

This release makes passkeys work on whatever address you actually browse from instead of only localhost, adds a masked account number so two identically-named accounts at the same bank can finally be told apart, and gets completed and archived goals back out of their dead end. It also fixes the Money Map's 30-day window, supports CAMT.052 for banks that only export intraday reports, makes category pickers scrollable inside dialogs on touch devices, and lines dashboard drilldown totals up with the cards above them.

Features

  • A masked account number to tell same-named accounts apart. Banks often report every account under the same label (usually the account holder's name), so two accounts at the same bank looked identical and had to be identified by cross-referencing balances or transactions before renaming them. The last 4 characters of the bank's own identifier are now stored and shown next to the account type and in the account pickers, sourced from the IBAN on Enable Banking and from number on Pluggy. Only those 4 characters are ever stored, never the full IBAN or account number. It is provider-owned like name, so it refreshes on sync and existing accounts backfill on their next one, and manual renames keep living in display_name. SimpleFIN exposes no identifier, so it renders nothing there. Closes #408 reported by @Dionysos71 (#415) 🙏
  • Create split groups and members from inside the transaction dialog. The group and member creation flows in the transaction splits section moved from inline expansion forms into focused modals, so you can set up a group and add members without leaving the transaction you are splitting. Follows on from #404. Contributed by @DannyFeliz (#442) 🎉

Fixes

  • Passkeys work on the address you are actually on. rp.id was derived from FRONTEND_URL, so on the stock Docker stack at http://127.0.0.1:3000 the browser rejected the ceremony with SecurityError: This is an invalid domain. before any prompt appeared. Passkeys only worked at exactly http://localhost:3000, and a LAN IP, 127.0.0.1 or a reverse-proxied domain all failed. The RP ID and expected origin are now resolved per request from the origin the browser is on and stored in the challenge, so verification matches the ceremony that issued it. WEBAUTHN_RP_ID still pins passkeys to one domain and now actually reaches the backend through Compose, and the frontend container learns the real FRONTEND_URL so a proxied domain is no longer refused by Vite before passkeys are even reachable. The two rules that can never be worked around, that an IP address is not a valid RP ID and that plain HTTP is not a secure context off localhost, are now explained up front instead of surfacing as an opaque error. Passkeys are also documented in .env.example and the README, where they were absent entirely. Closes #403 reported by @DannyFeliz and #410 reported by @chisato04 (#419) 🙏
  • Completed and archived goals can be reactivated. Neither state offered a route back to active, and the edit dialog never exposed status, so deleting the goal was the only escape. A Reactivate button now mirrors the existing pause/resume pair, and deleting a goal goes through the same confirm dialog accounts and assets already use instead of firing immediately on click. Reactivating keeps the goal's account or asset tracking link intact. Fixes #417 reported by @himan7991 (#418) 🙏
  • The Money Map's 30D range is an exact 30 days. It resolved its start date through the month-aligned path the multi-month ranges use, which snaps back to the 1st of a month, so on 2026-07-14 it actually covered 44 days and never matched the transactions list for the same period. It now resolves an exact rolling window ending today, matching the transactions "Last 30 days" preset, with recurring projections clamped to the window. Other ranges are untouched. Closes #402 reported by @Serafim696 (#414) 🙏
  • Category pickers scroll inside dialogs again. Radix's body scroll lock cancels wheel and touch events whose target sits outside the dialog's own DOM subtree, and the combobox list portals to document.body, so picking a category from inside a rule or transaction dialog was frozen on touch devices and unscrollable by mouse wheel. The list now drives its own scrolling with non-passive native listeners, whether or not a scroll lock is active. Fixes #428 reported by @viniciuscmartins (#439) 🙏 Contributed by @itodevio 🎉
  • CAMT.052 intraday reports import. The CAMT importer only walked the CAMT.053 end-of-day structure, so a valid CAMT.052 file parsed without error and silently yielded zero transactions, which from the UI looked identical to an empty account. BkToCstmrAcctRpt/Rpt is now used as a fallback when the CAMT.053 path finds nothing. Several European banks only issue CAMT.052. CAMT.053 behavior is unchanged. Contributed by @Hoovercraft (#416) 🎉
  • Calendar month names follow the interface language. Month names on the Transactions, Dashboard and Budgets calendars fell back to English when a date format setting triggered a non-native date order, for example a US-style date format in a German UI. They now follow the UI language consistently. Contributed by @jorishaenseler15 (#420) 🎉
  • Dashboard drilldown totals match the cards. Opening a drilldown from an income or expense card could show a footer total that disagreed with the card it came from, because the drilldown query did not apply the same filters as the summary. Both now share the same rules, including leaving closed accounts out. Contributed by @ADolkun (#379) 🎉
  • Transaction and rule flow corrections. Reapplying all rules now asks for confirmation before rewriting transaction fields, the rule dialog resets dependent fields when the condition type changes, bulk tag removal is labelled and translated in all 8 locales, and import review date handling and export filter payloads were tightened. Contributed by @ADolkun (#376) 🎉

Under the hood

  • Credential settings (secret_key, pluggy_client_secret, enable_banking_private_key, the S3 storage keys and oidc_client_secret) now use Pydantic's SecretStr, so they are masked in logs, tracebacks and serialization output instead of appearing as plain strings. Contributed by @pjrm (#413) 🎉

Big thanks to @DannyFeliz, @itodevio, @Hoovercraft, @jorishaenseler15, @ADolkun and @pjrm for the code, and to @Dionysos71, @chisato04, @himan7991, @Serafim696 and @viniciuscmartins for the reports that shaped this release 💜

Full Changelog: v0.13.9...v0.13.10

Don't miss a new securo release

NewReleases is sending notifications on new releases.