Commit Graph

577 Commits

Author SHA1 Message Date
github-actions[bot]
16aca7812a Bump version to next iteration after v0.6.8-alpha.10 release 2026-02-16 19:27:21 +00:00
Juan José Mata
06fedb34f3 Add new columns and sorting to admin users list (#1004)
* Add trial end date to admin users list

* Add new columns

* Regression
2026-02-16 20:10:14 +01:00
github-actions[bot]
9ce7669e1c Bump version to next iteration after v0.6.8-alpha.9 release 2026-02-14 00:19:56 +00:00
Juan José Mata
8264943f23 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

Co-authored-by: Claude <noreply@anthropic.com>

* Tailwind fixes

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-14 01:10:25 +01:00
Juan José Mata
bf0be85859 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

Co-authored-by: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-14 00:39:03 +01:00
Pluto
e99e38a91c 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
2026-02-13 19:53:24 +01:00
Juan José Mata
868a0ae4d8 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

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-13 19:30:29 +01:00
github-actions[bot]
25b02976f9 Bump version to next iteration after v0.6.8-alpha.8 release 2026-02-11 20:01:54 +00:00
Juan José Mata
0eedd533bb Generalize from PDF import to just files 2026-02-11 17:56:49 +00:00
github-actions[bot]
6bef5be089 Bump version to next iteration after v0.6.8-alpha.7 release 2026-02-10 23:12:22 +00:00
Juan José Mata
4b0986220f Remove Flipper and replace with ENV-driven FeatureFlags (#957)
* Presence of valid DEFAULT_UI_LAYOUT is sufficient

* Linter
2026-02-10 23:30:45 +01:00
github-actions[bot]
ea06058854 Bump version to next iteration after v0.6.8-alpha.6 release 2026-02-09 15:43:29 +00:00
github-actions[bot]
b40dd30261 Bump version to next iteration after v0.6.8-alpha.5 release 2026-02-09 15:05:48 +00:00
Juan José Mata
f1abbda9dd Add Intro UI feature flag 2026-02-09 12:47:23 +00:00
Juan José Mata
705b5a8b26 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`

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-09 11:09:25 +01:00
David Gil
ba442d5f26 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.

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-08 18:19:37 +01:00
MkDev11
d88c2151cb 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).

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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)

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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

Co-authored-by: Cursor <cursoragent@cursor.com>

* OpenAPI: add 422 invalid date filter to holdings index

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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)

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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

Co-authored-by: Cursor <cursoragent@cursor.com>

* 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'.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 11:22:32 +01:00
LPW
24981ffd52 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.
2026-02-08 10:30:46 +01:00
LPW
01c2209492 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.
2026-02-07 23:15:18 +01:00
Juan José Mata
fc3504abe0 Fix SSO provider warning timing (#927)
Warn after providers are registered to avoid false empty state.
2026-02-07 15:57:01 +01:00
github-actions[bot]
c6d3d85922 Bump version to next iteration after v0.6.8-alpha.4 release 2026-02-06 20:36:10 +00:00
Juan José Mata
61ce5c8514 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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-06 21:25:52 +01:00
BitToby
ba6e286b41 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.
2026-02-06 18:04:03 +01:00
MkDev11
87117445fe 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

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 16:14:42 +01:00
github-actions[bot]
3195e24650 Bump version to next iteration after v0.6.8-alpha.3 release 2026-02-05 23:55:35 +00:00
Dream
ca3abd5d8b 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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* 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.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* 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.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 00:45:11 +01:00
sentry[bot]
d09765a14c Add mailer subject tests and refine i18n keys (#910)
* Add mailer subject tests and refine i18n keys

* Linter

* Fix test

* More fixes

* More fixes

---------

Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-05 19:47:01 +01:00
MkDev11
68efe71cdb 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

---------

Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-04 23:58:09 +01:00
sentry[bot]
fb9468d80b Update Romanian localization for profile subtitle placeholder (#885)
Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
2026-02-03 17:08:53 +01:00
github-actions[bot]
34dcf5110a Bump version to next iteration after v0.6.8-alpha.2 release 2026-02-03 14:22:05 +00:00
tlink
9a9ebb147b Add localization for onboarding goals across multiple languages (#873)
* Add localization for onboarding goals across multiple languages

* Add password requirements localization for multiple languages

* Refactor localization keys for authentication messages

* Add `oidc` localization key for multiple languages

* Add OIDC account localization for multiple languages

* Add localization for trial and profile setup across multiple languages

* Refactor OIDC button label fallback to prioritize label presence over localization key

* Refactor onboarding tests to use I18n for text assertions and button labels

* Linter

* Last test fix?!?

* We keep both `oidc` and `openid_connect` due to contatenation issues

---------

Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-03 14:49:21 +01:00
MkDev11
0afdb1d0fd Feature/pdf import transaction rows (#846)
* Add import row generation from PDF extracted data

- Add generate_rows_from_extracted_data method to PdfImport
- Add import! method to create transactions from PDF rows
- Update ProcessPdfJob to generate rows after extraction
- Update configured?, cleaned?, publishable? for PDF workflow
- Add column_keys, required_column_keys, mapping_steps
- Set bank statements to pending status for user review
- Add tests for new functionality

Closes #844

* Add tests for BankStatementExtractor

- Test transaction extraction from PDF content
- Test deduplication across chunk boundaries
- Test amount normalization for various formats
- Test graceful handling of malformed JSON responses
- Test error handling for empty/nil PDF content

* Fix supports_pdf_processing? to validate effective model

The validation was always checking @default_model, but process_pdf
allows overriding the model via parameter. This could cause a
vision-capable override model to be rejected, or a non-vision-capable
override to pass validation only to fail during processing.

Changes:
- supports_pdf_processing? now accepts optional model parameter
- process_pdf passes effective model to validation
- Raise Provider::Openai::Error inside with_provider_response for
  consistent error handling

Addresses review feedback from PR#808

* Fix insert_all! bug: explicitly set import_id

Rails insert_all! on associations does NOT auto-set the foreign key.
Added import_id explicitly and use Import::Row.insert_all! directly.
Also reload rows before counting to ensure accurate count.

* Fix pending status showing as processing for bank statements with rows

When bank statement PDF imports have extracted rows, show a 'Ready for Review'
screen with a link to the confirm path instead of the 'Processing' spinner.

This addresses the PR feedback that users couldn't reach the review flow even
though rows were created.

* Gate publishable? on account.present? to prevent import failure

PDF imports are created without an account, and import! raises if account
is missing. This prevents users from hitting publish and having the job fail.

* Wrap generate_rows_from_extracted_data in transaction for atomicity

- Clear rows and reset count even when no transactions extracted
- Use transaction block to prevent partial updates on failure
- Use mapped_rows.size instead of reload for count

* Localize transactions count string with i18n helper

* Add AccountMapping step for PDF imports when account is nil

PDF imports need account selection before publishing. This adds
Import::AccountMapping to mapping_steps when account is nil,
matching the behavior of TransactionImport and TradeImport.

Addresses PR#846 feedback about account selection for PDF imports.

* Only include CategoryMapping when rows have non-empty categories

PDF extraction doesn't extract categories from bank statements,
so the CategoryMapping step would show empty. Now we only include
CategoryMapping if rows actually have non-empty category values.

This prevents showing an empty mapping step for PDF imports.

* Fix PDF import UI flow and account selection

- Add direct account selection in PDF import UI instead of AccountMapping
- AccountMapping designed for CSV imports with multiple account values
- PDF imports need single account for all transactions
- Add update action and route for imports controller
- Fix controller to handle pdf_import param format from form_with
- Show Publish button when import is publishable (account set)
- Fix stepper nav: Upload/Configure/Clean non-clickable for PDF imports
- Redirect PDF imports from configuration step (auto-configured)
- Improve AI prompt to recognize M-PESA/mobile money as bank statements
- Fix migration ordering for import_rows table columns

* Add guard for invalid account_id in imports#update

Prevents silently clearing account when invalid ID is passed.
Returns error message instead of confusing 'Account saved' notice.

* Localize step names in import nav and add account guard

- Use t() helper for all step names (Upload, Configure, Clean, Map, Confirm)
- Add guard for invalid account_id in imports#update
- Prevents silently clearing account when invalid ID is passed

* Make category column migrations idempotent

Check if columns exist before adding to prevent duplicate column
errors when migrations are re-run with new timestamps.

* Add match_path for PDF import step highlighting

Fixes step detection when path is nil by using separate match_path
for current step highlighting while keeping links disabled.

* Rename category migrations and update to Rails 7.2

- Rename class to EnsureCategoryFieldsOnImportRows to avoid conflicts
- Rename class to EnsureCategoryIconOnImportRows
- Update migration version from 7.1 to 7.2 per guidelines
- Rename files to match class names
- Add match_path for PDF import step highlighting

* Use primary (black) style for Create Account and Save buttons

* Remove match_path from auto-completed PDF steps

Only step 4 (Confirm) needs match_path for active-step detection.
Steps 1-3 are purely informational and always complete.

* Add fallback for document type translation

Handles nil or unexpected document_type values gracefully.
Also removes match_path from auto-completed PDF steps.

* Use index-based step number for mobile indicator

Fixes 'Step 5 of 4' issue when Map step is dynamically removed.

* Fix hostings_controller_test: use blank? instead of nil

Setting returns empty string not nil for unset values.

* Localize step progress label and use design token

* Fix button styling: use design system Tailwind classes

btn--primary and btn--secondary CSS classes don't exist.
Use actual design system classes from DS::Buttonish.

* Fix CRLF line endings in tags_controller_test.rb

---------

Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
2026-02-02 16:27:02 +01:00
Juan José Mata
146d6203fd Still alpha.2 out there 2026-02-02 16:15:14 +01:00
github-actions[bot]
a0c26990e5 Bump version to next iteration after v0.6.7-rc.2 release 2026-01-31 15:19:24 +00:00
MkDev11
6f8858b1a6 feat/Add AI-Powered Bank Statement Import (step 1, PDF import & analysis) (#808)
* feat: Add PDF import with AI-powered document analysis

This enhances the import functionality to support PDF files with AI-powered
document analysis. When a PDF is uploaded, it is processed by AI to:
- Identify the document type (bank statement, credit card statement, etc.)
- Generate a summary of the document contents
- Extract key metadata (institution, dates, balances, transaction count)

After processing, an email is sent to the user asking for next steps.

Key changes:
- Add PdfImport model for handling PDF document imports
- Add Provider::Openai::PdfProcessor for AI document analysis
- Add ProcessPdfJob for async PDF processing
- Add PdfImportMailer for user notification emails
- Update imports controller to detect and handle PDF uploads
- Add PDF import option to the new import page
- Add i18n translations for all new strings
- Add comprehensive tests for the new functionality

* Add bank statement import with AI extraction

- Create ImportBankStatement assistant function for MCP
- Add BankStatementExtractor with chunked processing for small context windows
- Register function in assistant configurable
- Make PdfImport#pdf_file_content public for extractor access
- Increase OpenAI request timeout to 600s for slow local models
- Increase DB connection pool to 20 for concurrent operations

Tested with M-Pesa bank statement via remote Ollama (qwen3:8b):
- Successfully extracted 18 transactions
- Generated CSV and created TransactionImport
- Works with 3000 char chunks for small context windows

* Add pdf-reader gem dependency

The BankStatementExtractor uses PDF::Reader to parse bank statement
PDFs, but the gem was not properly declared in the Gemfile. This would
cause NameError in production when processing bank statements.

Added pdf-reader ~> 2.12 to Gemfile dependencies.

* Fix transaction deduplication to preserve legitimate duplicates

The previous deduplication logic removed ALL duplicate transactions based
on [date, amount, name], which would drop legitimate same-day duplicates
like multiple ATM withdrawals or card authorizations.

Changed to only deduplicate transactions that appear in consecutive chunks
(chunking artifacts) while preserving all legitimate duplicates within the
same chunk or non-adjacent chunks.

* Refactor bank statement extraction to use public provider method

Address code review feedback:
- Add public extract_bank_statement method to Provider::Openai
- Remove direct access to private client via send(:client)
- Update ImportBankStatement to use new public method
- Add require 'set' to BankStatementExtractor
- Remove PII-sensitive content from error logs
- Add defensive check for nil response.error
- Handle oversized PDF pages in chunking logic
- Remove unused process_native and process_generic methods
- Update email copy to reflect feature availability
- Add guard for nil document_type in email template
- Document pdf-reader gem rationale in Gemfile

Tested with both OpenAI (gpt-4o) and Ollama (qwen3:8b):
- OpenAI: 49 transactions extracted in 30s
- Ollama: 40 transactions extracted in 368s
- All encapsulation and error handling working correctly

* Update schema.rb with ai_summary and document_type columns

* Address PR #808 review comments

- Rename :csv_file to :import_file across controllers/views/tests
- Add PDF test fixture (sample_bank_statement.pdf)
- Add supports_pdf_processing? method for graceful degradation
- Revert unrelated database.yml pool change (600->3)
- Remove month_start_day schema bleed from other PR
- Fix PdfProcessor: use .strip instead of .strip_heredoc
- Add server-side PDF magic byte validation
- Conditionally show PDF import option when AI provider available
- Fix ProcessPdfJob: sanitize errors, handle update failure
- Move pdf_file attachment from Import to PdfImport
- Document deduplication logic limitations
- Fix ImportBankStatement: catch specific exceptions only
- Remove unnecessary require 'set'
- Remove dead json_schema method from PdfProcessor
- Reduce default OpenAI timeout from 600s to 60s
- Fix nil guard in text mailer template
- Add require 'csv' to ImportBankStatement
- Remove Gemfile pdf-reader comment

* Fix RuboCop indentation in ProcessPdfJob

* Refactor PDF import check to use model predicate method

Replace is_a?(PdfImport) type check with requires_csv_workflow? predicate
that leverages STI inheritance for cleaner controller logic.

* Fix missing 'unknown' locale key and schema version mismatch

- Add 'unknown: Unknown Document' to document_types locale
- Fix schema version to match latest migration (2026_01_24_180211)

* Document OPENAI_REQUEST_TIMEOUT env variable

Added to .env.local.example and docs/hosting/ai.md

* Rename ALLOWED_MIME_TYPES to ALLOWED_CSV_MIME_TYPES for clarity

* Add comment explaining requires_csv_workflow? predicate

* Remove redundant required_column_keys from PdfImport

Base class already returns [] by default

* Add ENV toggle to disable PDF processing for non-vision endpoints

OPENAI_SUPPORTS_PDF_PROCESSING=false can be used for OpenAI-compatible
endpoints (e.g., Ollama) that don't support vision/PDF processing.

* Wire up transaction extraction for PDF bank statements

- Add extracted_data JSONB column to imports
- Add extract_transactions method to PdfImport
- Call extraction in ProcessPdfJob for bank statements
- Store transactions in extracted_data for later review

* Fix ProcessPdfJob retry logic, sanitize and localize errors

- Allow retries after partial success (classification ok, extraction failed)
- Log sanitized error message instead of raw message to avoid data leakage
- Use i18n for user-facing error messages

* Add vision-capable model validation for PDF processing

* Fix drag-and-drop test to use correct field name csv_file

* Schema bleedover from another branch

* Fix drag-drop import form field name to match controller

* Add vision capability guard to process_pdf method

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-01-30 20:44:25 +01:00
Pere Montpeó
9f5fdd4d13 feat: add valuations API endpoints for managing account reconciliations (#745)
* feat: add valuations API endpoints for managing account reconciliations

* refactor: formatting

* fix: make account extraction clearer

* feat: validation and error handling improvements

* feat: transaction

* feat: error handling

* Add API documentation LLM context

* Make it easier for people

* feat: transaction in creation

* feat: add OpenAPI spec for Valuations API

* fix: update notes validation to check for key presence

* Prevent double render

* All other docs use `apiKeyAuth`

* More `apiKeyAuth`

* Remove testing assertions from API doc specs

* fix: correct valuation entry references

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-30 18:54:15 +01:00
Dream
04931e27eb Fix Errno::ENOENT when git is not installed (#838)
Rescue Errno::ENOENT in commit_sha so environments without git
(e.g. Docker containers) don't crash on boot.
2026-01-30 12:22:51 +01:00
StalkerSea
a86329d632 PWA: Update manifest, meta tags, and fix UI layout issues (#801)
* pwa(cleanup): enforce LF, head meta + icons, manifest orientation, remove static webmanifest

* pwa(cleanup): add gitattributes, head meta/icons, manifest orientation; remove static manifest; small nav & dashboard fixes

* pwa(cleanup): improve transaction drawer header layout with inline close button

* fix: address PR review feedback

- Add dom_id to transaction header for Turbo Stream updates (Codex)
- Add pending badge next to date when transaction is pending (CodeRabbit)
- Make close button keyboard-focusable by removing tabindex=-1 (CodeRabbit)
- Fix settings nav horizontal scroll with flex-nowrap space-x-1 (CodeRabbit)

* fix: localize 'Linked with Plaid' tooltip string (CodeRabbit)

* Update .gitattributes

Better comment smh

* fix: align transaction/transfer dialog icons and update transfer drawer pattern

- Fix icon alignment in transaction header (items-center instead of items-start)
- Make transfer/linked icons consistent size and color
- Update transfers/show.html.erb to use frame: drawer with hide_close_icon pattern
- Match transfer dialog header layout with transaction details

* fix: enhance header layout

This in the transaction and transfer views, with consistent icon placement

* fix: remove fixed height from HTML document class

basically a regression issue pretty sure

* fix: update dialog rendering to use 'frame' and hide close icon in headers

* fix: update transaction type tabs layout for improved responsiveness

* fix: conditionally render transaction type tabs based on account type
2026-01-29 15:16:49 +01:00
github-actions[bot]
4adc4199ee Bump version to next iteration after v0.6.8-alpha.1 release 2026-01-28 18:19:20 +00:00
Juan José Mata
ef4f5f7b8b feat: CORS support (#813)
* feat: Add CORS support for Flutter mobile client

Add rack-cors gem and configure CORS for API and OAuth endpoints
to enable cross-origin requests from mobile clients and other
external applications.

https://claude.ai/code/session_01RJ6MKLkjBv7x5AQLEUn8AF

* feat: Add /sessions/* to CORS for webview authentication

Enable CORS for session endpoints to support webview-based
authentication flows in the Flutter mobile client.

https://claude.ai/code/session_01RJ6MKLkjBv7x5AQLEUn8AF

* test: Add integration tests for CORS configuration

Test that CORS middleware is configured and returns proper headers
for API, OAuth, and session endpoints including preflight requests.

https://claude.ai/code/session_01RJ6MKLkjBv7x5AQLEUn8AF

* Gemfile.lock

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-28 17:25:02 +01:00
MkDev11
eeff4edbea Add warning for TwelveData plan-restricted tickers (#803)
* Add warning for TwelveData plan-restricted tickers

Fixes #800

- Add Security::PlanRestrictionTracker concern using Rails cache
- Detect plan upgrade errors during Security::Price::Importer sync
- Display amber warning on /settings/hosting with affected tickers
- Include unit tests for the new functionality

* Scope plan restriction cache by provider

Addresses review feedback:
- Cache key now includes provider name to support multiple data providers
- Methods now require provider parameter for proper scoping
- Added tests for provider-scoped restrictions
- Added documentation explaining instance-level API key architecture

* Fix RuboCop array bracket spacing

* Fix empty array bracket spacing

* Move plan upgrade detection to Provider::TwelveData

* Fix provider scoping tests to use direct cache writes

---------

Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
2026-01-27 15:45:50 +01:00
Alessio Cappa
aef582f553 feat: Move upcoming recurring transactions in a dedicated tab (#771)
* feat: Move upcoming transactions in a dedicated tab

* Adjust formatting

* feat: adjust visibility on mobile

* feat: change translation label

* feat: show only upcoming transactions expected in the next 10 days

* feat: show upcoming transactions tab only when option enabled

* feat: render empty partial when there are no recurring transactions

* feat: align icon sizing and spacing between transactions and upcoming sections

* feat: add missing localitazion labels

* fix: move filter on upcoming transactions in controller

* fix: add missing localitazion labels
2026-01-27 12:32:35 +01:00
Juan José Mata
946d0cb3ef Merge branch 'main' into feature/llm-cache-reset
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-27 08:50:01 +01:00
Dream
51579d3731 FR: Add transaction type as rule condition option (#790)
* Add transaction type condition filter for rules

Add ability to filter rules by transaction type (income, expense, transfer).
This allows users to create rules that differentiate between transactions
with the same name but different types.

- Add Rule::ConditionFilter::TransactionType with select dropdown
- Register in TransactionResource condition_filters
- Add tests for income, expense, and transfer filtering

Closes #373

* Address PR review feedback for transaction type filter

- Fix income filter to exclude transfers and investment_contribution
- Fix expense filter to include investment_contribution regardless of sign
- Add i18n for option and operator labels
- Add tests for edge cases (transfer inflows, investment contributions)

Logic now matches Transaction::Search#apply_type_filter for consistency.
2026-01-26 16:53:05 +01:00
eureka928
b82757f58e Use i18n for AI cache reset strings
Extract hardcoded strings to locale file for proper internationalization.
2026-01-26 09:49:05 +01:00
eureka928
b511b3add9 Add clear_ai_cache endpoint to rules controller
Add POST /rules/clear_ai_cache route and controller action to trigger AI cache clearing for the current family.
2026-01-26 09:46:26 +01:00
Juan José Mata
9119a635d1 The main branch is now for v0.6.8-alpha.*
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-25 21:52:58 +01:00
github-actions[bot]
812dc9d954 Bump version to next iteration after v0.6.7-rc.1 release 2026-01-25 19:44:11 +00:00
Juan José Mata
4c69ba9420 Update version from alpha to rc
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-25 20:34:43 +01:00
Piet
51d1a8f22b fix: Register sync_all_accounts cron job on Sidekiq startup (#764)
* fix: Register sync_all_accounts cron job on Sidekiq startup

AutoSyncScheduler.sync! was only called when changing settings in the UI,
so the nightly sync job was never registered. Now it's initialized when
Sidekiq starts, ensuring accounts sync nightly as configured.

* Utilize existing configure_server block

---------

Co-authored-by: Pieter <ptr@arcsec.org>
2026-01-24 22:09:52 +01:00