Skip to content

Releases: beatrax-app/beatrax

v1.3.0

Choose a tag to compare

@github-actions github-actions released this 14 Jun 14:25
Immutable release. Only release title and notes can be modified.

"Local & in sync" — the largest release to date. Three tracks shipped:
goals & motivation, take-it-with-you, and insight & records. The fourth track
(local-first end-to-end-encrypted device sync) is in active development for a
follow-up v1.4 release.

Added

  • Base-currency FX conversion — non-EUR account balances now roll into a
    single reporting currency you choose, using a pluggable, offline-capable rate
    source. Closes the gap where non-EUR accounts were silently excluded from the
    net-worth headline.
  • Savings goals — set a target amount and date, track contributions, and see
    a forecast-driven projected finish date for each goal. The dashboard surfaces
    your nearest-finishing goals at a glance.
  • Savings pots / envelopes — carve virtual sub-balances ("pots") out of a
    real account and assign money to them without moving it between banks; pots
    reconcile against the real account balance so the numbers always tie out.
  • Responsive, installable PWA — every screen is now phone-legible, and the
    app installs to your home screen with an offline app-shell. Financial pages
    are never cached offline (privacy by construction); the transactions list
    gets phone infinite-scroll. Charts upgraded (ApexCharts 5).
  • PIN / biometric app-lock — protect the app with a PIN (Argon2id +
    libsodium key-wrap) and/or device biometrics (WebAuthn / Touch ID), with a
    server-authoritative idle re-lock, a privacy veil, and cross-tab lock sync.
    Also establishes the at-rest key-unlock gate that the upcoming sync feature
    will build on.
  • Bills / cash-flow calendar — upcoming fixed payments laid out on a
    calendar with a running projected balance, so you can see what's due and what
    you'll have left.
  • Tax-deductible tagging + per-year export — tag tax-relevant transactions
    (with an optional deduction category and note) from the transactions list,
    detail view, counterparty profile, or cash book; review a whole year on the
    /tax cockpit; and export the year's set as CSV or PDF for your records.
    Ships a six-country deduction-category corpus and a setup-wizard step.
  • Full-text search over your entire history — a fast FTS5 index over
    merchant names, descriptions, and tax notes powers a ⌘K command palette and a
    search-and-filter surface on /transactions, with date / account / amount /
    category filters and typed account: / category: / amount: / after: /
    before: tokens.
  • Unusual-charge / anomaly alerts — beatrax now proactively flags charges
    that look out of the ordinary: much larger than your typical spend for that
    merchant or category (robust median/MAD statistics), a large charge at a
    brand-new merchant, or an apparent duplicate within a short window (excluding
    known recurring series). Alerts appear through the existing alerts surface via
    a "Subscription drift ↔ Unusual charges" switch, with reason chips, a
    dashboard tile, and a nav badge. Each alert is acknowledge-/snooze-/dismiss-
    able; "mark as expected" creates a narrow, server-computed suppression rule
    you can see and remove in Settings (with one-tap undo). Detection runs on the
    queue (never slowing imports), with a one-time full-history backfill on first
    activation. Tunable sensitivity and a minimum-amount floor in Settings.

Security

  • The anomaly feature shipped with a full STRIDE threat model verified against
    the implementation (22/22 threats closed): every background-job query is
    explicitly user-scoped, suppression bands are computed server-side (never
    client-trusted), alert state changes go through a single audited state
    machine, and cross-user access returns 404.

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 07 Jun 15:58
Immutable release. Only release title and notes can be modified.

