Commit Graph

828 Commits

Author SHA1 Message Date
soky srm
ae5b23fe67 Initial split transaction support (#1230)
* Initial split transaction support

* Add support to unsplit and edit split

* Update show.html.erb

* FIX address reviews

* Improve UX

* Update show.html.erb

* Reviews

* Update edit.html.erb

* Add parent category to dialog

* Update en.yml

* Add UI indication to totals

* FIX ui update

* Add category select like rest of app

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-03-20 21:19:30 +01:00
Juan José Mata
53f478a77b Add scheduled DemoFamilyRefreshJob to rebuild demo data daily (#1217)
* Add scheduled demo family refresh job

Rebuild demo data daily at 5am UTC by anonymizing and enqueueing deletion of the existing demo family while immediately generating new sample data. Add super-admin email notifications with 24-hour session and signup metrics, plus tests for the new job and mailer.

* Delete demo monitoring key before family refresh

Ensure DemoFamilyRefreshJob removes ApiKey::DEMO_MONITORING_KEY from the old demo family before enqueueing async family destruction and generating replacement sample data. Adds a regression assertion that the key is gone before generator execution.
2026-03-17 19:41:26 +01:00
Juan José Mata
a377ed7552 Remove unused DeveloperMessage model (#1207)
DeveloperMessage was a debug-only STI subclass of Message that was never
created by any production code. Remove the model, view partial, test,
and fixtures, and simplify Chat#conversation_messages accordingly.

https://claude.ai/code/session_012pm5HKGKFs1tpAsvXMr4Tp

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-16 20:22:11 +01:00
Serge L
5aa808e668 Feat: Add default user account and consolidate account actions in menu (#1130)
* feat: Add default account for manual transaction entries (#1061)

Allow users to designate a default account that auto-selects
in the transaction creation form. Also consolidates account list
actions (edit, link/unlink, enable/disable) into a meatball menu.

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

* - handle context menu width on mobile
- restrict default account to depository types only
- added FR, ES and DE i18n files

* - Add credit card accounts can also be used as default
- Moved logic into controller

* Scope context menu max-width to accounts menu only
- decouples the width constraint from the shared DS::Menu component by introducing an optional max_width param

* fix ci test and address issues raised by coderabbit and codex

* Address CodeRabbit review feedback

- Use .present? for institution_name guards to avoid empty UI artifacts
- Align "Set default" menu visibility with actual preselection eligibility
  (active + unlinked + supports_default?) to prevent drift between UI and model
- Keep disabled star visible when account is already default but now ineligible

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add eligible_for_transaction_default? predicate to Account model

Consolidates active + unlinked + supports_default? checks into a single
shared predicate used by the controller, view, and user model guard,
preventing a direct PATCH from bypassing UI eligibility rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Added "Unset default" option
Added negative test for default account
Removed duplicated logic for account.eligible_for_transaction_default

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 21:26:26 +01:00
Renzo
581d3684b2 feat: Add duplicate button when a transaction is selected (#1123)
* feat: Add duplicate button when a transaction is selected

* feat: add merchant field

* feat: add duplicate transaction btn 2
2026-03-15 17:05:01 +01:00
Juan José Mata
cade5b22f7 Document admin-only reset auth in OpenAPI docs (#1198)
* Document admin-only reset auth in OpenAPI docs

The DELETE /api/v1/users/reset endpoint now requires admin role
(ensure_admin). Update the rswag spec to:
- Set default user role to admin so the 200 test passes
- Add a 403 response case for non-admin users with read_write scope
- Clarify the description notes admin requirement
- Add SuccessMessage schema and users paths to openapi.yaml

https://claude.ai/code/session_01Tj8ToLRmVg5HLmHwq9KKDY

* Consolidate duplicate 403 responses for reset endpoint

OpenAPI keys responses by status code, so two 403 blocks caused the
first (insufficient scope) to be silently overwritten by the second
(non-admin). Merge into a single 403 whose description covers both
causes: requires read_write scope and admin role. The test exercises
the read-only key path which hits 403 via scope check.

https://claude.ai/code/session_01Tj8ToLRmVg5HLmHwq9KKDY

* Em-dash out of messages.

* Fix tests

* Fix tests

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-15 00:23:38 +01:00
Ellion Blessan
98ae6782dc feat(transaction): add support for file attachments using Active Storage (#713)
* feat(transaction): add support for file attachments using Active Storage

* feat(attachments): implement transaction attachments with upload, show, and delete functionality

* feat(attachments): enhance attachment upload functionality to support multiple files and improved error handling

* feat(attachments): add attachment upload form and display functionality in transaction views

* feat(attachments): implement attachment validation for count, size, and content type; enhance upload form with validation hints

* fix(attachments): use correct UI components

* feat(attachments): Implement Turbo Stream responses for creating and deleting transaction attachments.

* fix(attachments): include auth in activestorage controller

* test(attachments): add test coverage for turbostream and auth

* feat(attachments): extract strings to i18n

* fix(attachments): ensure only newly added attachments are purged when transaction validation fails.

* fix(attachments): validate attachment params

* refactor(attachments): use stimulus declarative actions

* fix(attachments): add auth for other representations

* refactor(attachments): use Browse component for attachment uploads

* fix(attachments): reject empty values on attachment upload

* fix(attachments): hide the upload form if reached max uploads

* fix(attachments): correctly purge only newly added attachments on upload failure

* fix(attachments): ensure attachment count limit is respected within a transaction lock

* fix(attachments): update attachment parameter handling to avoid `ParameterMissing` errors.

* fix(components): adjust icon_only logic for buttonish

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-03-14 23:56:27 +01:00
AdamWHY2K
3a869c760e feat: add pending transaction manual merging tool (#1088)
* refactor: use a map of providers that support pending transactions

* feat: add pending transaction manual merging tool

* fix(coderabbit): validate posted_entry_id against eligible posted candidates server-side

* fix(coderabbit): validate offset for negative numbers

* fix(coderabbit): check if pending_duplicate_candidates has_more in one transaction

* refactor: use list of radio buttons for better pagination

* chore: show current transaction range in paginated view

* chore: whitespace

chore: whitespace
2026-03-14 20:32:13 +01:00
Serge L
57199d6eb9 Feat: Add QIF (Quicken Interchange Format) import functionality (#1074)
* Feat: Add QIF (Quicken Interchange Format) import functionality
- Add the ability to import QIF files for users coming from Quicken
- Includes categories and tags
- Comprehensive tests for QifImport, including parsing, row generation, and import functionality.
- Ensure handling of hierarchical categories (ex "Home:Home Improvement" is imported as Parent:Child)

* Fix QIF import issues raised in code review

- Fix two-digit year windowing in QIF date parser (e.g. '99 → 1999, not 2099)
- Fix ArgumentError from invalid `undef: :raise` encoding option
- Nil-safe `leaf_category_name` with blank guard and `.to_s` coercion
- Memoize `qif_account_type` to avoid re-parsing the full QIF file
- Add strong parameters (`selection_params`) to QifCategorySelectionsController
- Wrap all mutations in DB transactions in uploads and category-selections controllers
- Skip unchanged tag rows (only write rows where tags actually differ)
- Replace hardcoded strings with i18n keys across QIF views and nav
- Fix potentially colliding checkbox/label IDs in category selection view
- Improve keyboard accessibility: use semantic `<label>` for file picker area

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix QIF import test count and Brakeman mass assignment warning

- Update ImportsControllerTest to expect 4 disabled import options (was 3),
  accounting for the new QIF import type added in this branch
- Remove :account_id from upload_params permit list; it was never accessed
  through strong params (always via params.dig with Current.family scope),
  so this resolves the Brakeman high-confidence mass assignment warning

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix: QIF import security, safety, and i18n issues raised in code review
- Added french, spanish and german translations for newly added i18n keys
- Replace params.dig(:import, :account_id) with a proper strong-params
  accessor (import_account_id) in UploadsController to satisfy Rails
  parameter filtering requirements
- Guard ImportsController#show against QIF imports reaching the publish
  screen before a file has been uploaded, preventing an unrescued error
  on publish
- Gate the QIF "Clean" nav step link on import.uploaded? to prevent
  routing to CleansController with an unconfigured import (which would
  raise "Unknown import type: QifImport" via ImportsHelper)
- Replace hard-coded "txn" pluralize calls in the category/tag selection
  view with t(".txn_count") and add pluralization keys to the locale file
- Localize all hard-coded strings in the QIF upload section of
  uploads/show.html.erb and add corresponding en.yml keys
- Convert the CSV upload drop zone from a clickable <div> (JS-only) to
  a semantic <label> element, making it keyboard-accessible without
  JavaScript

* Fix: missing translations keys

* Add icon mapping and random color assignment to new categories

* fix a lint issue

* Add a warning about splits and some plumbing for future support.
Updated locales.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:22:39 +01:00
Juan José Mata
02af8463f6 Administer invitations in /admin/users (#1185)
* Add invited users with delete button to admin users page

Shows pending invitations per family below active users in /admin/users/.
Each invitation row has a red Delete button aligned with the role column.
Alt/option-clicking any Delete button changes all invitation button labels
to "Delete All" and destroys all pending invitations for that family.

- Add admin routes: DELETE /admin/invitations/:id and DELETE /admin/families/:id/invitations
- Add Admin::InvitationsController with destroy and destroy_all actions
- Load pending invitations grouped by family in users controller index
- Render invitation rows in a dashed-border tbody below active user rows
- Add admin-invitation-delete Stimulus controller for alt-click behavior
- Add i18n strings for invitation UI and flash messages

https://claude.ai/code/session_01F8WaH5TmtdUWwhHnVoQ6Gm

* Fix destroy_all using params[:id] from member route

The member route /admin/families/:id/invitations sets params[:id],
not params[:family_id], so Family.find was always receiving nil.

https://claude.ai/code/session_01F8WaH5TmtdUWwhHnVoQ6Gm

* Fix translation key in destroy_all to match locale

t(".success_all") looked up a nonexistent key; the locale defines
admin.invitations.destroy_all.success, so t(".success") is correct.

https://claude.ai/code/session_01F8WaH5TmtdUWwhHnVoQ6Gm

* Scope bulk delete to pending invitations and allow re-inviting emails

- destroy_all now uses family.invitations.pending.destroy_all so accepted
  and expired invitation history is preserved
- Replace blanket email uniqueness validation with a custom check scoped
  to pending invitations only, so the same email can be invited again
  after an invitation is deleted or expires

https://claude.ai/code/session_01F8WaH5TmtdUWwhHnVoQ6Gm

* Drop unconditional unique DB index on invitations(email, family_id)

The model-level uniqueness check was already scoped to pending
invitations, but the blanket unique index on (email, family_id)
still caused ActiveRecord::RecordNotUnique when re-inviting an
email that had any historical invitation record in the same family
(e.g. after an accepted invite or after an account deletion).

Replace it with no DB-level unique constraint — the
no_duplicate_pending_invitation_in_family model validation is the
sole enforcer and correctly scopes uniqueness to pending rows only.

https://claude.ai/code/session_01F8WaH5TmtdUWwhHnVoQ6Gm

* Replace blanket unique index with partial unique index on pending invitations

Instead of dropping the DB-level uniqueness constraint entirely, replace
the unconditional unique index on (email, family_id) with a partial unique
index scoped to WHERE accepted_at IS NULL. This enforces the invariant at
the DB layer (no two non-accepted invitations for the same email in a
family) while allowing re-invites once a prior invitation has been accepted.

https://claude.ai/code/session_01F8WaH5TmtdUWwhHnVoQ6Gm

* Fix migration version and make remove_index reversible

- Change Migration[8.0] to Migration[7.2] to match the rest of the codebase
- Pass column names to remove_index so Rails can reconstruct the old index on rollback

https://claude.ai/code/session_01F8WaH5TmtdUWwhHnVoQ6Gm

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-03-14 11:32:33 +01:00
Chase Martin
50f3a5c030 Fix Plaid link script loading and first-sync account linking (#1165)
* fix: Handle conditional loading of Plaid Link script

* fix: Plaid accounts not linking on first sync

* fix: Handle Plaid script loading edge cases

* fix: Use connection token for disconnect safety and retry failed script loads

* fix: Destroy Plaid Link handler on controller disconnect

* fix: Add timeout to Plaid CDN script loader to prevent deadlocks
2026-03-13 08:11:51 +01:00
Alessio Cappa
9888b3071c feat: move account logo determination in dedicated method (#1190) 2026-03-13 07:56:29 +01:00
soky srm
e1ff6d46ee Make categories global (#1160)
* Make categories global

This solves us A LOT of cash flow and budgeting problems.

* Update schema.rb

* Update auto_categorizer.rb

* Update income_statement.rb

* FIX budget sub-categories

* FIX sub-categories and tests

* Add 2 step migration
2026-03-11 15:54:01 +01:00
Juan José Mata
7ae9077935 Add default family selection for invite-only onboarding mode (#1174)
* Add default family selection for invite-only onboarding mode

When onboarding is set to invite-only, admins can now choose a default
family that new users without an invitation are automatically placed into
as members, instead of creating a new family for each signup.

https://claude.ai/code/session_01U9KgikKjV6xbyBZ5wMYsYx

* Restrict invite codes and onboarding settings to super_admin only

The Invite Codes section on /settings/hosting was visible to any
authenticated user via the show action, leaking all family names/IDs
through the default-family dropdown. This tightens access:

- Hide the entire Invite Codes section in the view behind super_admin?
- Add before_action :ensure_super_admin to InviteCodesController for
  all actions (index, create, destroy), replacing the inline admin? check
- Add ensure_super_admin_for_onboarding filter on hostings#update that
  blocks non-super_admin users from changing onboarding_state or
  invite_only_default_family_id

https://claude.ai/code/session_01U9KgikKjV6xbyBZ5wMYsYx

* Fix tests for super_admin-only invite codes and onboarding settings

- Hostings controller test: sign in as sure_support_staff (super_admin)
  for the onboarding_state update test, since ensure_super_admin_for_onboarding
  now requires super_admin role
- Invite codes tests: use super_admin fixture for the success case and
  verify that a regular admin gets redirected instead of raising StandardError

https://claude.ai/code/session_01U9KgikKjV6xbyBZ5wMYsYx

* Fix system test to use super_admin for self-hosting settings

The invite codes section is now only visible to super_admin users,
so the system test needs to sign in as sure_support_staff to find
the onboarding_state select element.

https://claude.ai/code/session_01U9KgikKjV6xbyBZ5wMYsYx

* Skip invite code requirement when a default family is configured

When onboarding is invite-only but a default family is set, the
claim_invite_code before_action was blocking registration before
the create action could assign the user to the default family.
Now invite_code_required? returns false when
invite_only_default_family_id is present, allowing codeless
signups to land in the configured default family.

https://claude.ai/code/session_01U9KgikKjV6xbyBZ5wMYsYx

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-10 18:12:53 +01:00
Juan José Mata
c09362b880 Check for pending invitations before creating new Family during SSO log in/sign up (#1171)
* Check for pending invitations before creating new Family during SSO account creation

When a user signs in via Google SSO and doesn't have an account yet, the
system now checks for pending invitations before creating a new Family.
If an invitation exists, the user joins the invited family instead.

- OidcAccountsController: check Invitation.pending in link/create_user
- API AuthController: check pending invitations in sso_create_account
- SessionsController: pass has_pending_invitation to mobile SSO callback
- Web view: show "Accept Invitation" button when invitation exists
- Flutter: show "Accept Invitation" tab/button when invitation pending

https://claude.ai/code/session_019Tr6edJa496V1ErGmsbqFU

* Fix external assistant tests: clear Settings cache to prevent test pollution

The tests relied solely on with_env_overrides to clear configuration, but
rails-settings-cached may retain stale Setting values across tests when
the cache isn't explicitly invalidated. Ensure both ENV vars AND Setting
values are cleared with Setting.clear_cache before assertions.

https://claude.ai/code/session_019Tr6edJa496V1ErGmsbqFU

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-10 13:38:42 +01:00
Juan José Mata
c47edaa51e Indexa Capital y very much alpha 2026-03-06 23:58:48 +00:00
Juan José Mata
7fce804c89 Group users by family in /admin/users (#1139)
* Display user admins grouped

* Start family/groups collapsed

* Sort by number of transactions

* Display subscription status

* Fix tests

* Use Stimulus
2026-03-06 23:38:25 +01:00
Michel Roegl-Brunner
f8d3678a40 Fix [1018]: Add Date field when entering Account Balance (#1068)
* Add new Date field when creating a new Account

* Fix german translation

* Update app/controllers/concerns/accountable_resource.rb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com>

* Add missing opening_balance:date to update_params

* Change label text

---------

Signed-off-by: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-06 10:22:01 +01:00
Alessio Cappa
0f78f54f90 New select component (#1071)
* feat: add new UI component to display dropdown select with filter

* feat: use new dropdown componet for category selection in transactions

* feat: improve dropdown controller

* feat: Add checkbox indicator to highlight selected element in list

* feat: add possibility to define dropdown without search

* feat: initial implementation of variants

* feat: Add default color for dropdown menu

* feat: add "icon" variant for dropdown

* refactor: component + controller refactoring

* refactor: view + component

* fix: adjust min width in selection for mobile

* feat: refactor collection_select method to use new filter dropdown component

* fix: compute fixed position for dropdown

* feat: controller improvements

* lint issues

* feat: add dot color if no icon is available

* refactor: controller refactor + update naming for variant from icon to logo

* fix: set width to 100% for select dropdown

* feat: add variant to collection_select in new transaction form

* fix: typo in placeholder value

* fix: add back include_blank property

* refactor: rename component from FilterDropdown to Select

* fix: translate placeholder and keep value_method and text_method

* fix: remove duplicate variable assignment

* fix: translate placeholder

* fix: verify color format

* fix: use right autocomplete value

* fix: selection issue + controller adjustments

* fix: move calls to startAutoUpdate and stopAutoUpdate

* Update app/javascript/controllers/select_controller.js

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>

* fix: add aria-labels

* fix: pass html_options to DS::Select

* fix: unnecessary closing tag

* fix: use offsetvalue for position checks

* fix: use right classes for dropdown transitions

* include options[:prompt] in placeholder init

* fix: remove unused locale key

* fix: Emit a native change event after updating the input value.

* fix: Guard against negative maxHeight in constrained layouts.

* fix: Update test

* fix: lint issues

* Update test/system/transfers_test.rb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>

* Update test/system/transfers_test.rb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>

* refactor: move CSS class for button select form in maybe-design-system.css

---------

Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-06 10:16:14 +01:00
Alessio Cappa
3b2d630d99 Fix holdings table on mobile (#1114)
* fix: extend width for holdings table in reports

* fix: use right cols for header

* fix: reduce padding on sections

* fix: update holdings table display on dashboard

* feat: set max width for holding name

* fix: remove fixed width on last column

* Update app/views/pages/dashboard/_investment_summary.html.erb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>

* fix: add check on holding.ticker to ensure it's present

---------

Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-06 10:11:21 +01:00
Serge L
a92fd3b3e8 feat: Enhance holding detail drawer with live price sync and enriched overview (#1086)
* Feat: Implement manual sync prices functionality and enhance holdings display

* Feat: Enhance sync prices functionality with error handling and update UI components

* Feat: Update sync prices error handling and enhance Spanish locale messages

* Fix: Address CodeRabbit review feedback

- Set fallback @provider_error when prices_updated == 0 so turbo stream
  never fails silently without a visible error message
- Move attr_reader :provider_error to class header in Price::Importer
  for conventional placement alongside other attribute declarations
- Precompute @last_price_updated in controller (show + sync_prices)
  instead of running a DB query directly inside ERB templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix: Replace bare rescue with explicit exception handling in turbo stream view

Bare `rescue` silently swallows all exceptions, making debugging impossible.
Match the pattern already used in show.html.erb: rescue ActiveRecord::RecordInvalid
explicitly, then catch StandardError with logging (message + backtrace) before
falling back to the unknown label.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix: Update test assertion to expect actual provider error message

The stub returns "Yahoo Finance rate limit exceeded" as the provider error.
After the @provider_error fallback fix, the controller now correctly surfaces
the real provider error when present (using .presence || fallback), so the
flash[:alert] is the actual error string, not the generic fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix: Assert scoped security_ids in sync_prices materializer test

Replace loose stub with constructor expectation to verify that
Balance::Materializer is instantiated with the single-security scope.

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

* Fix: Assert holding remap in remap_security test

Add assertion that @holding.security_id is updated to the target
security after remap, covering the core command outcome.

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

* Fix: CI test failure - Update disconnect external assistant test to use env overrides

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 10:05:52 +01:00
Alessio Cappa
ad318ecdb9 fix: remove fixed height on budget chart to fill all the available space (#1124) 2026-03-05 09:26:33 +01:00
Juan José Mata
0057458963 Add dynamic assistant icon: OpenClaw lobster SVG for external assistant (#1122)
* Add dynamic assistant icon: OpenClaw lobster SVG for external assistant

When a family (or installation via ASSISTANT_TYPE env var) uses the
"external" assistant, the AI avatar now shows a lobster/claw icon
(claw.svg / claw-dark.svg) instead of the default builtin AI icon.
The icon switches dynamically based on the current configuration.

https://claude.ai/code/session_01Wt7HiFypk3Nbs8z2hAkmkG

* Update app/views/chats/_ai_avatar.html.erb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Juan José Mata <jjmata@jjmata.com>

---------

Signed-off-by: Juan José Mata <jjmata@jjmata.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-04 18:43:22 +01:00
lolimmlost
158e18cd05 Add budget rollover: copy from previous month (#1100)
* Add budget rollover: copy from previous month

When navigating to an uninitialized budget month, show a prompt
offering to copy amounts from the most recent initialized budget.
Copies budgeted_spending, expected_income, and all matching category
allocations. Also fixes over-allocation warning showing on uninitialized
budgets.

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

* Redirect copy_previous to categories wizard for review

Matches the normal budget setup flow (edit → categories → show)
so users can review/tweak copied allocations before confirming.

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

* Address code review: eager-load categories, guard against overwrite

- Add .includes(:budget_categories) to most_recent_initialized_budget
  to avoid N+1 when copy_from! iterates source categories
- Guard copy_previous action against overwriting already-initialized
  budgets (prevents crafted POST from clobbering existing data)
- Add i18n key for already_initialized flash message

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

* Add invariant guards to copy_from! for defensive safety

Validate that source budget belongs to the same family and precedes
the target budget before copying. Protects against misuse from
other callers beyond the controller.

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

* Fix button overflow on small screens in copy previous prompt

Stack buttons vertically on mobile, side-by-side on sm+ breakpoint.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 21:13:59 +01:00
Alessio Cappa
69f4e47d68 Add safe-area padding for PWA on import page (#1113) 2026-03-03 21:12:27 +01:00
LPW
84bfe5b7ab Add external AI assistant with Pipelock security proxy (#1069)
* feat(helm): add Pipelock ConfigMap, scanning config, and consolidate compose

- Add ConfigMap template rendering DLP, response scanning, MCP input/tool
  scanning, and forward proxy settings from values
- Mount ConfigMap as /etc/pipelock/pipelock.yaml volume in deployment
- Add checksum/config annotation for automatic pod restart on config change
- Gate HTTPS_PROXY/HTTP_PROXY env injection on forwardProxy.enabled (skip
  in MCP-only mode)
- Use hasKey for all boolean values to prevent Helm default swallowing false
- Single source of truth for ports (forwardProxy.port/mcpProxy.port)
- Pipelock-specific imagePullSecrets with fallback to app secrets
- Merge standalone compose.example.pipelock.yml into compose.example.ai.yml
- Add pipelock.example.yaml for Docker Compose users
- Add exclude-paths to CI workflow for locale file false positives

* Add external assistant support (OpenAI-compatible SSE proxy)

Allow self-hosted instances to delegate chat to an external AI agent
via an OpenAI-compatible streaming endpoint. Configurable per-family
through Settings UI or ASSISTANT_TYPE env override.

- Assistant::External::Client: SSE streaming HTTP client (no new gems)
- Settings UI with type selector, env lock indicator, config status
- Helm chart and Docker Compose env var support
- 45 tests covering client, config, routing, controller, integration

* Add session key routing, email allowlist, and config plumbing

Route to the actual OpenClaw session via x-openclaw-session-key header
instead of creating isolated sessions. Gate external assistant access
behind an email allowlist (EXTERNAL_ASSISTANT_ALLOWED_EMAILS env var).
Plumb session_key and allowedEmails through Helm chart, compose, and
env template.

* Add HTTPS_PROXY support to External::Client for Pipelock integration

Net::HTTP does not auto-read HTTPS_PROXY/HTTP_PROXY env vars (unlike
Faraday). Explicitly resolve proxy from environment in build_http so
outbound traffic to the external assistant routes through Pipelock's
forward proxy when enabled. Respects NO_PROXY for internal hosts.

* Add UI fields for external assistant config (Setting-backed with env fallback)

Follow the same pattern as OpenAI settings: database-backed Setting
fields with env var defaults. Self-hosters can now configure the
external assistant URL, token, and agent ID from the browser
(Settings > Self-Hosting > AI Assistant) instead of requiring env vars.
Fields disable when the corresponding env var is set.

* Improve external assistant UI labels and add help text

Change placeholder to generic OpenAI-compatible URL pattern. Add help
text under each field explaining where the values come from: URL from
agent provider, token for authentication, agent ID for multi-agent
routing.

* Add external assistant docs and fix URL help text

Add External AI Assistant section to docs/hosting/ai.md covering setup
(UI and env vars), how it works, Pipelock security scanning, access
control, and Docker Compose example. Drop "chat completions" jargon
from URL help text.

* Harden external assistant: retry logic, disconnect UI, error handling, and test coverage

- Add retry with backoff for transient network errors (no retry after streaming starts)
- Add disconnect button with confirmation modal in self-hosting settings
- Narrow rescue scope with fallback logging for unexpected errors
- Safe cleanup of partial responses on stream interruption
- Gate ai_available? on family assistant_type instead of OR-ing all providers
- Truncate conversation history to last 20 messages
- Proxy-aware HTTP client with NO_PROXY support
- Sanitize protocol to use generic headers (X-Agent-Id, X-Session-Key)
- Full test coverage for streaming, retries, proxy routing, config, and disconnect

* Exclude external assistant client from Pipelock scan-diff

False positive: `@token` instance variable flagged as "Credential in URL".
Temporary workaround until Pipelock supports inline suppression.

* Address review feedback: NO_PROXY boundary fix, SSE done flag, design tokens

- Fix NO_PROXY matching to require domain boundary (exact match or .suffix),
  case-insensitive. Prevents badexample.com matching example.com.
- Add done flag to SSE streaming so read_body stops after [DONE]
- Move MAX_CONVERSATION_MESSAGES to class level
- Use bg-success/bg-destructive design tokens for status indicators
- Add rationale comment for pipelock scan exclusion
- Update docs last-updated date

* Address second round of review feedback

- Allowlist email comparison is now case-insensitive and nil-safe
- Cap SSE buffer at 1 MB to prevent memory blowup from malformed streams
- Don't expose upstream HTTP response body in user-facing errors (log it instead)
- Fix frozen string warning on buffer initialization
- Fix "builtin" typo in docs (should be "built-in")

* Protect completed responses from cleanup, sanitize error messages

- Don't destroy a fully streamed assistant message if post-stream
  metadata update fails (only cleanup partial responses)
- Log raw connection/HTTP errors internally, show generic messages
  to users to avoid leaking network/proxy details
- Update test assertions for new error message wording

* Fix SSE content guard and NO_PROXY test correctness

Use nil check instead of present? for SSE delta content to preserve
whitespace-only chunks (newlines, spaces) that can occur in code output.

Fix NO_PROXY test to use HTTP_PROXY matching the http:// client URL so
the proxy resolution and NO_PROXY bypass logic are actually exercised.

* Forward proxy credentials to Net::HTTP

Pass proxy_uri.user and proxy_uri.password to Net::HTTP.new so
authenticated proxies (http://user:pass@host:port) work correctly.
Without this, credentials parsed from the proxy URL were silently
dropped. Nil values are safe as positional args when no creds exist.

* Update pipelock integration to v0.3.1 with full scanning config

Bump Helm image tag from 0.2.7 to 0.3.1. Add missing security
sections to both the Helm ConfigMap and compose example config:
mcp_tool_policy, mcp_session_binding, and tool_chain_detection.
These protect the /mcp endpoint against tool injection, session
hijacking, and multi-step exfiltration chains.

Add version and mode fields to config files. Enable include_defaults
for DLP and response scanning to merge user patterns with the 35
built-in patterns. Remove redundant --mode CLI flag from the Helm
deployment template since mode is now in the config file.
2026-03-03 15:47:51 +01:00
sentry[bot]
a914e35fca refactor: Improve enable banking panel rendering context (#1073)
Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
2026-03-01 23:23:25 +01:00
lolimmlost
f13da4809b Fix PWA: back/X buttons untappable in wizard layout (budget edit) (#1076)
The wizard layout header lacked safe-area-inset-top padding, causing
the back arrow and X button to sit under the system status bar in PWA
standalone mode. All other layouts already account for this.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-01 22:42:53 +01:00
Duc-Thomas
7e912c1c93 Fix Investment account subtype not saving on creation (#1039)
* Add permitted_accountable_attributes for investments

* Include fields_for for accountable subtype selection
2026-02-23 17:47:49 -05:00
Alessio Cappa
430c95e278 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
2026-02-23 17:43:00 -05:00
Michel Roegl-Brunner
98df0d301a 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

---------

Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-02-23 17:18:15 -05:00
0xRozier
4ba90e0e8a 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.

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

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

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 17:05:46 -05:00
Alessio Cappa
1881606786 feat: Add merchant logo in filter selection (#1037)
* feat: Add merchant logo in filter selection

* fix: move external div outside of if statement
2026-02-21 08:41:33 -06:00
Number Eight
7725661a96 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
2026-02-19 21:54:44 +01:00
Alessio Cappa
13c2335a6a feat: New tag creation UI (#1014)
* feat: Update tag creation UI

* fix: remove unused target

* fix: remove connect/disconnect functions

* fix: remove unnecessary target
2026-02-19 19:55:10 +01:00
dataCenter430
cb3c076f7b fix: show Edit button in account view bulk selection bar (#1002) 2026-02-19 18:55:15 +01:00
Alessio Cappa
862d39dc3b fix: Remove additional padding from JS controller and add directly as a class (#1007) 2026-02-16 23:36:27 +01:00
soky srm
d79d86d848 PDF ai import (#1006)
Add support to review transactions for AI pdf import
2026-02-16 21:11:41 +01: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
Alessio Cappa
23087c1e98 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
2026-02-16 13:45:49 +01:00
Mark Hendriksen
f5469ea774 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.
2026-02-15 23:33:41 +01:00
Mark Hendriksen
ebf89808f5 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.
2026-02-15 13:25:28 +01:00
Alessio Cappa
e0ae71f33a 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
2026-02-15 13:23:19 +01:00
aviu16
bd34165426 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

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

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

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

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 09:31:15 +01:00
BitToby
170bd2858d fix: inverted Buy/Sell type selection by changing amount.negative to amount.positive in trade edit views (#952) 2026-02-14 10:45:50 +01: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
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
Claude
d9acf19038 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
2026-02-13 15:46:19 +01:00
Juan José Mata
9f6bf1080e Bring back /reports link
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-11 20:44:55 +01:00