Kosovo was missing from the COUNTRY_MAPPING in LanguagesHelper. Added Kosovo with ISO 3166-1 alpha-2 code XK and flag emoji 🇽🇰. The entry is placed in alphabetical order between Kuwait (KW) and Kyrgyzstan (KG) to maintain consistency with the existing list. Fix Investment account subtype not saving on creation (#1039) * Add permitted_accountable_attributes for investments * Include fields_for for accountable subtype selection feat: Add tag badge in filter window (#1038) * feat: Add tag badge in filter window * fix: validate Tag color attribute as hex format and increase transparency mix in border color * fix: use fallback for tag color fix/qol: Add Callback URL the Enable Banking Instructions (#1060) * fix/qol: Add wich Callback URL to use to the Enable Banking Instructions * CodeRabbit suggestion * CodeRabbit suggestion * Skip CI failure on findings --------- fix: Update PWA icons to use current logo (#1052) * fix: Update PWA icons to use current logo (#997) Replace outdated android-chrome-192x192.png and logo-pwa.png with the current logo. The old icons showed the previous branding (cyan border / old logomark) which appeared when creating web shortcuts on smartphones. Also add the 192x192 icon entry to the PWA manifest for better Android home screen icon support. * fix: Replace transparent background with solid #F9F9F9 in 192x192 PWA icon The android-chrome-192x192.png had an RGBA transparent background which can cause display issues on Android home-screen shortcuts. Regenerated with a solid #F9F9F9 background to match theme_color/background_color in the PWA manifest and the 512x512 icon. --------- Bump version to next iteration after v0.6.8-alpha.13 release Use Langfuse client trace upsert API (#1041) Replace direct trace.update calls with client trace upserts so OpenAI provider is compatible with langfuse-ruby 0.1.6 behavior. Add richer warning logs that include full exception details for trace creation, trace upserts, and generation logging failures. Add tests for client-based trace upserts and detailed error logging. Add build ID to Flutter app version display Add MCP server endpoint for external AI assistants (#1051) * Add MCP server endpoint for external AI assistants Expose Sure's Assistant::Function tools via JSON-RPC 2.0 at POST /mcp, enabling external AI clients (Claude, GPT, etc.) to query financial data through the Model Context Protocol. - Bearer token auth via MCP_API_TOKEN / MCP_USER_EMAIL env vars - JSON-RPC 2.0 with proper id threading, notification handling (204) - Transient session (sessions.build) to prevent impersonation leaks - Centralize function_classes in Assistant module - Docker Compose example with Pipelock forward proxy - 18 integration tests with scoped env (ClimateControl) * Update compose for full Pipelock MCP reverse proxy integration Use Pipelock's --mcp-listen/--mcp-upstream flags (PR #127) to run bidirectional MCP scanning in the same container as the forward proxy. External AI clients connect to port 8889, Pipelock scans requests (DLP, injection, tool policy) and responses (injection, tool poisoning) before forwarding to Sure's /mcp endpoint. This supersedes the standalone compose in PR #1050. * Fix compose --preset→--mode, add port 3000 trust comment, notification test Review fixes: - pipelock run uses --mode not --preset (would prevent stack startup) - Document port 3000 exposes /mcp directly (auth still required) - Add version requirement note for Pipelock MCP listener support - Add test: tools/call sent as notification does not execute Feat/Abstract Assistant into module with registry (#1020) * Abstract Assistant into module with registry (fixes #1016) - Add Assistant module with registry/factory (builtin, external) - Assistant.for_chat(chat) routes by family.assistant_type - Assistant.config_for(chat) delegates to Builtin for backward compat - Assistant.available_types returns registered types - Add Assistant::Base (Broadcastable, respond_to contract) - Move current behavior to Assistant::Builtin (Provided + Configurable) - Add Assistant::External stub for future OpenClaw/WebSocket - Migration: add families.assistant_type (default builtin) - Family: validate assistant_type inclusion - Tests: for_chat routing, available_types, External stub, blank chat guard * Fix RuboCop layout: indentation in Assistant module and tests * Move new test methods above private so Minitest discovers them * Clear thinking indicator in External#respond_to to avoid stuck UI * Rebase onto upstream main: fix schema to avoid spurious diffs - Rebase feature/abstract-assistant-1016 onto we-promise/main - Rename migration to 20260218120001 to avoid duplicate version with backfill_crypto_subtype - Regenerate schema from upstream + assistant_type only (keeps vector_store_id, realized_gain, etc.) - PR schema diff now shows only assistant_type addition and version bump --------- Add Pipelock agent security scan to CI (#1049) * Add Pipelock agent security scan to CI Scans PR diffs for leaked secrets and agent security risks. Zero config, runs on every PR to main. * Retrigger CI (v1 action tag now available) * Harden checkout: persist-credentials false Pipelock only reads local git history for diff scanning, no auth token needed in .git/config. Improvements to Flutter client (#1042) * Chat improvements * Delete/reset account via API for Flutter app * Fix tests. * Add "contact us" to settings * Update mobile/lib/screens/chat_conversation_screen.dart * Improve LLM special token detection * Deactivated user shouldn't have API working * Fix tests * API-Key usage * Flutter app launch failure on no network * Handle deletion/reset delays * Local cached data may become stale * Use X-Api-Key correctly! --------- Skip unnecessary sync when account balance unchanged on update (#1040) The update action was calling set_current_balance (which triggers sync_later internally) on every form submission, even when the balance hadn't changed. This caused the account to enter a syncing state, replacing the visible balance with a pulsing skeleton placeholder until the sync completed. Now we compare the submitted balance against the current value and only call set_current_balance when it actually differs. Also removes a redundant sync_later call that duplicated the one already inside set_current_balance. feat: Add merchant logo in filter selection (#1037) * feat: Add merchant logo in filter selection * fix: move external div outside of if statement Sync Helm chart and Rails app versions in CI and release workflows (#1030) * Sync Helm chart and Rails app versions in CI and release workflows - values.yaml: default image.tag to "" so it uses Chart.appVersion (was hardcoded to stale "0.6.6" while app was at 0.6.8-alpha.13) - chart-ci.yml: add version-sync job that fails if version.rb, Chart.yaml version, and Chart.yaml appVersion diverge; trigger on version.rb changes too - chart-release.yml: derive chart version from version.rb (single source of truth) instead of auto-incrementing independent chart-v* tags https://claude.ai/code/session_01Eq3WHBn3Uwjezxb6ctdjMB * Default to `false` AI_DEBUG_MODE * Apply suggestions from CodeRabbit --------- Fix mobile-build using tag name instead of branch for filenames When workflow_dispatch is triggered from a tag (e.g. v0.6.7) instead of a branch, github.ref_name returns the tag name, causing filenames like sure-v0.6.7-{stamp}.apk instead of sure-main-{stamp}.apk. Guard against this by checking github.ref_type and falling back to the repository's default branch when a tag is selected. https://claude.ai/code/session_01TDfNkNxQ6uWxQxLAwJY5Qa Add workflow to build mobile apps from main without tagging (#1028) * Add workflow to build mobile apps from main without tagging Adds a new `mobile-main-build.yml` workflow that can be triggered manually via workflow_dispatch to build Android APK and iOS unsigned builds from the main branch. Uses a `main-YYYYMMDDHHMI` stamp for versioning (e.g. sure-main-202602181259.apk) and updates the gh-pages README.md MOBILE_DOWNLOADS section with direct download links. https://claude.ai/code/session_01TDfNkNxQ6uWxQxLAwJY5Qa * Rename to mobile-build.yml and support any branch Instead of hardcoding "main", derive the branch name from github.ref_name, sanitise it for filenames/tags (slashes → hyphens), and use it throughout: version, tag, release notes, and gh-pages README. The checkout step now explicitly pins ref: ${{ github.ref }} so the tag always matches the dispatched branch. Example artifacts from main: sure-main-202602181259.apk Example from feature/foo: sure-feature-foo-202602181259.apk https://claude.ai/code/session_01TDfNkNxQ6uWxQxLAwJY5Qa * Add continue-on-error to artifact download steps If either the Android or iOS build fails, the download step would hard-fail and abort the release job before the conditional logic in "Prepare release assets" could handle the partial result. Adding continue-on-error lets the workflow proceed so a release can still be created with whichever artifacts succeeded. https://claude.ai/code/session_01TDfNkNxQ6uWxQxLAwJY5Qa * Fix in-place replacement of MOBILE_DOWNLOADS section in README The previous logic stripped the marker block then appended the new section at the end of the file, causing it to drift to the bottom on every run. Now writes the section to a temp file and uses awk to replace the block between the markers in-place, preserving the section's original position in the README. https://claude.ai/code/session_01TDfNkNxQ6uWxQxLAwJY5Qa --------- Bump version to next iteration after v0.6.8-alpha.12 release Enable inclusion of hidden files in helm chart package Remove OPENAI_URI_BASE and OPENAI_MODEL from Helm secret values (#1025) These are optional app configuration values (not secrets), and listing them in rails.secret.values alongside required keys like SECRET_KEY_BASE makes users think they must be specified. Users who need them can set them via rails.extraEnv or rails.settings instead. https://claude.ai/code/session_01BP8Nr2cZWDdu9zGL9vD8Mw fix: Enable Banking DNS issues and provide better UI sync feedback (#1021) * fix(docker): add explicit DNS config to fix enable banking sync * fix(enable-banking): surface sync errors in the UI * fix: add spaces inside array brackets for RuboCop * fix(enable-banking): surface sync errors and partial failures in UI chore(deps): bump nokogiri from 1.18.9 to 1.19.1 (#1024) Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.18.9 to 1.19.1. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.18.9...v1.19.1) --- updated-dependencies: - dependency-name: nokogiri dependency-version: 1.19.1 dependency-type: indirect ... Refactor GitHub Actions workflows (#1023) * Unify release workflows and add chart/mobile wrappers * Update chart CI to kube 1.25 * Fetch tagged commit before pushing release branch * Old `azure/setup-helm` * Base chart dispatch version on existing chart tags * `grep` failure with `pipefail` bypasses the user-friendly error message * `gh-pages` push lacks retry logic * Auto-incremented chart tag collision * `grep -Ev` pipeline will crash * Missed one feat: New tag creation UI (#1014) * feat: Update tag creation UI * fix: remove unused target * fix: remove connect/disconnect functions * fix: remove unnecessary target Fix crypto subtype for trades api (#1022) * fix: crypto subtype not persisted by permitting :subtype in CryptosController * Backfill crypto subtype for existig accounts so Trades API works * fix: backfill only unlinked cryptos; use raw SQL in migration; deterministic redirect in test * Update schema.rb for BackfillcryptoSubtypeForTrades migration --------- fix: add logic to skip future pending transactions and add cleanup ta… (#1011) * fix: add logic to skip future pending transactions and add cleanup task for stuck entries * Update lib/tasks/cleanup_stuck_pending_lunchflow.rake * Update app/models/lunchflow_entry/processor.rb * fix(coderabbit): assertions use entryable instead of transaction for pending state checks * chore(codex): add comments to clarify handling of pending transactions, exclude self in cleanup task * fix(coderabbit): memoize external_id --------- fix: show Edit button in account view bulk selection bar (#1002) Fix foreign currency accounts using wrong exchange rate in balance sheet totals (#1010) Balance sheet totals and accountable type summaries used a SQL JOIN on exchange_rates matching only today's date, which returned NULL (defaulting to 1:1) when no rate existed for that exact date. This caused foreign currency accounts to show incorrect totals. Changes: - Refactor BalanceSheet::AccountTotals to batch-fetch exchange rates via ExchangeRate.rates_for, with provider fallback, instead of a SQL join - Refactor Accountable.balance_money to use the same batch approach - Add ExchangeRate.rates_for helper for deduplicated rate lookups - Fix net worth chart query to fall back to the nearest future rate when no historical rate exists for a given date - Add composite index on accounts (family_id, status, accountable_type) - Reuse nearest cached exchange rate within a 5-day lookback window before calling the provider, preventing redundant API calls on weekends and holidays when providers return prior-day rates https://claude.ai/code/session_01GyssBJxQqdWnuYofQRjUu8 Syntax error in workflow Bump version to next iteration after v0.6.8-alpha.11 release Default tap on URL opens settings No credentials = no TestFlight Upload to TestFlight after `release` / fix version name Fix Android icon color Add demo account to Flutter client also Default login for Flutter client beta Wire TestFlight up to mobile releases iOS build fixes/prep for TestFlight LLC is Sure Finances, keep it the same New icon set and name Safe area around icon Add flutter_export_environment.sh to .gitignore Ignore changes in `mobile/` directory for publish workflow Enhance mobile release workflow with dispatch and script Added workflow_dispatch trigger and updated GitHub Release step to use a script for release notes and asset uploads. New icons New icon Fix version number for Android Version number in Gradle build Version number to bundle files More .gitignore noise chore(deps): bump rack from 3.1.18 to 3.1.20 (#1013) Bumps [rack](https://github.com/rack/rack) from 3.1.18 to 3.1.20. - [Release notes](https://github.com/rack/rack/releases) - [Changelog](https://github.com/rack/rack/blob/main/CHANGELOG.md) - [Commits](https://github.com/rack/rack/compare/v3.1.18...v3.1.20) --- updated-dependencies: - dependency-name: rack dependency-version: 3.1.20 dependency-type: indirect ... Update Flutter iOS run command in `mobile/README.md` fix: Remove additional padding from JS controller and add directly as a class (#1007) PDF ai import (#1006) Add support to review transactions for AI pdf import Bump version to next iteration after v0.6.8-alpha.10 release Improve tests Add new columns and sorting to admin users list (#1004) * Add trial end date to admin users list * Add new columns * Regression feat: Update gh-pages README with latest mobile release links (#1003) Add steps to the mobile-release workflow that checkout the gh-pages branch and update its README.md with direct download links to the latest Flutter mobile clients (Android APK, debug APK, iOS unsigned build). Uses HTML comment markers for idempotent updates on subsequent releases. https://claude.ai/code/session_01GuUjjmMzxvdSwfvhrjvJr1 Fix: Handle missing category in SetTransactionCategory executor (#1001) fix: Transfers were not syncing between accounts (#987) * fix: Include investment_contribution in transfer? check and protect transfer entries from sync Transfer transactions with kind "investment_contribution" were not recognized as transfers by the UI, causing missing +/- indicators, "Transfer" labels, and showing regular transaction forms instead of transfer details. Also adds user_modified: true to entries created via TransferMatchesController and SetAsTransferOrPayment rule action to protect them from provider sync overwrites, matching the existing behavior in Transfer::Creator. https://claude.ai/code/session_019BZ5Z1aqKSK3cRdR81P5Jg * fix: Centralize transfer/budget kind constants for consistent investment_contribution handling Define TRANSFER_KINDS and BUDGET_EXCLUDED_KINDS on Transaction to eliminate hard-coded kind lists scattered across filters, rules, and analytics code. investment_contribution is now consistently treated as a transfer in search filters, rule conditions, and UI display (via TRANSFER_KINDS), while budget analytics correctly continue treating it as an expense (via BUDGET_EXCLUDED_KINDS). https://claude.ai/code/session_019BZ5Z1aqKSK3cRdR81P5Jg * fix: Update tests for consistent investment_contribution as transfer kind - search_test: loan_payment is now in TRANSFER_KINDS, so uncategorized filter correctly excludes it (same as funds_movement/cc_payment) - condition_test: investment_contribution is now a transfer kind, so it matches the transfer filter rather than expense filter https://claude.ai/code/session_019BZ5Z1aqKSK3cRdR81P5Jg * fix: Eliminate SQL injection warnings in Transaction::Search Replace string-interpolated SQL with parameterized queries: - totals: use sanitize_sql_array with ? placeholders - apply_category_filter: pass TRANSFER_KINDS as bind parameter - apply_type_filter: use where(kind:)/where.not(kind:) and parameterized IN (?) for compound OR conditions - Remove unused transfer_kinds_sql helper https://claude.ai/code/session_019BZ5Z1aqKSK3cRdR81P5Jg --------- feat: Display dashboard as a 2-columns grid on big screens (#1000) * feat: display 2 columns grid in dashboard for wide screens * fix: update sortable controller to consider X/Y coordinates * fix: lint issues + missing variable init Flutter title and icon alignment fixes Small Flutter UI tweaks Intro mode in Flutter client fixes Replace text-tertiary with text-subdued in views (#999) * Replace text-tertiary with text-subdued in views Replace usages of the text-tertiary utility with text-subdued across several view partials to standardize subdued text styling because text-tertiary does not exist in the design system (reports, doorkeeper auth, simplefin items). Also adjust the net worth empty-liabilities markup to use a grid layout for consistent spacing, and update the related controller test selector to match the new CSS class. * Standardize empty net worth message markup Replace inconsistent markup and classes for empty asset/liability sections in the net worth partial. Swap text-secondary/p-2/text-center for text-subdued with unified padding (py-3 px-4 lg:px-6), and simplify the liabilities block from a grid/div to a single paragraph for consistent styling and spacing. Fix separators in breakdown table view (#996) * Fix separators in breakdown table view Correct conditional logic for rendering column separators (rulers) in the reports breakdown table. The top-level check now compares idx to groups.size instead of group.size, and the subcategory check compares idx to group[:subcategories].size. This ensures separators are shown between categories and subcategories correctly, avoiding missing or extra rulers. * Fix subcategory index variable name in partial Rename the inner loop index from `idx` to `sub_idx` in app/views/reports/_breakdown_table.html.erb to avoid shadowing the outer `idx`. This ensures the conditional that renders the separator (`shared/ruler`) uses the correct index for subcategories, preventing incorrect rendering of separators between subcategory rows. * Fix conditional block order in breakdown table Reorder ERB tags to properly nest the subcategory conditional and the ruler render in the reports breakdown partial. This ensures the divider is only rendered between subcategories and prevents mismatched ERB/end tags that could break template rendering. fix: Viewport issue in PWA (#995) * fix: move safe-area padding from body/HTML to navbars. Add script to compute app height dynamically. * fix: Initialize sankey tooltip with top-0 to avoid overflow * fix: add fallback to HTML height * fix: properly set bottom spacing and use position fixed for bottom navbar * fix: move viewport controller initialization fix: locale-dependent category duplication bug (#956) * fix: locale-dependent category duplication bug * fix: use family locale for investment contributions category to prevent duplicates and handle legacy data * Remove v* tag trigger from flutter-build to fix double-runs publish.yml already calls flutter-build via workflow_call on v* tags, so the direct push trigger was causing duplicate workflow runs. * Refactor mobile release asset flow * fix: category uniqueness and workflow issues * fix: fix test issue * fix: solve test issue * fix: resolve legacy problem * fix: solve lint test issue * fix: revert unrelated changes --------- fix: prevent New rule modal from closing when removing conditions or actions (#991) fix: prevent value overflow in Assets vs Liabilities card (#992) * fix: prevent value overflow in Assets vs Liabilities card Fixes issue where large asset/liability values overflow the container when AI side panel is open and reduces horizontal space. Changes: - Added flex-wrap to allow values to wrap to next line if needed - Added break-all to both asset and liability values for long numbers - Added shrink-0 to minus sign to prevent it from shrinking Fixes #976 * refactor: use break-words instead of break-all per code review Changed from break-all to break-words for currency values to prevent awkward mid-number breaks (e.g., $1,234,5 / 67.89). break-words only breaks when content overflows and keeps values intact when possible, providing cleaner line breaks while still preventing overflow. --------- fix: inverted Buy/Sell type selection by changing amount.negative to amount.positive in trade edit views (#952) Bump version to next iteration after v0.6.8-alpha.9 release Show disabled import options when no accounts exist (#977) * Show disabled import options before accounts exist Keep account-dependent import choices visible on /imports/new and render them as disabled with guidance when no accounts are available. * Refactor disabled import options: extract partial, fix accessibility (#986) - Extract _import_option partial to eliminate duplicated enabled/disabled markup across TransactionImport, TradeImport, and MintImport (also used by AccountImport, CategoryImport, RuleImport for consistency) - Replace misleading chevron-right with lock icon in disabled state - Add aria-disabled="true" for screen reader accessibility - Remove redundant default: parameter from t() call - Fix locale key ordering (requires_account after import_* keys) - Fix extra blank line in test file - Add assertion for aria-disabled attribute in test https://claude.ai/code/session_016j9tDYEBfWX9Dzd99rAYjX * Tailwind fixes --------- Expose ui_layout and ai_enabled to mobile clients and add enable_ai endpoint (#983) * Wire ui layout and AI flags into mobile auth Include ui_layout and ai_enabled in mobile login/signup/SSO payloads, add an authenticated endpoint to enable AI from Flutter, and gate mobile navigation based on intro layout and AI consent flow. * Linter * Ensure write scope on enable_ai * Make sure AI is available before enabling it * Test improvements * PR comment * Fix review issues: test assertion bug, missing coverage, and Dart defaults (#985) - Fix login test to use ai_enabled? (method) instead of ai_enabled (column) to match what mobile_user_payload actually serializes - Add test for enable_ai when ai_available? returns false (403 path) - Default aiEnabled to false when user is null in AuthProvider to avoid showing AI as available before authentication completes - Remove extra blank lines in auth_provider.dart and auth_service.dart https://claude.ai/code/session_01LEYYmtsDBoqizyihFtkye4 --------- fix: Handle empty compound conditions on rules index (#965) * fix: Handle empty compound conditions on rules index * fix: avoid contradictory rule condition summary on /rules * refactor: move rules condition display logic from view to model * fix: localize rule title fallback and preload conditions in rules index Document merchants API endpoints (#980) Add rswag request specs for merchants index/show and define a MerchantDetail schema used by the docs. Update the generated OpenAPI document with merchants paths and schema. Add family moniker selection and dynamic UI labels (#981) * Add family moniker selection and dynamic UI labels Introduce a Family moniker persisted in the database with allowed values Family/Group, add required onboarding selection for it, and thread moniker-aware copy through key user-facing views and locales. Also add helper methods and tests for onboarding form presence and family moniker behavior. * Small copy edits/change moniker question order * Conditional Group/Family onboarding flow fixes * Fix label * Grouping of fields * Profile Info page Group/Family changes * Only admins can change Group/Family moniker * Repetitive defaults * Moniker in Account model * Moniker in User model * Auth fix * Sure product is also a moniker --------- Disable Turbo prefetch on dashboard outflow category links Hovering over category links in the outflow donut chart triggered Turbo 8's default link prefetching, which made a real request to the transactions controller. The controller's store_params! before_action saved those filter params (category + date range) to the session. When the user later navigated to /transactions via the nav menu, the stored params were restored, showing an unexpected filtered view. Adding data-turbo-prefetch="false" prevents the prefetch on hover while preserving the intended click-to-navigate behavior. https://claude.ai/code/session_01Na7AF1wyidPwFdPq5w8oaw Flutter login polish (#973) * Skip config screen by setting demo site default * Small copy edits * Login page polish Mobile-only GitHub workflow builds (#975) * Mobile build only * Fix copy on debug * PR review comments Bump version to next iteration after v0.6.8-alpha.8 release Bring back `/reports` link Fix flaky expectations in import-related tests (#963) Fix tests Generalize from PDF import to just files Index all PDF imports into vector store with type metadata Update backend table with status and requirements Clarify status of non-OpenAI vector store Add `Family` vector search function call / support for document vault (#961) * Add SearchFamilyImportedFiles assistant function with vector store support Implement per-Family document search using OpenAI vector stores, allowing the AI assistant to search through uploaded financial documents (tax returns, statements, contracts, etc.). The architecture is modular with a provider- agnostic VectorStoreConcept interface so other RAG backends can be added. Key components: - Assistant::Function::SearchFamilyImportedFiles - tool callable from any LLM - Provider::VectorStoreConcept - abstract vector store interface - Provider::Openai vector store methods (create, upload, search, delete) - Family::VectorSearchable concern with document management - FamilyDocument model for tracking uploaded files - Migration adding vector_store_id to families and family_documents table https://claude.ai/code/session_01TSkKc7a9Yu2ugm1RvSf4dh * Extract VectorStore adapter layer for swappable backends Replace the Provider::VectorStoreConcept mixin with a standalone adapter architecture under VectorStore::. This cleanly separates vector store concerns from the LLM provider and makes it trivial to swap backends. Components: - VectorStore::Base — abstract interface (create/delete/upload/remove/search) - VectorStore::Openai — uses ruby-openai gem's native vector_stores.search - VectorStore::Pgvector — skeleton for local pgvector + embedding model - VectorStore::Qdrant — skeleton for Qdrant vector DB - VectorStore::Registry — resolves adapter from VECTOR_STORE_PROVIDER env - VectorStore::Response — success/failure wrapper (like Provider::Response) Consumers updated to go through VectorStore.adapter: - Family::VectorSearchable - Assistant::Function::SearchFamilyImportedFiles - FamilyDocument Removed: Provider::VectorStoreConcept, vector store methods from Provider::Openai https://claude.ai/code/session_01TSkKc7a9Yu2ugm1RvSf4dh * Add Vector Store configuration docs to ai.md Documents how to configure the document search feature, covering all three supported backends (OpenAI, pgvector, Qdrant), environment variables, Docker Compose examples, supported file types, and privacy considerations. https://claude.ai/code/session_01TSkKc7a9Yu2ugm1RvSf4dh * No need to specify `imported` in code * Missed a couple more places * Tiny reordering for the human OCD * Update app/models/assistant/function/search_family_files.rb * PR comments * More PR comments --------- Fix property subtype not persisting on edit (#930) * Fix property subtype not persisting on edit * Add regression test for property subtype persistence This change introduces model specs and factories to cover property subtype persistence on update. FactoryBot setup and test dependencies were adjusted to support the new specs. * Add regression test for property subtype persistence * remove unused FactoryBot factories and test * remove FactoryBot in Gemfile.lock * Fix no-op regression test for property subtype update * Delete no-op property_test * add pimary_residence in properties fixtures * add capybara system test for property subtype persistence * fix spelling and indent * rename test to "can persist property subtype" --------- Bump version to next iteration after v0.6.8-alpha.7 release fix: restore drawer positioning for transaction modals on desktop (#857) (#896) * feat: Add responsive dialog behavior for transaction modals Add responsive option to DS::Dialog component that switches between: - Mobile (< 1024px): Modal style (centered) with inline close button - Desktop (≥ 1024px): Drawer style (right side panel) with header close button Update transaction, transfer, holding, trade, and valuation views to use responsive behavior, maintaining mobile experience while reverting desktop to drawer style like budget categories. Changes: - app/components/DS/dialog.rb: Add responsive parameter and helper methods - app/components/DS/dialog.html.erb: Apply responsive styling - app/views/*/show.html.erb: Add responsive: true and hide close icons on mobile * fix: Enhance close button accessibility in dialog components * fix: Refactor dialog component to improve close button handling and accessibility Include newer providers in automatic family sync (#934) * Include newer providers in automatic family sync Coinbase, CoinStats, Mercury, and SnapTrade all implement Syncable and have Syncer classes but were not listed in child_syncables, meaning their data only refreshed on manual sync button clicks. * refactor(syncer): Open/Closed principle for provider sync - Adding new providers requires modifying child_syncables (violates O/C) - plaid_items missing .active scope (bug: syncs deleted items) - snaptrade_items can exist without user registration → fails on sync - Scattered knowledge about 'ready to sync' logic 1. **Registry pattern**: SYNCABLE_ITEM_ASSOCIATIONS constant lists all provider associations that participate in family sync 2. **Encapsulated sync-readiness**: Each item model defines its own `syncable` scope that knows when it's ready for auto-sync: - Most providers: `syncable = active` (not scheduled for deletion) - SnapTrade: `syncable = active + user_registered` (has API creds) 3. **Single loop**: child_syncables iterates the registry, calling `.syncable` on each association - Adding a provider = add to registry + define syncable scope - Each model owns its 'ready to sync' business logic - Fixes plaid_items bug (now uses .active via .syncable) - Fixes snaptrade auto-sync failures (filters unregistered items) - Easy to extend with new conditions per provider - family/syncer.rb: Registry + dynamic collection - *_item.rb (7 files): Add `scope :syncable, -> { active }` - snaptrade_item.rb: Add syncable with user_registered filter * Fix rubocop bracket spacing in SnaptradeItem syncable scope fix: keep nav bar sticky at top (#943) * fix: keep nav bar sticky at top * fix: sticky on settings page * fix: keep padding in settings page * fix: make all settings page title sticky * fix: make buttons sticky with title * fix: set header bar min height * fix: mobile responsive * fix: reduce header bar feat: Add LLM prompt for API endpoint consistency (#949) * Add LLM prompt for API endpoint consistency (fixes #944) - Add .cursor/rules/api-endpoint-consistency.mdc: checklist that applies when editing app/controllers/api/v1, spec/requests/api/v1, or test/controllers/api/v1. Enforces (1) Minitest-only behavioral coverage for new endpoints, (2) rswag docs-only (no expect/assert), (3) same API key auth pattern in all rswag specs. - Reference the rule in AGENTS.md under API Development Guidelines. * Add tests for API endpoint consistency implementation - Minitest: test/api_endpoint_consistency_rule_test.rb checks rule file exists, globs, and all three sections (Minitest, rswag docs-only, API key auth) plus AGENTS.md reference. - Standalone: test/support/verify_api_endpoint_consistency.rb runs same checks without loading Rails (use when app fails to boot). - Rule: add mdc: links for Cursor, note valuations_spec OAuth outlier. * Address review: add --compliance check, CLAUDE.md section - Verification script: --compliance scans current APIs and reports rswag OAuth vs API key, missing Minitest for controllers, expect/assert. - CLAUDE.md: add Post-commit API consistency subsection under API Development Guidelines (links to rule, documents script + --compliance). --------- Remove Flipper and replace with ENV-driven FeatureFlags (#957) * Presence of valid DEFAULT_UI_LAYOUT is sufficient * Linter Normalize legacy SSO icon values before validation (#955) chore(deps): bump faraday from 2.13.2 to 2.14.1 (#953) Bumps [faraday](https://github.com/lostisland/faraday) from 2.13.2 to 2.14.1. - [Release notes](https://github.com/lostisland/faraday/releases) - [Changelog](https://github.com/lostisland/faraday/blob/main/CHANGELOG.md) - [Commits](https://github.com/lostisland/faraday/compare/v2.13.2...v2.14.1) --- updated-dependencies: - dependency-name: faraday dependency-version: 2.14.1 dependency-type: direct:production ... Bump version to next iteration after v0.6.8-alpha.6 release Remove reference to nonexistent Sidekiq::Throttled gem (#950) The sidekiq-throttled gem is not in the Gemfile, so including Sidekiq::Throttled::Job causes an uninitialized constant NameError at boot time, breaking production builds. https://claude.ai/code/session_01Bj7xgndJt28BcUHW1v1M9S Bump version to next iteration after v0.6.8-alpha.5 release Forgot to make test Flipper-conditional Add Intro UI feature flag First cut of a simplified "intro" UI layout (#265) * First cut of a simplified "intro" UI layout * Linter * Add guest role and intro-only access * Fix guest role UI defaults (#940) Use enum predicate to avoid missing role helper. * Remove legacy user role mapping (#941) Drop the unused user role references in role normalization and SSO role mapping forms to avoid implying a role that never existed. Refs: #0 * Remove role normalization (#942) Remove role normalization Roles are now stored directly without legacy mappings. * Revert role mapping logic * Remove `normalize_role_settings` * Remove unnecessary migration * Make `member` the default * Broken `.erb` --------- Implement Indexa Capital provider with real API integration (#933) * Add Indexa Capital provider scaffold Generate Indexa Capital provider scaffolding and align credential fields with the API authentication requirements. * Fix PR 926 lint and schema CI failures * Implement Indexa Capital provider with real API integration - Rewrite all broken view templates (were meta-ERB from code generator) - Create missing select_accounts.html.erb template - Implement real API calls: list_accounts via /users/me, get_holdings via /accounts/{number}/fiscal-results, get_account_balance via /accounts/{number}/performance - Add API token auth support (stored token > env token > credentials) - Add api_token column with encryption support - Redesign settings panel: API token prominent, credentials collapsible - Fix account balances display using performance endpoint portfolios - Fix accounts index empty-state guard missing indexa_capital_items - Simplify activities fetch job (no activities API endpoint exists) - Fix i18n interpolation (%%{ -> %{) throughout locale file * Add tests for Indexa Capital provider integration - IndexaCapitalItemTest: validations, credentials, scopes, sync status - IndexaCapitalAccountTest: upsert, holdings, account provider linking - Provider::IndexaCapitalTest: auth modes, API stubs, error handling - IndexaCapitalItemsControllerTest: CRUD, setup, linking, authorization - Fixtures for items (token + credentials) and accounts (mutual + pension) 52 tests, 98 assertions, 0 failures * Address code review feedback from PR #933 - Fix zero balance bug: use `nil?` instead of `present?` so 0 is stored - Fix has_indexa_capital_credentials? to check api_token (was ignored) - Fix build_provider to delegate to Provided concern (was ignoring token) - Fix IndexaCapital section outside encryption_error guard in settings - Add account_number sanitization to prevent path traversal in API URLs - Replace all skipped processor tests with real working tests - Add zero-balance and path-traversal test coverage 61 tests, 107 assertions, 0 failures * Address code review round 2: credentials validation, RuboCop, test quality - Fix RuboCop SpaceInsideArrayLiteralBrackets in credentials check - Chain where.not calls so all three username/document/password must be present - Require all three credentials (||) instead of any one (&&) in validate_configuration! - Move attr_reader to private to avoid exposing credentials publicly - Parse dates with Date.parse in extract_balance for robustness - Remove stale TODO and Crypto from supported_account_types - Order build_provider query deterministically by created_at - Replace no-op holdings assertion with meaningful assert_difference * Address code review round 3: JSON parse safety and test precision - Rescue JSON::ParserError on 2xx responses for clearer error messages - Fix weak balance assertion: set balance to 0 before processing, assert expected value (27093.01 = sum of holdings amounts) * Include Indexa Capital in automatic family sync Add indexa_capital_items to Family::Syncer#child_syncables so balances and holdings refresh on daily auto-sync and login sync, not only on manual sync button clicks. --------- Add REST API for holdings and trades (Discussion #905) (#918) * Add REST API for holdings and trades (Discussion #905) - Trades: GET index (filter by account_id, account_ids, start_date, end_date), GET show, POST create (buy/sell with security_id or ticker), PATCH update, DELETE destroy. Create restricted to accounts that support trades (investment or crypto exchange). Uses existing Trade::CreateForm for creation. - Holdings: GET index (filter by account_id, account_ids, date, start_date, end_date, security_id), GET show. Read-only; scoped to family. - Auth: read scope for index/show; write scope for create/update/destroy. - Responses: JSON via jbuilder (trade: id, date, amount, qty, price, account, security, category; holding: id, date, qty, price, amount, account, security, avg_cost). Pagination for index endpoints (page, per_page). * API v1 holdings & trades: validation, docs, specs - Holdings: validate date params, return 400 for invalid dates (parse_date!) - Trades: validate start_date/end_date, return 422 for invalid dates - Trades: accept buy/sell and inflow/outflow in update (trade_sell_from_type_or_nature?) - Trades view: nil guard for trade.security - Trades apply_filters: single join(:entry) when filtering - OpenAPI: add Trade/TradeCollection schemas, ErrorResponse.errors - Add spec/requests/api/v1/holdings_spec.rb and trades_spec.rb (rswag) - Regenerate docs/api/openapi.yaml * CI: fix Brakeman and test rate-limit failures - Disable Rack::Attack in test (use existing enabled flag) so parallel API tests no longer hit 429 from shared api_ip throttle - Add Brakeman ignore for trades_controller trade_params mass-assignment (account_id/security_id validated in create/update) - Trades/holdings API and OpenAPI spec updates * Trades: partial qty/price update fallback; fix PATCH OpenAPI schema - Fall back to existing trade qty/price when only one is supplied so sign normalisation and amount recalculation always run - OpenAPI: remove top-level qty, price, investment_activity_label, category_id from PATCH body; document entryable_attributes only * Trades: fix update/DELETE OpenAPI and avoid sell-trade corruption - Only run qty/price normalisation when client sends qty or price; preserve existing trade direction when type/nature omitted - OpenAPI: remove duplicate PATCH path param; add 422 for PATCH; document DELETE 200 body (DeleteResponse) * API: flat trade update params, align holdings errors, spec/OpenAPI fixes - Trades update: accept flat params (qty, price, type, etc.), build entryable_attributes in build_entry_params_for_update (match transactions) - Holdings: ArgumentError → 422 validation_failed; parse_date!(value, name) with safe message; extract render_validation_error, log_and_render_error - Specs: path id required (trades, holdings); trades delete 200 DeleteResponse; remove holdings 500; trades update body flat; holdings 422 invalid date - OpenAPI: PATCH trade request body flat * OpenAPI: add 422 invalid date filter to holdings index * API consistency and RSwag doc-only fixes - Trades: use render_validation_error in all 4 validation paths; safe_per_page_param case/when - Holdings: set_holding to family.holdings.find; price as Money.format in API; safe_per_page_param case/when - Swagger: Holding qty/price descriptions (Quantity of shares held, Formatted price per share) - RSwag: trades delete and valuations 201 use bare run_test! (documentation only, no expect) * Fix index-vs-show visibility inconsistencies and preserve custom activity labels - Add account status filter to set_holding to match index behavior - Add visible scope to set_trade to match index behavior - Preserve existing investment_activity_label when updating qty/price * Trades: clearer validation for non-numeric qty/price Return 'must be valid numbers' when qty or price is non-numeric (e.g. abc) instead of misleading 'must be present and positive'. --------- Add "Link to existing" option in SnapTrade Setup Accounts modal (#935) * Add account linking functionality for SnapTrade items - Introduced UI to link existing accounts when setting up SnapTrade items, preventing duplicate account creation. - Updated controller to fetch linkable accounts. - Added tests to verify proper filtering of accounts and linking behavior. * Add `snaptrade_item_id` to account linking flow for SnapTrade items - Updated controller to allow specifying `snaptrade_item_id` when linking accounts. - Adjusted form and views to include `snaptrade_item_id` as a hidden field. - Enhanced tests to validate behavior with the new parameter. Add tests for SnapTrade error handling and refine unlink behavior (#931) - Introduced new tests to cover SnapTrade decryption and connection errors in `SnaptradeItemsControllerTest`. - Updated error messages for improved user clarity. - Modified `unlink` functionality to preserve `SnaptradeAccount` records while ensuring proper detachment of associated holdings. Auto-categorize investment contributions across all transfer paths (#924) * Ensure investment contributions are auto-categorized with proper kind and category creation. * Retrigger CI Fix SSO provider warning timing (#927) Warn after providers are registered to avoid false empty state. fix: loan transfer kind assignment to use destination account (#874) * fix: loan transfer kind assignment to use destination account * fix: update system test to use depository account instead of investment account Bump version to next iteration after v0.6.8-alpha.4 release Protect demo API key from deletion (#919) * feat: Protect demo monitoring API key from deletion - Add DEMO_MONITORING_KEY constant to ApiKey model - Add `demo_monitoring_key?` method to identify the monitoring key - Add `visible` scope to exclude monitoring key from UI queries - Update controller to use `visible` scope, hiding the monitoring key - Prevent revocation of the monitoring key with explicit error handling - Update Demo::Generator to use the shared constant Users on the demo instance can still create their own API keys, but cannot see or delete the monitoring key used for uptime checks. https://claude.ai/code/session_01RQFsw39K7PB5kztboVdBdB * Linter * Protect demo monitoring API key from deletion * Use monitoring source for demo API key * Add test for demo monitoring revoke guard * Disable Rack::Attack in test and development --------- feat: Allow to create rules to mark transactions as transfers or payments (#920) * feat: Allow to create rules to define transfer or payments * fix: lint issues * Update app/models/rule/action_executor/set_as_transfer_or_payment.rb * fix: indentation issue * fix: add explicit return * fix: add guard on target_account * fix: use local variable for transfer and revert explicit return as it doesn't work * fix: Adjust transaction naming --------- fix: allow refreshes from the same source for cost basis updates (#917) * fix: allow refreshes from the same source for cost basis updates * test: update cost basis priority expectations Fix mobile login "Record not found" for unseeded instances (#916) * Auto-create mobile OAuth application when missing (#912) Self-hosted users who set up their instance without running `db:seed` (or reset their database) got "Record not found" on mobile login because `MobileDevice.shared_oauth_application` used `find_by!` which raises when the "Sure Mobile" Doorkeeper application does not exist. Switch to `find_or_create_by!` so the record is created transparently on first use, matching the attributes from the seed file. * Nice Claude Code suggestion --------- feat: add SSL_CA_FILE and SSL_VERIFY environment variables to support… (#894) * feat: add SSL_CA_FILE and SSL_VERIFY environment variables to support self-signed certificates in self-hosted environments * fix: NoMethodError by defining SSL helper methods before configure block executes * refactor: Refactor SessionsController to use shared SslConfigurable module and simplify SSL initializer redundant checks * refactor: improve SSL configuration robustness and error detection accuracy * fix:HTTParty SSL options, add file validation guards, prevent Tempfile GC, and redact URLs in error logs * fix: Fix SSL concern indentation and stub Simplefin POST correctly in tests * fix: normalize ssl_verify to always return boolean instead of nil * fix: solve failing SimpleFin test * refactor: trim unused error-handling code from SslConfigurable, replace Tempfile with fixed-path CA bundle, fix namespace pollution in initializers, and add unit tests for core SSL configuration and Langfuse CRL callback. * fix: added require ileutils in the initializer and require ostruct in the test file. * fix: solve autoload conflict that broke provider loading, validate all certs in PEM bundles, and add missing requires. Fix OIDC household invitation (issue #900) (#904) * Fix OIDC household invitation (issue #900) - Auto-add existing user when inviting by email (no invite email sent) - Accept page: choose 'Create account' or 'Sign in' (supports OIDC) - Store invitation token in session on sign-in; accept after login (password, OIDC, OIDC link, OIDC JIT, MFA) - Invitation#accept_for!(user): add user to household and mark accepted - Defensive guards: nil/blank user, token normalization, accept_for! return check * Address PR review: rename accept_for! to accept_for, i18n OIDC notice, test fixes, stub Rails.application.config * Fix flaky system test: assert only configure step, not flash message --------- fix: Preserve tags on bulk edits (take 3) (#889) * fix: handle tags separately from entryable_attributes in bulk updates Tags use a join table (taggings) rather than a direct column, which means empty tag_ids clears all tags rather than meaning "no change". This caused bulk category-only edits to accidentally clear existing tags. This fix: - Removes tag_ids from entryable_attributes in Entry.bulk_update! - Adds update_tags parameter to explicitly control tag updates - Uses params.key?(:tag_ids) in controller to detect explicit tag changes - Preserves existing tags when tag_ids is not provided in the request This is a cleaner architectural solution compared to tracking "touched" state in the frontend, as it properly acknowledges the semantic difference between column attributes and join table associations. https://claude.ai/code/session_014CsmTwjteP4qJs6YZqCKnY * fix: handle tags separately in API transaction updates Apply the same pattern to the API endpoint: tags are now handled separately from entryable_attributes to distinguish between "not provided" (preserve existing tags) and "explicitly set to empty" (clear all tags). This allows API consumers to: - Update other fields without affecting tags (omit tag_ids) - Clear all tags (send tag_ids: []) - Set specific tags (send tag_ids: [id1, id2]) https://claude.ai/code/session_014CsmTwjteP4qJs6YZqCKnY * Proposed fix * fix: improve tag handling in bulk updates for transactions * fix: allow bulk edit to clear/preserve tags by omitting hidden multi-select field * PR comments * Dumb copy/paste error * Linter --------- Fix flash message persistence in drag-and-drop CSV import (#915) * Initial plan * Disable Turbo on drag-and-drop import form to fix flash message display --------- Bump version to next iteration after v0.6.8-alpha.3 release Add Google Sign-In (SSO) support to Flutter mobile app (#860) * Add mobile SSO support to sessions controller Add /auth/mobile/:provider route and mobile_sso_start action that captures device params in session and renders an auto-submitting POST form to OmniAuth (required by omniauth-rails_csrf_protection). Modify openid_connect callback to detect mobile_sso session, issue Doorkeeper tokens via MobileDevice, and redirect to sureapp://oauth/callback with tokens. Handles MFA users and unlinked accounts with error redirects. Validates provider name against configured SSO providers and device info before proceeding. * Add SSO auth flow to Flutter service and provider Add buildSsoUrl() and handleSsoCallback() to AuthService for constructing the mobile SSO URL and parsing tokens from the deep link callback. Add startSsoLogin() and handleSsoCallback() to AuthProvider for launching browser-based SSO and processing the redirect. * Register deep link listener for SSO callback Listen for sureapp://oauth/* deep links via app_links package, handling both cold start (getInitialLink) and warm (uriLinkStream) scenarios. Routes callbacks to AuthProvider.handleSsoCallback(). * Add Google Sign-In button to Flutter login screen Add "or" divider and outlined Google Sign-In button that triggers browser-based SSO via startSsoLogin('google_oauth2'). Add app_links and url_launcher dependencies to pubspec.yaml. * Fix mobile SSO failure handling to redirect back to app When OmniAuth fails during mobile SSO flow, redirect to sureapp://oauth/callback with the error instead of the web login page. Cleans up mobile_sso session data on failure. * Address PR review feedback for mobile SSO flow - Use strong params for device info in mobile_sso_start - Guard against nil session data in handle_mobile_sso_callback - Add error handling for AppLinks initialization and stream - Handle launchUrl false return value in SSO login - Use user-friendly error messages instead of exposing exceptions - Reject empty token strings in SSO callback validation * Consolidate mobile device token logic into MobileDevice model Extract duplicated device upsert and token issuance code from AuthController and SessionsController into MobileDevice. Add CALLBACK_URL constant and URL builder helpers to eliminate repeated deep-link strings. Add mobile SSO integration tests covering the full flow, MFA rejection, unlinked accounts, and failure handling. * Fix CI: resolve Brakeman redirect warnings and rubocop empty line Move mobile SSO redirect into a private controller method with an inline string literal so Brakeman can statically verify the target. Remove unused URL builder helpers from MobileDevice. Fix extra empty line at end of AuthController class body. * Use authorization code exchange for mobile SSO and add signup error handling Replace passing plaintext tokens in mobile SSO redirect URLs with a one-time authorization code pattern. Tokens are now stored server-side in Rails.cache (5min TTL) and exchanged via a secure POST to /api/v1/auth/sso_exchange. Also wraps device/token creation in the signup action with error handling and sanitizes device error messages. * Add error handling for login device registration and blank SSO code guard * Address PR #860 review: fix SSO race condition, add OpenAPI spec, and cleanup - Fix race condition in sso_exchange by checking Rails.cache.delete return value to ensure only one request can consume an authorization code - Use strong parameters (params.require) for sso_exchange code param - Move inline HTML from mobile_sso_start to a proper view template - Clear stale session[:mobile_sso] flag on web login paths to prevent abandoned mobile flows from hijacking subsequent web SSO logins - Add OpenAPI/rswag spec for all auth API endpoints * Fix mobile SSO test to match authorization code exchange pattern The test was asserting tokens directly in the callback URL, but the code uses an authorization code exchange pattern. Updated to exchange the code via the sso_exchange API endpoint. Also swaps in a MemoryStore for this test since the test environment uses null_store which discards writes. * Refactor mobile OAuth to use single shared application Replace per-device Doorkeeper::Application creation with a shared "Sure Mobile" OAuth app. Device tracking uses mobile_device_id on access tokens instead of oauth_application_id on mobile_devices. --------- Normalize whitespace in text rule matching (#890) Normalize whitespace in text-based rule filters so transaction names with irregular spacing still match. Refs #886 Add mailer subject tests and refine i18n keys (#910) * Add mailer subject tests and refine i18n keys * Linter * Fix test * More fixes * More fixes --------- feat: Customizable Budget Month Start Day (#810) * Add customizable budget month start day (#253) Allow users to set a custom month-to-date start date (1st-28th) for budgeting and MTD calculations. Useful for users who want budget periods aligned with their pay schedule (e.g., 25th to 24th). Changes: - Add month_start_day column to families table (default: 1) - Add database check constraint for valid range (1-28) - Add Family#uses_custom_month_start?, custom_month_start_for, custom_month_end_for, current_custom_month_period helper methods - Add Period.current_month_for(family), last_month_for(family) methods - Update Budget model for custom month boundaries in find_or_bootstrap, param_to_date, budget_date_valid?, current?, and name methods - Add month_start_day setting to Settings > Preferences UI - Add warning message when custom month start day is configured - Add comprehensive tests with travel_to for date robustness Fixes #253 * Add /api/v1/user endpoint for Flutter mobile app and PWA Expose user preferences including month_start_day via API endpoint following existing pattern for default_period. This allows Flutter mobile app and PWA to read/update user preferences through a consistent API contract. Endpoints: - GET /api/v1/user - Read user preferences including family settings - PATCH /api/v1/user - Update user preferences Response includes: id, email, first_name, last_name, default_period, locale, and family settings (currency, timezone, date_format, country, month_start_day). * Update Periodable to use family-aware MTD periods When users select 'current_month' or 'last_month' period filters on dashboard/reports, now respects the family's custom month_start_day setting instead of using static calendar month boundaries. This ensures MTD filter on dashboard is consistent with how budgets calculate their periods when custom month start day is configured. * Fix param_to_date to correctly map budget params to custom periods When a family uses a custom start day, the previous implementation called custom_month_start_for on the 1st of the month, which incorrectly shifted dates before the start day to the previous month. Now we directly construct the date using family.month_start_day, so 'jan-2026' with month_start_day=25 correctly returns Jan 25, 2026 instead of Dec 25, 2025. * Fix param_to_date and use Current pattern in API controller - Fix param_to_date to directly construct date with family.month_start_day instead of using custom_month_start_for which incorrectly shifted dates - Replace current_user with Current.user/Current.family in API controller to follow project convention used in other API v1 controllers * Add i18n for budget name method Use I18n.t for localizable budget period names to follow project conventions for user-facing strings. * Remove unused budget_end variable in budget_date_valid? * Use Date.current for timezone consistency in Budget#current? * Address PR review feedback - Remove API users endpoint (mobile won't use yet) - Remove user route from config/routes.rb - Remove ai_summary/document_type schema bleed from pdf-import-ai branch * Pass family to param_to_date for custom month logic * Run migration to add month_start_day column to schema * Schema regressions --------- Add encryption support to provider account models (#815) * Enable encryption for raw payloads in account models. * Add backfill support for Snaptrade, Coinbase, Coinstats, and Mercury accounts. API v1: add amount_cents + signed_amount_cents to transactions (#899) * feat(api): add amount_cents + signed_amount_cents to transactions * fix: use currency.minor_unit_conversion for amount_cents - Replace hardcoded *100 with currency.minor_unit_conversion - Handles JPY (0 decimals), KWD/BHD (3 decimals), etc. correctly - Add assert_amount_cents_fields helper to validate sign/scale invariants Update Romanian localization for profile subtitle placeholder (#885) Use `dependent: :purge_later` for ActiveRecord attachments (#882) * Use dependent: :purge_later for user profile_image cleanup This is a simpler alternative to PR #787's callback-based approach. Instead of adding a custom callback and method, we use Rails' built-in `dependent: :purge_later` option which is already used by FamilyExport and other models in the codebase. This single-line change ensures orphaned ActiveStorage attac… Signed-off-by: Josh Pigford <josh@joshpigford.com>
.cursor/rules/*.mdc into single .junie/guidelines.md file (#343)
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 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
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.