Added

  • CHANGELOG.md as the source of truth for release notes, automatically
    published into each GitHub Release body by the release workflow.
  • Cash book — a new /cash page to hand-enter cash and other off-bank
    spending (or income) so it lands in the same ledger as your imports: manual
    entries categorise, recur-detect, and count toward your month exactly like
    imported ones, because they flow through the canonical recording pipeline
    (a synthetic per-user Cash account + a "manual" source). Manual rows are
    user-owned and deletable (unlike immutable imported rows). The amount field
    accepts plain and Dutch-grouped formats; the chosen category is validated as
    your own; and two genuinely-distinct identical same-day entries both record
    (the recorder bumps the booking time on a fingerprint collision rather than
    dropping the second).
  • Net-worth roll-up — the dashboard leads with one figure across all
    accounts (assets minus liabilities), with an expandable per-account breakdown.
    Each account's balance is the same anchor the forecast uses as "today's
    balance", already sign-correct (a credit card counts as what you owe). Sums
    EUR-denominated accounts into the headline figure and flags when a non-EUR
    account is left out (no balance FX conversion yet); the internal
    paypal_funding routing account is excluded. Backed by a new
    NetWorthQuery Public service over the previously-internal balance resolver.
  • Month-over-month spending — the dashboard shows a "This month vs last"
    card: the current period's total spend with the signed change against the
    previous period, and the categories that moved the most (each with its delta).
    Spending more reads in rose, less in emerald. Uses the same EUR-settled outflow
    definition as the rest of the ledger, so the figures reconcile; renders nothing
    until there is a prior period to compare.
  • Sidebar count badges — the nav items (Transactions, Recurring,
    Counterparties, Drift alerts, Budgets, Subscriptions, Imports, Receipts) now
    show how many items each holds. All counts come from a single per-user cached
    payload (NavCountsService, short TTL, invalidated on demand) so the sidebar —
    which renders on every page — never fans out a pile of COUNT queries per
    render. Large counts are compact-formatted (e.g. "3.1k"), and a count of zero
    hides the badge to keep the rail calm.
  • "You could save here" insights — the dashboard shows a "Ways to save"
    card that pairs your recurring subscriptions with the most relevant official
    link from the support-resource corpus: a cheaper / student / retention plan
    where one exists, a cancellation page when a subscription's price has drifted
    up, or a gentle review nudge for an ongoing charge. Each suggestion is
    dismissible (and stays dismissed), and the whole set is cached per user so the
    dashboard never re-runs the resolution on every render. Purely informational —
    beatrax surfaces the official link, it never cancels or switches anything.
  • Recurring ↔ counterparty navigation — a counterparty profile's Recurring
    card now lists that merchant's recurring series (each linking to the series
    detail), and the recurring series detail page links back to the counterparty
    profile. Resolved through the shared transactions.counterparty_id, so it is
    exact rather than name-matched.
  • Settings redesign — the Settings page is reorganised from a narrow flat
    list into wider, titled cards (Appearance · Preferences · Forecasting ·
    Importing · Shared merchant list · Data & backup · Help · Developer), keeping
    every existing control and behaviour, with proper padding from the nav.
  • Encrypted backups — Settings → Data & backup can now download a
    passphrase-encrypted snapshot of your whole database (a VACUUM INTO copy,
    encrypted in place and streamed as a .sqlite.enc file), safe to keep on an
    external drive or in cloud storage because it is unreadable without the
    passphrase. Encryption is quantum-safe by construction: a purely symmetric
    scheme (no public-key step, so no Shor exposure) using Argon2id key derivation
    and XChaCha20-Poly1305 with a 256-bit key. The plaintext snapshot is locked to
    0600 and deleted as soon as it is encrypted; the passphrase never persists.
    Settings → Data & backup can also restore from an encrypted backup: upload
    the .enc, enter the passphrase, and type the confirmation phrase. The file is
    decrypted and integrity-checked first — a wrong passphrase or corrupt backup
    throws before anything changes — then a pre-restore snapshot of the current
    database is saved and the verified backup is swapped in (reload to see the
    restored data). Available on the SQLite (desktop) build; on a server, use
    php artisan db:restore (which gates on maintenance mode) instead.
  • Support-resource profiles — a counterparty profile now shows a "Support &
    cancelling" card (merchants) or "Getting help" card (government) with the
    official cancel / help / cheaper-plan links, a tel: helpline, and — where a
    service genuinely supports it — a one-click pre-filled cancellation mailto:.
    Backed by a new bundled resources/corpus/support/<country>.yaml corpus
    (researched for ~25 common subscriptions and the main NL agencies; the
    cancellation method, e.g. online form / phone / registered letter, is shown in
    a note since none of these document email cancellation). Looked up by
    word-level brand matching that tolerates legal-entity suffixes ("Netflix
    International BV" → Netflix) without false-matching ("Apple" never matches
    "Applebee's"; a plain "Albert Heijn" grocery charge never inherits the
    "Albert Heijn Premium" cancel card). Link schemes are restricted to http(s)
    and the mailto address is injection-guarded.
  • Subscription Drift Watch — a new /drift/watch page ("Subscriptions" in
    the sidebar) that ranks your approved subscriptions by how much their price
    has crept up since the first charge, each with a baseline → latest figure, a
    signed €/% delta, an amount-history sparkline, and an "open alert" badge that
    deep-links to the drift alert. The subscription-centric companion to the
    alert-centric /drift page; reuses the recurring occurrence history rather
    than adding a new store, and reads the full history so the baseline is the
    true first charge.
  • Category Budgets — a new /budgets page (Budgets module) to set a
    monthly spending ceiling per expense category and track the current period's
    spend against it, with a status-coloured progress bar (under / near / over),
    remaining amount, an inline editor, and a period total. Budget writes are
    validated against the user's own + global expense categories (a
    client-supplied category id can never attach a budget to another user's
    category), and the amount field accepts both plain and Dutch grouped formats.
    An optional Budgets step is added to the first-run setup wizard so new
    users can set a few category budgets during onboarding (or skip it); a step
    added after a user already finished onboarding is seeded as skipped, so
    finished users are not dropped back into the wizard.

