* fix(design-system): DS::Button a11y audit Closes #1738. Four concrete fixes surfaced by the savings-goals audit + #1737 universal checklist: 1. Focus ring (WCAG 2.4.7). `base.css` had `focus-visible:outline-gray-900` which is **1.07:1** against the primary button's gray-900 background — invisible. Widen to `outline-2 outline-offset-2`, place outline outside the button via offset, and add a dark-mode `outline-white` so the ring is always visible against the page chrome regardless of the button surface. 2. Touch target (WCAG 2.5.5). Icon-only buttons at the default `:md` size were `w-9 h-9` = 36×36, below the 44×44 enhanced target. Bump `md.icon_container_classes` to `w-11 h-11` and `lg.icon_container_classes` to `w-12 h-12` to keep the size scale intact. `sm` stays at 32×32 (already passes WCAG 2.5.8 AA's 24×24 minimum; intentional compact-density variant). 3. Default button type. `content_tag(:button, ...)` inherits the HTML default `type="submit"`, so a DS::Button rendered inside a form steals Enter-key submission from the first text input (reproducible in the form stepper). Default to `type="button"` in the non-`href` branch; existing form submitters pass `type: "submit"` explicitly and continue to work. The `button_to` (href) branch keeps the submit default because button_to wraps its own form. 4. Icon-only accessible name. Icon-only buttons render no text node, so AT users hear "button" with no name. Derive a humanized aria-label from the icon key (e.g. `icon: "more-horizontal"` → `aria-label="More horizontal"`); explicit `aria: { label: }` on the caller still wins. Soft fallback — callers should still pass meaningful labels for richer copy. Plus: replace the stale `fg-white` icon class on the destructive variant with `text-inverse` (the `fg-*` namespace was deprecated in #1626 so `fg-white` resolved to nothing; the icon was using its helper-default color rather than the white the design intended). Out of scope: - Menu avatar trigger (custom 36×36 button bypassing DS::Button) — belongs to #1743 DS::Menu audit. - DS::FilledIcon `lg` size container (decorative, not interactive) — belongs to #1742. * fix(design-system): force type=submit on StyledFormBuilder#submit The DS::Button default-type-button change in the previous commit broke every `form.submit "Log in"` callsite because `StyledFormBuilder#submit` (app/helpers/styled_form_builder.rb) renders a DS::Button under the hood with no explicit `type:`. After the default flip, those submit buttons rendered as `type="button"`, so submitting forms (login, password reset, every form using `form.submit`) silently no-ops. CI surfaced this via ~30 system tests failing in the `sign_in` helper, which couldn't get past the login page. Pin `type: "submit"` on the DS::Button rendered by `StyledFormBuilder#submit`. The 22 view-level `f.submit` / `render DS::Button.new(type: :submit, ...)` callers already pass type explicitly and are unaffected. * fix(review): href-branch type-button bug + focus-ring tokens + profile Save submit CodeRabbit P1+P2 review on #1840: 1. button.rb: `merged_opts.delete(:href)` always returned nil because Buttonish#initialize strips :href from opts into @href, so the `if href.blank?` guard was ALWAYS true. Every DS::Button rendered via button_to (the href branch) got `type="button"` on the inner button, breaking submission of those button_to-generated forms (e.g. imports/_ready.html.erb publish button, imports/_failure.html.erb try-again button). Drop the local `href = merged_opts.delete(:href)` so the guard now reads the @href reader, leaving the href branch's HTML default intact. 2. settings/profiles/show.html.erb: the Save button is rendered with `render DS::Button.new(...)` inside `styled_form_with` (not via form.submit), so the StyledFormBuilder#submit type-pin from624e9794doesn't cover it. Pass `type: :submit` explicitly so the profile form submits again under the default-type-button policy. 3. base.css: replace raw `outline-gray-900` / `outline-white` with the established alpha-ring focus pattern (focus-visible:ring-alpha-black-300 + theme-dark:ring-alpha-white-300) already used by app/components/settings/provider_card.html.erb and sure-design-system/components.css. Keeps a11y focus ring while using DS tokens. * fix(review): add type: :submit to DS::Button submitters inside forms CI test_system on #1840 surfaced 6 failures (confirm-dialog close, property create/edit, transaction filter apply) caused by the same gap thatdb563f3dstarted addressing: the default-type-button policy on DS::Button means every \`render DS::Button.new(...)\` inside a \`<form>\` (or \`styled_form_with\`) that relies on the HTML default to submit is now an inert \`type="button"\`. Audited every \`render DS::Button.new(\` callsite repo-wide for the combination (no \`type:\`, no \`href:\`, inside a form context) and pinned \`type: :submit\` explicitly on the 12 forms that need it: - layouts/shared/_confirm_dialog.html.erb: Confirm button inside the global \`<form method=\"dialog\">\` — fixes test_should_allow_revoking_API_key_with_confirmation. - properties/{new,edit,balances}.html.erb: Save/Next submitter inside \`styled_form_with\` — fixes test_can_create_property_account, test_can_persist_property_subtype. - transactions/searches/_menu.html.erb: Apply inside the filter form — fixes test_can_filter_uncategorized_transactions, test_all_filters_work_and_empty_state_shows_if_no_match, test_can_open_filters_and_apply_one_or_more. - transactions/bulk_updates/new.html.erb: Save in bulk-edit drawer. - account_sharings/show.html.erb: Save in account-sharing form. - category/deletions/new.html.erb, tag/deletions/new.html.erb: destructive + safe submit buttons in deletion dialog forms. - family_merchants/merge.html.erb: Submit in merge form. - subscriptions/upgrade.html.erb: contribute_and_support_sure submit. - rules/_category_rule_cta.html.erb: Dismiss inside the rule_prompts_disabled form. Cancel/close DS::Button instances inside these same forms intentionally keep the \`type=button\` default since they drive JS-only actions (\`DS--dialog#close\`, \`DS--menu#close\`). * fix(review): add type: :submit to 4 remaining form-context DS::Button callers Second sweep for the same default-type-button regression that24c517ebfixed for 12 callsites. The latest CI run on this branch narrowed the failures from 6 to 2 (the property wizard's Address step still failed because that view was not in the first sweep). Audited via a wider 4000-char form-context window: - app/views/properties/address.html.erb: Save inside styled_form_with — fixes the remaining test_can_create_property_account + test_can_persist_property_subtype by letting Step 3 of the property wizard complete. - app/views/onboardings/goals.html.erb: Submit inside form_with so the onboarding goals step submits. - app/views/account_sharings/show.html.erb (owner-side form): Save button for the family-share permissions form (the non-owner Save was already fixed in24c517eb). - app/views/transactions/_attachments.html.erb: Upload inside styled_form_with — kept the JS-driven hook (attachment_upload_target) but explicit type:submit covers the no-JS fallback. * fix(review): pin type=submit on the Save currencies button Codex P1 (third pass) caught one more in-form DS::Button I missed in the earlier sweeps: \`app/views/settings/preferences/show.html.erb:185\` renders the Save currencies submit deep inside a long \`styled_form_with\` block. The form-context scan I used had a finite look-back window which missed it because the matching \`styled_form_with\` opener sits ~80 lines / 4k+ characters above the button. Switched to a whole-file scan to confirm no further callsite remains.
Deutsch | Español | Français | 日本語 | 한국어 | Português | Русский | 中文
Sure: The personal finance app for everyone
Get involved: Discord • Website • Issues
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 2021–2022 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 didn’t 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. You’re free to fork it under the AGPLv3 license — but we’d 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-versionfile 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
- Mac dev setup
- Linux dev setup
- Windows dev setup
- Dev containers - visit this guide
One-click Install
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.
