cuppabot 7fb6df71f2 Russian language support added (#2005)
* Add russian localization

* Update localization files from upstream

* Add russian to supported languages

* Add CHANGELOG.ru.md

* Changes in CHANGELOG.ru.md

* Fix some errors after PR

* Remove duplicated 'merge_duplicate' key in the same mapping in locales/views/transactions/ru.yml

* Fixed a translation error into Russian about creating a new account by invitation.

* Clarification of financial terms in Russian translation

* Add russian localization

* Update localization files from upstream

* Add russian to supported languages

* Add CHANGELOG.ru.md

* Changes in CHANGELOG.ru.md

* Fix some errors after PR

* Remove duplicated 'merge_duplicate' key in the same mapping in locales/views/transactions/ru.yml

* Fixed a translation error into Russian about creating a new account by invitation.

* Clarification of financial terms in Russian translation

* Improve Russian i18n translations

* Improve Russian i18n translations

* Improve Russian i18n translations

* Improve Russian i18n translations

* Improve Russian i18n translations

* Improve tests for Russian i18n translations

* Improve Russian i18n translations

* Improve Russian i18n translations

* Minimalistic SECURITY.md

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>

* ci(preview): render Cloudflare config from trusted template (#2207)

* Fix SSO provider settings updates (#2210)

* fix(goals): UI polish — submit validation, container-responsive cards, picker & filter fixes (#2160)

* fix(ds): disabled buttons use not-allowed cursor

Tailwind v4 preflight sets cursor:pointer on every <button>, including
disabled ones. Add disabled:cursor-not-allowed to the DS button base so
disabled buttons read as non-interactive.

* fix(goals): disable new-goal submit until required fields valid

The submit button was always enabled, and the funding-accounts checkbox
group has no native 'required', so a goal with no linked account could be
submitted and only fail server-side (422). Disable the submit until name,
a positive target amount, and >=1 account are present, and add a
submit-time guard that surfaces inline errors and focuses the first
offending field as a backstop.

* fix(goals): keep color/icon picker from shifting the form

DS::Disclosure wraps its body in an mt-2 div that sits in normal flow, so
opening the absolutely-positioned picker popover nudged the form down ~8px.
Use a raw <details> for the picker so the popover overlays without
reflowing the content beneath it.

* fix(goals): container-responsive cards, meta-line status, scrollable tabs

- Card grids + KPI strip switch from viewport breakpoints to container
  queries (@container), so columns track the actual content width when the
  account/AI sidebars are open instead of crushing three columns into a
  narrow center.
- Move the status pill from the title row to the meta line; the title now
  gets the full header width (no more 'Hou...' truncation at 3-up). Drop
  the secondary line when the pill already states it (completed / open).
- Card internals harden for narrow widths (ring shrink-0, footer wrap,
  shorter 'N days left' secondary).
- Filter tabs scroll horizontally instead of wrapping 'On track' mid-label
  or forcing the row wider than the viewport.

* fix(goals): only require a funding account on the create form

GoalsController#edit renders account checkboxes from visible accounts only,
so a goal backed solely by a now-hidden (disabled / pending_deletion)
account renders none checked. The submit-validation then wedged the edit
form — a name/notes change couldn't be saved even though #update preserves
existing links when account_ids is omitted. Gate the account requirement on
a require-account Stimulus value that is true only for the create form.

* fix(goals): give the color/icon picker trigger an accessible name

The hand-rolled <summary> is icon-only (pen), so screen readers announced an
unlabeled control. Add a localized aria-label.

* fix(goals): render form validation errors inline on server re-render

The client-side controller already surfaces name / amount / account errors
inline and disables submit, but a server 422 (JS disabled, or a race that
lets an invalid submit through) fell back to the top run-on banner
("X must be filled and Y and Z."). Make the existing inline error hints
server-aware so a failed submit shows the same per-field red text the
client path does, and drop the base-error banner — base only ever carries
the account requirement, which now renders beside the funding-accounts
list.

* fix(goals): blur projection chart under privacy mode

The projection chart's SVG axis labels and annotations (target, "$X short",
$200K/$400K ticks) rendered in cleartext while privacy mode blurred every
other number on the page. Tag the chart container `privacy-sensitive`, the
same wrapper-level treatment the net-worth and cashflow-sankey charts
already use, so it blurs with the rest.

* fix(goals): stop target-date input stretching when amount error shows

The target-amount / target-date row is a two-column grid. The amount
column carries its inline error <p> underneath, so when that error
appears the column grows and the default `items-stretch` makes the
sibling date input stretch to match — the date box visibly grew taller
than the amount box. Anchor the row with `items-start` so each input
keeps its natural height and the error just extends below its own column.

* fix(goals): make invalid submit announce errors instead of dead-ending

Review follow-ups:
- Swap the submit gate from the disabled attribute to aria-disabled: a
  truly disabled default submit also blocks Enter-key implicit
  submission, so an invalid form was a dead button with every inline
  error still hidden. The button now stays clickable and lets
  validateOnSubmit surface the errors; DS buttonish styles the
  aria-disabled state (cursor-not-allowed + opacity-50). Side effect:
  loading_button_controller submits also dim while busy, which reads as
  an upgrade.
- Focus the first funding-account checkbox when accounts are the only
  missing field (focus previously went nowhere).
- Drop the now-orphaned goals.goal_card.days_left_by locale key.

* fix(ds): canonical transaction-row — stop category pills truncating (#2147)

* fix(ds): canonical transaction-row — stop category pills truncating (#2137)

The desktop transaction grid gave the name column col-span-8 (67%, usually
half-empty) and the category column only col-span-2 (17%), so the category
pill's name area was clamped to ~44px and ellipsized nearly every value
("Misc...", "Shop...", "Rest...") despite the empty space the audit flagged.

- Rebalance the lg:grid-cols-12 row: name col-span-8 -> 7, category 2 -> 3
  (amount unchanged; still 12). Category gains 50% width from the over-wide
  name column.
- categories/_badge: the pill was `flex w-full` (stretched to fill the column);
  make it `inline-flex max-w-full` so it hugs its content and short names render
  fully, capping + truncating only when genuinely too long.

Verified on /transactions: visible-row category truncation dropped 7/7 -> 2/7
even in the compressed (AI-panel-open) view; Payment / Shopping / Restaurants
now render in full. Fixes both the interactive categories/menu and the static
transfer categories/badge (menu reuses the badge partial).

* feat(ds): lift categories/_badge onto DS::Pill

Addresses the Drift Patrol finding (and jjmata's request) properly
instead of patching the bespoke span: the badge becomes a DS::Pill in
badge mode. The pill primitive grows the three capabilities the badge
needed and the bot's one-liner glossed over:

- truncate: pills that may shrink inside min-w-0 columns drop their
  shrink-0/whitespace-nowrap and ellipsize the label instead of
  overflowing (the transaction-row category cell this PR fixes).
- label_testid: stamps data-testid on the label span; five test files
  target [data-testid='category-name'].
- icon_size: passthrough to the icon helper (badge keeps its
  established sm glyph; default stays xs).

custom_color was already the sanctioned escape hatch for user-chosen
hues. Owned visual deltas from pill standardization: px-1.5/py-1 ->
px-2/py-0.5, gap-1 -> gap-1.5, border mix 10% -> 20%; bg mix, hex text,
radius, text scale, icon size, truncation and testid are parity.

Label wrapper only renders when truncate/label_testid ask for it, so
existing pill DOM (and the find("span", text:) assertions on it) is
unchanged. Four new pill tests + a Lookbook case cover the recipe.

* feat(merchants): add raw data import (csv) for merchants (#1992)

* feat(merchants): add csv import endpoint for merchants

* docs: update endpoint docs

* fix(merchant): recommended ai fixes

* chore(ci): finish Node 24 GitHub Actions migration (#2221)

* chore(ci): finish Node 24 GitHub Actions migration

* chore(ci): update preview security check for github-script v8

* fix(mobile): redact sensitive diagnostic logs (#2199)

* fix(mobile): redact sensitive diagnostic logs

* fix(mobile): tighten diagnostic log redaction

* fix(mobile): harden sanitized diagnostics

* fix(mobile): clarify offline fallback diagnostics

* fix(mobile): refine diagnostic log redaction

* fix(mobile): tighten diagnostic log redaction

* fix(mobile): harden auth diagnostic failures

* feat(ds): DS::SegmentedControl — fix invisible dark selected pill (#2145)

* feat(ds): DS::SegmentedControl; fix invisible dark selected pill (#2137)

Ships DS::SegmentedControl — a single-select pill group (filters, mode
switches) — plus a Lookbook preview, tests, and an exemplar migration of the
budget filter tabs.

The audit flagged the dark selected pill as invisible: the bespoke controls
paired a container-inset track (gray-800) with a gray-700 active pill, barely a
step apart. The primitive uses the DS tab-token values (tab-bg-group -> a
near-black alpha-black-700 track in dark), against which the gray-700 active
pill clearly reads. Values are inlined with @variant theme-dark because
@apply-ing the custom tab utilities drops their dark override.

- app/components/DS/segmented_control.rb: slot-based with_segment(label,
  active:, href:, **opts); link or button; full_width: for equal footprint;
  selected style isolated in .segmented-control__segment--active so a controller
  can toggle it as one class.
- .segmented-control recipe in components.css.
- Migrate budgets/_budget_tabs; budget_filter_controller now toggles the single
  --active class instead of five raw utility classes.

Verified in-browser: dark active pill reads (gray-700 on near-black track);
filter toggle still works. Tests + rubocop clean.

Deferred (follow-up): auth sign-in/up switch, transaction-type tabs, and other
bespoke segmented controls — same primitive, one migration each.

* fix(a11y): expose segmented-control selection + derive active from filter param

- DS::SegmentedControl: set aria-current (links) / aria-pressed (buttons) from
  the segment's active state so screen readers announce the selection.
- budget_filter_controller: mirror aria-pressed when it toggles the active class.
- _budget_tabs: compute each segment's initial active: from params[:filter] so
  a ?filter=over_budget request server-renders the correct pill (no flash before
  Stimulus runs). Addresses CodeRabbit reviews on #2145.

* fix(ds): close unterminated segmented-control CSS rule

The --active rule swallowed the table-scroll block's comment opener and
never closed, so the Tailwind build died with 'Missing closing } at
@layer components' and both test jobs failed at boot. Restore the
closing brace and the /* opener.

Also add the budgets.show.filter.aria_label locale key the budget tabs
view referenced only through its inline default.

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>

* fix(ds): one height rail for icon and text buttons (#2202)

* fix(ds): put icon buttons on the text-button height rail

Icon-only DS::Button containers were 32/44/48px squares while text
buttons of the same nominal size render ~28/36/48px tall, so every
mixed header row (icon menu trigger next to text buttons — the
transactions index, account pages, the app header) sat misaligned.

- buttonish SIZES: icon containers now share the text rail
  (sm w-7, md w-9, lg w-12 unchanged).
- DS::Popover's hand-rolled w-11 trigger joins the rail at w-9.
- The layout's hand-rolled privacy toggle (mobile + desktop) matches
  the md icon-button chrome: w-9, rounded-lg, container-inset hover —
  it sat at w-8 with a different hover next to a DS icon button.
- DS::Select's panel adopts shadow-border-lg, the elevation Menu and
  Popover already use, replacing the weaker shadow-lg+border-xs combo.

Measured on the transactions header after the change: 36/38/36px.

* fix(ds): keep the 44px touch target on coarse pointers

The height rail trades icon-button size for row alignment, which is a
pointer-precision tradeoff: WCAG 2.5.5's 44x44 minimum is about
fingers, not mice. sm/md icon containers (and the two off-rail
consumers: the popover trigger and the layout privacy toggles) gain
pointer-coarse:w-11/h-11, so touch devices keep the full target while
fine-pointer layouts get the aligned 36px row.

Measured via Playwright: desktop 36x36, iPhone emulation 44x44 on both
the menu trigger and the privacy toggle.

* fix(sync-toast): morph refresh, defer behind modals, DS conformance (#2105)

* fix(sync-toast): morph refresh, defer behind modals, DS conformance

Follow-up to #1964 (addresses #2071).

- Refresh via Turbo morph visit instead of window.location.reload, so
  scroll position and data-turbo-permanent elements (the AI chat panel)
  survive and there is no white flash.
- Defer the toast while a <dialog> is open and reveal it on close. A
  refresh mid-modal closes the dialog and discards its in-progress input,
  which is the exact data loss this toast exists to prevent. Handles
  stacked modals.
- Refresh CTA and close button now use DS::Button (secondary / icon). The
  close is always visible, inside the card, focusable, and has an
  aria-label; the old hover-only corner chip was unreachable on touch and
  not keyboard-focusable.
- Add role="status" / aria-live="polite" to the toast.
- Fix icon color: "inverse" is not a key in the icon helper color map, so
  it silently rendered no color class (dark icon on bg-info). Use "white",
  which maps to the functional text-inverse token.
- Tighten copy: "New data available" / "Refresh".
- Sync the broadcast comment with the actual replace/morph behavior.

* fix(sync-toast): detach deferred dialog listener on disconnect

A toast replaced by a newer broadcast_replace_to while a <dialog> was open kept
its 'close' listener attached, so the detached controller fired #reveal()/#arm()
when the dialog closed — a spurious auto-refresh from a stale toast (and repeated
syncs could queue several). Store the dialog + handler refs and remove the
listener in disconnect(). Flagged by codex + coderabbit on #2105.

* fix(sync-toast): re-check interaction and dialogs at refresh-fire time

The interaction check ran once at arm time but the refresh fired two
seconds later. The post-dialog reveal made that window matter: the user
closes a dialog sitting on a form, resumes typing, and the timer morphs
the page — wiping non-turbo-permanent input, the exact data-loss class
this toast exists to prevent. A dialog opened during the window had the
mirror problem (the refresh would close it).

Bail inside the callback instead, leaving the toast visible for a
manual refresh, matching the mid-form behavior. Also documents the
dialog-removed-without-close edge on the deferred listener.

* perf(transactions): preload new form options (#2189)

* perf(transactions): preload new form options

* refactor(transactions): reuse new form account scope

* perf(reports): collapse investment flow aggregates (#2190)

* perf(reports): collapse investment flow aggregates

* fix(reports): avoid shared-account flow duplication

* fix: Savings Goal Marked Reached While Still Short (#2180)

* fix: saving goal is marke while several states

* feat(enable_banking): support MFA/decoupled banks and harden session handling (#2174)

Decoupled/MFA banks (e.g. VR Bank in Holstein) were hard-blocked because the
authorize flow aborted whenever auth_methods[0] was DECOUPLED. Enable Banking's
hosted /auth page actually coordinates decoupled SCA and redirects back with a
code, so route these banks through it instead:

- Provider#start_authorization accepts and forwards an auth_method param
- EnableBankingItem#select_auth_method picks the best method
  (REDIRECT > DECOUPLED > EMBEDDED), filtering by psu_type and skipping hidden
  methods
- Shared begin_authorization! re-fetches ASPSP metadata on each authorize and
  reauthorize, so the method is always re-derived (no persistence required)
- Remove the DECOUPLED block in the controller

Also stop the integration from constantly reporting "session expired":

- Only a session-level GET /sessions 401/404 flips the connection to
  requires_update; per-account 401/404 are retried and no longer kill the
  whole connection
- Reconcile session_expires_at from the API's access.valid_until on every sync
- Treat an expired session as a graceful requires_update state instead of
  raising a bare error

No schema changes. Adds covering tests.

* fix: request change reach

---------

Co-authored-by: Tobias Rahloff <rahloff@gmail.com>

* Improve Russian i18n translations

* Improve Russian i18n translations

* Improve Russian i18n translations

* Improve Russian i18n translations

* No need for language-specific CHANGELOG.md file

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: tea <john.fx@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: ghost <49853598+JSONbored@users.noreply.github.com>
Co-authored-by: Guillem Arias Fauste <accounts@gariasf.com>
Co-authored-by: Blaž Dular <22869613+xBlaz3kx@users.noreply.github.com>
Co-authored-by: Sure Admin (bot) <sure-admin@splashblot.com>
Co-authored-by: Jonathan Chang <55106972+jonathanchang31@users.noreply.github.com>
Co-authored-by: Tobias Rahloff <rahloff@gmail.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-07-08 08:10:18 +02:00
2026-07-03 23:20:55 -07:00
2024-02-02 09:05:04 -06:00
2024-02-02 09:05:04 -06:00
2024-02-02 09:05:04 -06:00
2025-05-20 13:31:05 -05:00
2024-02-02 09:05:04 -06:00
2024-08-23 10:06:24 -04:00
2026-06-15 23:29:36 +02:00
2026-07-03 23:20:55 -07:00
2024-02-02 09:05:04 -06:00
2026-06-15 23:29:36 +02:00
2024-02-02 09:05:04 -06:00
2025-09-24 00:19:51 +02:00
2026-04-13 13:44:37 +02:00
2024-02-02 09:05:04 -06:00
2026-06-05 15:16:41 +02:00

Ask DeepWiki View performance data on Skylight Dosu Pipelock Security Scan

sure_shot

Deutsch | Español | Français | 日本語 | 한국어 | Português | Русский | 中文

Sure: The personal finance app for everyone

Get involved: DiscordWebsiteIssues

Important

This repository is a community fork of the now-abandoned Maybe Finance project.
Learn more in their final release doc.

Backstory

The Maybe Finance (archived/abandoned repo) team spent most of 20212022 building a full-featured personal finance and wealth management app. It even included an “Ask an Advisor” feature that connected users with a real CFP/CFA — all included with your subscription.

The business end of things didn't work out, and so they stopped developing the app in mid-2023.

After spending nearly $1 million on development (employees, contractors, data providers, infra, etc.), the team open-sourced the app. Their goal was to let users self-host it for free — and eventually launch a hosted version for a small fee.

They actually did launch that hosted version … briefly.

That also didnt work out — at least not as a sustainable B2C business — so now here we are: hosting a community-maintained fork to keep the codebase alive and see where this can go next.

Join us!

Hosting Sure

Sure is a fully working personal finance app that can be self hosted with Docker.

Forking and Attribution

This repo is a community fork of the archived Maybe Finance repo. Youre free to fork it under the AGPLv3 license — but wed love it if you stuck around and contributed here instead.

To stay compliant and avoid trademark issues:

  • Be sure to include the original AGPLv3 license and clearly state in your README that your fork is based on Maybe Finance but is not affiliated with or endorsed by Maybe Finance Inc.
  • "Maybe" is a trademark of Maybe Finance Inc. and therefore, use of it is NOT allowed in forked repositories (or the logo)

Performance Issues

With data-heavy apps, inevitably, there are performance issues. We've set up a public dashboard showing the problematic requests seen on the demo site, along with the stacktraces to help debug them.

https://www.skylight.io/app/applications/s6PEZSKwcklL/recent/6h/endpoints

Any contributions that help improve performance are very much welcome.

Local Development Setup

If you are trying to self-host the app, read this guide to get started.

The instructions below are for developers to get started with contributing to the app.

Requirements

  • See .ruby-version file for required Ruby version
  • PostgreSQL >9.3 (latest stable version recommended)
  • Redis > 5.4 (latest stable version recommended)

Getting Started

cd sure
cp .env.local.example .env.local
bin/setup
bin/dev

# Optionally, load demo data
rake demo_data:default

Visit http://localhost:3000 to view the app.

If you loaded the optional demo data, log in with these credentials:

  • Email: user@example.com
  • Password: Password1!

For further instructions, see guides below.

Setup Guides

One-click Install

Run on PikaPods

Deploy on Railway

Managed OpenClaw for Sure Finances

Managed OpenClaw for Sure Finances

License and Trademarks

Maybe and Sure are both distributed under an AGPLv3 license.

  • "Maybe" is a trademark of Maybe Finance, Inc.
  • "Sure" is not, and refers to this community fork.

Alt

Description
No description provided
Readme AGPL-3.0 117 MiB
Languages
Ruby 74.3%
HTML 13.7%
Dart 7.6%
JavaScript 3.6%
CSS 0.3%
Other 0.3%