Fixed

  • The receipt-conflict resolver ("Use receipt") no longer 500s on a malformed
    stored value: a non-JSON incoming_value is skipped (not applied) while the
    pending row is still cleared, matching the read side's tolerance. The demo
    seeder now JSON-encodes the conflict values like the production producer.
  • Server-deployment support alongside the NativePHP desktop build. config
    now defines Postgres, MySQL, and MariaDB connections (SQLite stays the
    default, so the desktop build is unchanged), selectable via DB_CONNECTION
    • the DB_* env vars. A new interactive php artisan beatrax:setup command
      walks a self-hoster through writing .env (app URL, application key,
      database), verifies the connection, and hands off to beatrax:install in a
      fresh process. A deploy/server/ recipe ships a single-container FrankenPHP
      image (code + assets baked in) with Postgres, a queue worker, and the
      scheduler, and .docs/deployment.md documents both the Docker and the
      bare-metal (clone-without-Docker) paths, including logging to stderr, the
      database queue (no Redis/Horizon on a server), and keeping the Dev Console
      off in production.
  • Import other European banks' CSV exports via a preset-driven generic CSV
    importer. Bundled presets cover N26, Revolut, and ING (Netherlands), each
    selectable under a new "Other bank" source in the import wizard. The engine
    handles the cross-bank differences — signed vs separate debit/credit columns
    vs an "Af/Bij"-style direction indicator, comma-or-dot decimals with thousands
    separators, per-row or fixed currency, and varied date formats — matches
    columns by a normalised header name (tolerant of minor spelling differences),
    skips pending/reverted rows (e.g. Revolut State) instead of aborting, and
    rounds sub-cent amounts rather than truncating. Adding another bank is a
    data-only change (a new entry in CsvPresetRegistry).

Added

  • Government-agency and bank-fee classification now lives in a regex-capable,
    per-country YAML corpus (resources/corpus/<type>/<country>.yaml) instead of
    hardcoded Dutch keyword constants. Patterns may be literal substrings or a
    regex: body, and the bundled set covers tax / social-security / broadcast-fee
    agencies across all 27 EU member states plus the UK, US, Canada, and Ukraine
    (e.g. Finanzamt, DGFiP/URSSAF, HMRC, IRS, Canada Revenue Agency, the German
    Rundfunkbeitrag). Patterns are collision-safe: risky short acronyms use
    regex:\b…\b word boundaries or the agency's full name, and agencies whose
    statement descriptors carry only a payment reference (not the agency name)
    are deliberately omitted to avoid false positives.

  • The internal bank-statement parsers are no longer branded around a single
    bank: the generic CAMT....

Read more

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 06 Jun 17:04
Immutable release. Only release title and notes can be modified.

What's Changed

  • fix: Windows install time (decrease composer dependency files)
  • fix: loopback 403 flood
  • chore: standardise on Docker toolchain

Full Changelog: v1.1.0...v1.1.1

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 03 Jun 15:34
Immutable release. Only release title and notes can be modified.
First stable (non-beta) release.

- fix(desktop): keep the queue worker alive past PHP's 120s wall-clock limit on Windows
- perf(import): persist large imports in bounded chunks instead of one transaction
- fix(ledger): make the demo seeder's transaction count deterministic
- chore: require PHP 8.5 as the project runtime floor; CI + bundle on 8.5 only

v1.0.3-beta

v1.0.3-beta Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 29 May 12:28
Immutable release. Only release title and notes can be modified.
v1.0.3-beta — hotfix: pre-warm Blade view cache at NativePHP boot to …

v1.0.1-beta

v1.0.1-beta Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 28 May 20:19
Immutable release. Only release title and notes can be modified.
v1.0.1-beta — release pipeline iteration; draft-then-flip publish flow.