Skip to content

v0.13.11

Latest

Choose a tag to compare

@tassionoronha tassionoronha released this 30 Jul 18:01
0d7dca6

This release adds a cash-flow calendar that puts your balance on a month grid so you can see where the money runs thin before it happens, and brings the interface to two more languages, French and European Portuguese. It also fixes a set of things that quietly did the wrong thing rather than failing loudly: Enable Banking connections asking every bank for 180 days of consent regardless of what that bank allows, categorization rules silently inverting \s, \d and \b, a single crypto holding aborting an entire SimpleFIN sync, and date fields defaulting to the wrong day for anyone not on UTC. Mobile got a proper pass, and two-factor codes now tolerate a clock that drifts.

image

Features

  • A cash-flow calendar for transactions. The transactions page gains a Calendar view alongside the list: a month grid with each day's running balance, its transactions, and projected entries from your recurring rules, so a shortfall three weeks out is visible now instead of on the day it lands. Days can be shown Compact, balance and markers only, or Detailed, with the top transactions and a +N more. A balance trend line sits above the grid, a legend explains the markers, and picking a day opens its transactions in a side panel. Scoped to one account at a time so the running balance means something. Closes #400 reported by and contributed by @RomuloGatto (#401) 🎉
  • French. A complete French locale, with the date-fns locale wired up so dates and month names follow it too. Contributed by @tdechanterac (#455) 🎉
  • European Portuguese. A genuine pt-PT translation rather than a pt-BR copy: tu-form address matching the register es, it and de already use, European vocabulary (ficheiro, utilizador, palavra-passe, definições, ecrã), a + infinitive instead of the gerund, and the false friends avoided, so income is Rendimentos rather than Renda, which means rent. A bare pt still resolves to pt-BR, so nothing changes for existing users. Contributed by @11VitorAlves11 (#461) 🎉

Fixes

  • Enable Banking asks each bank for a consent window it actually allows. maximum_consent_validity arrives from Enable Banking in seconds but was stored and used as days, so a bank reporting 7,776,000 was recorded as allowing 7.7 million days, and the frontend never sent the value at all. Every connection asked for the 180-day default, which banks with a shorter cap reject outright. Across the live institution list the real limits are 7, 89, 90 and 180 days, and connecting to any of the 90-day banks failed. The value is now converted once and sent per institution. Contributed by @pjrm (#459) 🎉
  • Categorization rules stop inverting their own regex. The regex operator uppercased the pattern along with the transaction text, which flips every lowercase escape class: \s became \S, \d became \D, \b became \B. A rule meant to match a word boundary matched only the inside of words. The shipped Investimentos rule uses \bCDB\b, \bLCA\b and \bLCI\b, so it both missed real CDB transactions and wrongly categorized names like BRASILCAP CAPITALIZACAO SA because LCA sits inside BRASILCAP. Case-insensitive matching was already handled by the IGNORECASE flag, so the uppercasing was redundant for literals and destructive for everything else. Accents are still stripped from the pattern. Closes #463 reported by and contributed by @TomazMPP (#464) 🎉
  • One crypto holding no longer aborts a whole SimpleFIN sync. A ticker longer than three characters, DOGE for example, was written into the 3-character currency column and the database rejected it, failing the entire sync rather than that one holding. Tickers now go to the ticker column and the currency falls back to the account's. Closes #448 reported by and contributed by @brandonjones24 (#450) 🎉
  • Two-factor codes tolerate clock drift. A TOTP code was accepted only inside its exact 30-second window, so an authenticator a few seconds out of step with the server produced valid-looking codes that were rejected. The adjacent windows on either side are now accepted, and the verification endpoint is rate limited so the wider window stays bounded against guessing. Contributed by @ADolkun (#441) 🎉
  • Date fields default to your day, not UTC's. Form defaults were built from new Date().toISOString(), which is a UTC day, so anyone east or west of UTC could open a form near midnight and get yesterday or tomorrow pre-filled. Transaction, transfer, account, asset, settlement and recurring forms now use the browser's local calendar day through one shared helper. Download filenames keep their UTC timestamps. Contributed by @ADolkun (#440) 🎉
  • Mobile interface pass. Seven layout problems on small screens: the transactions header no longer overflows, the filter menu opens as a single in-panel list with drill-down instead of side submenus that ran off the edge, bulk actions and the transfer-linking dialog stay inside the viewport, the month label stays legible when compact, rule fields are usable, and account actions that were hover-only, and therefore unreachable on a touch device, are now available from a menu. Desktop layouts are unchanged. Closes #437 reported by @mjneto, contributed by @MarlonPassos-git (#476) 🎉
  • The category dialog's Save button stays on screen. The dialog was 757px tall with no height limit, so on a viewport under about 770px, a 1366x768 laptop or any desktop at 125% zoom, it was clipped at both ends and Save sat below the fold with no way to reach it. The dialog is now capped to the viewport with the form body scrolling and the footer pinned. Closes #467 reported by and contributed by @MarlonPassos-git (#465) 🎉
  • Categories are listed alphabetically within their group. Category order inside a group was whatever the database returned, so it could differ between page loads. Contributed by @jun10r4lm31d4 (#472) 🎉
  • Icon-only buttons announce what they do. Buttons that show only an icon, the avatar menu, admin toggles, reports pagination, import undo, the goals colour picker, and edit and delete in budgets and recurring, had no accessible name, so a screen reader announced only "button". They are labelled now, and a lint rule keeps unlabelled controls from coming back. Contributed by @rodrimaia (#422) 🎉
  • A sync no longer breaks itself by racing. Two overlapping syncs for the same connection, a manual Sync landing on top of a scheduled run, could each insert the same (account_id, external_id) pair because neither saw the other's uncommitted row. Every later sync then aborted the whole connection with MultipleResultsFound. Duplicate pairs are now tolerated and the same latent crash is fixed in the importer (#456)
  • Transaction and rule safety. Workspace boundaries are enforced on transaction and rule writes, rule actions and transaction references are validated more defensively, rule dates compare as dates, and rule backfill and category overwrite are explicit controls. Contributed by @ADolkun (#375) 🎉

Under the hood

  • OAuth callback URLs are derived from FRONTEND_URL in the backend instead of being assembled in Compose. docker-compose.prod.yml hardcoded http://localhost:3000/oauth/callback for both bank providers regardless of where the app was served, and the setting defaults still pointed at a Vite port the project stopped using. Behaviour at the defaults is unchanged. The installer now requires podman-compose 1.6.0, the first release that resolves nested ${VAR:-${OTHER:-x}} interpolation; below it FRONTEND_URL reached the containers with the inner variable left as literal text, which breaks CORS, passkeys and login callbacks in a way that is hard to trace (#478)

Big thanks to @RomuloGatto, @tdechanterac, @11VitorAlves11, @pjrm, @TomazMPP, @brandonjones24, @ADolkun, @MarlonPassos-git, @jun10r4lm31d4 and @rodrimaia for the code, and to @mjneto for the report that shaped the mobile work 💜

Full Changelog: v0.13.10...v0.13.11