Full Code of maybe-finance/maybe for AI

main 77b546983275 cached
1578 files
3.5 MB
1.0M tokens
4709 symbols
1 requests
Download .txt
Showing preview only (4,011K chars total). Download the full file or copy to clipboard to get everything.
Repository: maybe-finance/maybe
Branch: main
Commit: 77b546983275
Files: 1578
Total size: 3.5 MB

Directory structure:
gitextract_cwa_8u3g/

├── .cursor/
│   └── rules/
│       ├── cursor_rules.mdc
│       ├── general-rules.mdc
│       ├── project-conventions.mdc
│       ├── project-design.mdc
│       ├── self_improve.mdc
│       ├── stimulus_conventions.mdc
│       ├── testing.mdc
│       ├── ui-ux-design-guidelines.mdc
│       └── view_conventions.mdc
├── .devcontainer/
│   ├── Dockerfile
│   ├── devcontainer.json
│   └── docker-compose.yml
├── .dockerignore
├── .editorconfig
├── .env.example
├── .env.local.example
├── .env.test.example
├── .erb_lint.yml
├── .gitattributes
├── .github/
│   ├── DISCUSSION_TEMPLATE/
│   │   └── feature-requests.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── other.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       ├── pr.yml
│       └── publish.yml
├── .gitignore
├── .rubocop.yml
├── .ruby-version
├── CLAUDE.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── LICENSE
├── Procfile.dev
├── README.md
├── Rakefile
├── app/
│   ├── assets/
│   │   ├── builds/
│   │   │   └── .keep
│   │   └── tailwind/
│   │       ├── application.css
│   │       ├── geist-font.css
│   │       ├── geist-mono-font.css
│   │       ├── maybe-design-system/
│   │       │   ├── background-utils.css
│   │       │   ├── border-utils.css
│   │       │   ├── component-utils.css
│   │       │   ├── foreground-utils.css
│   │       │   └── text-utils.css
│   │       ├── maybe-design-system.css
│   │       └── simonweb_pickr.css
│   ├── channels/
│   │   └── application_cable/
│   │       ├── channel.rb
│   │       └── connection.rb
│   ├── components/
│   │   ├── DS/
│   │   │   ├── alert.html.erb
│   │   │   ├── alert.rb
│   │   │   ├── button.html.erb
│   │   │   ├── button.rb
│   │   │   ├── buttonish.rb
│   │   │   ├── dialog.html.erb
│   │   │   ├── dialog.rb
│   │   │   ├── dialog_controller.js
│   │   │   ├── disclosure.html.erb
│   │   │   ├── disclosure.rb
│   │   │   ├── filled_icon.html.erb
│   │   │   ├── filled_icon.rb
│   │   │   ├── link.html.erb
│   │   │   ├── link.rb
│   │   │   ├── menu.html.erb
│   │   │   ├── menu.rb
│   │   │   ├── menu_controller.js
│   │   │   ├── menu_item.html.erb
│   │   │   ├── menu_item.rb
│   │   │   ├── tab.rb
│   │   │   ├── tabs/
│   │   │   │   ├── nav.rb
│   │   │   │   └── panel.rb
│   │   │   ├── tabs.html.erb
│   │   │   ├── tabs.rb
│   │   │   ├── tabs_controller.js
│   │   │   ├── toggle.html.erb
│   │   │   ├── toggle.rb
│   │   │   ├── tooltip.html.erb
│   │   │   ├── tooltip.rb
│   │   │   └── tooltip_controller.js
│   │   ├── UI/
│   │   │   ├── account/
│   │   │   │   ├── activity_date.html.erb
│   │   │   │   ├── activity_date.rb
│   │   │   │   ├── activity_feed.html.erb
│   │   │   │   ├── activity_feed.rb
│   │   │   │   ├── balance_reconciliation.html.erb
│   │   │   │   ├── balance_reconciliation.rb
│   │   │   │   ├── chart.html.erb
│   │   │   │   └── chart.rb
│   │   │   ├── account_page.html.erb
│   │   │   └── account_page.rb
│   │   ├── application_component.rb
│   │   └── design_system_component.rb
│   ├── controllers/
│   │   ├── accountable_sparklines_controller.rb
│   │   ├── accounts_controller.rb
│   │   ├── api/
│   │   │   └── v1/
│   │   │       ├── accounts_controller.rb
│   │   │       ├── auth_controller.rb
│   │   │       ├── base_controller.rb
│   │   │       ├── chats_controller.rb
│   │   │       ├── messages_controller.rb
│   │   │       ├── test_controller.rb
│   │   │       ├── transactions_controller.rb
│   │   │       └── usage_controller.rb
│   │   ├── application_controller.rb
│   │   ├── budget_categories_controller.rb
│   │   ├── budgets_controller.rb
│   │   ├── categories_controller.rb
│   │   ├── category/
│   │   │   ├── deletions_controller.rb
│   │   │   └── dropdowns_controller.rb
│   │   ├── chats_controller.rb
│   │   ├── concerns/
│   │   │   ├── accountable_resource.rb
│   │   │   ├── authentication.rb
│   │   │   ├── auto_sync.rb
│   │   │   ├── breadcrumbable.rb
│   │   │   ├── entryable_resource.rb
│   │   │   ├── feature_guardable.rb
│   │   │   ├── impersonatable.rb
│   │   │   ├── invitable.rb
│   │   │   ├── localize.rb
│   │   │   ├── notifiable.rb
│   │   │   ├── onboardable.rb
│   │   │   ├── periodable.rb
│   │   │   ├── restore_layout_preferences.rb
│   │   │   ├── self_hostable.rb
│   │   │   ├── store_location.rb
│   │   │   └── stream_extensions.rb
│   │   ├── cookie_sessions_controller.rb
│   │   ├── credit_cards_controller.rb
│   │   ├── cryptos_controller.rb
│   │   ├── currencies_controller.rb
│   │   ├── current_sessions_controller.rb
│   │   ├── depositories_controller.rb
│   │   ├── email_confirmations_controller.rb
│   │   ├── family_exports_controller.rb
│   │   ├── family_merchants_controller.rb
│   │   ├── holdings_controller.rb
│   │   ├── impersonation_sessions_controller.rb
│   │   ├── import/
│   │   │   ├── cleans_controller.rb
│   │   │   ├── configurations_controller.rb
│   │   │   ├── confirms_controller.rb
│   │   │   ├── mappings_controller.rb
│   │   │   ├── rows_controller.rb
│   │   │   └── uploads_controller.rb
│   │   ├── imports_controller.rb
│   │   ├── investments_controller.rb
│   │   ├── invitations_controller.rb
│   │   ├── invite_codes_controller.rb
│   │   ├── loans_controller.rb
│   │   ├── lookbooks_controller.rb
│   │   ├── messages_controller.rb
│   │   ├── mfa_controller.rb
│   │   ├── onboardings_controller.rb
│   │   ├── other_assets_controller.rb
│   │   ├── other_liabilities_controller.rb
│   │   ├── pages_controller.rb
│   │   ├── password_resets_controller.rb
│   │   ├── passwords_controller.rb
│   │   ├── plaid_items_controller.rb
│   │   ├── properties_controller.rb
│   │   ├── registrations_controller.rb
│   │   ├── rules_controller.rb
│   │   ├── securities_controller.rb
│   │   ├── sessions_controller.rb
│   │   ├── settings/
│   │   │   ├── api_keys_controller.rb
│   │   │   ├── billings_controller.rb
│   │   │   ├── hostings_controller.rb
│   │   │   ├── preferences_controller.rb
│   │   │   ├── profiles_controller.rb
│   │   │   └── securities_controller.rb
│   │   ├── subscriptions_controller.rb
│   │   ├── tag/
│   │   │   └── deletions_controller.rb
│   │   ├── tags_controller.rb
│   │   ├── trades_controller.rb
│   │   ├── transaction_categories_controller.rb
│   │   ├── transactions/
│   │   │   ├── bulk_deletions_controller.rb
│   │   │   └── bulk_updates_controller.rb
│   │   ├── transactions_controller.rb
│   │   ├── transfer_matches_controller.rb
│   │   ├── transfers_controller.rb
│   │   ├── users_controller.rb
│   │   ├── valuations_controller.rb
│   │   ├── vehicles_controller.rb
│   │   └── webhooks_controller.rb
│   ├── data_migrations/
│   │   └── balance_component_migrator.rb
│   ├── helpers/
│   │   ├── accounts_helper.rb
│   │   ├── application_helper.rb
│   │   ├── categories_helper.rb
│   │   ├── chats_helper.rb
│   │   ├── custom_confirm.rb
│   │   ├── entries_helper.rb
│   │   ├── imports_helper.rb
│   │   ├── languages_helper.rb
│   │   ├── mfa_helper.rb
│   │   ├── settings_helper.rb
│   │   ├── styled_form_builder.rb
│   │   └── transactions_helper.rb
│   ├── javascript/
│   │   ├── application.js
│   │   ├── controllers/
│   │   │   ├── app_layout_controller.js
│   │   │   ├── application.js
│   │   │   ├── auto_submit_form_controller.js
│   │   │   ├── budget_form_controller.js
│   │   │   ├── bulk_select_controller.js
│   │   │   ├── category_controller.js
│   │   │   ├── chat_controller.js
│   │   │   ├── clipboard_controller.js
│   │   │   ├── color_avatar_controller.js
│   │   │   ├── color_select_controller.js
│   │   │   ├── confirm_dialog_controller.js
│   │   │   ├── deletion_controller.js
│   │   │   ├── donut_chart_controller.js
│   │   │   ├── element_removal_controller.js
│   │   │   ├── file_upload_controller.js
│   │   │   ├── hotkey_controller.js
│   │   │   ├── import_controller.js
│   │   │   ├── index.js
│   │   │   ├── intercom_controller.js
│   │   │   ├── list_filter_controller.js
│   │   │   ├── list_keyboard_navigation_controller.js
│   │   │   ├── mobile_cell_interaction_controller.js
│   │   │   ├── money_field_controller.js
│   │   │   ├── onboarding_controller.js
│   │   │   ├── password_validator_controller.js
│   │   │   ├── password_visibility_controller.js
│   │   │   ├── plaid_controller.js
│   │   │   ├── preserve_scroll_controller.js
│   │   │   ├── profile_image_preview_controller.js
│   │   │   ├── rule/
│   │   │   │   ├── actions_controller.js
│   │   │   │   └── conditions_controller.js
│   │   │   ├── rules_controller.js
│   │   │   ├── sankey_chart_controller.js
│   │   │   ├── scroll_on_connect_controller.js
│   │   │   ├── selectable_link_controller.js
│   │   │   ├── theme_controller.js
│   │   │   ├── time_series_chart_controller.js
│   │   │   ├── tooltip_controller.js
│   │   │   ├── trade_form_controller.js
│   │   │   ├── transfer_match_controller.js
│   │   │   └── turbo_frame_timeout_controller.js
│   │   ├── services/
│   │   │   └── currencies_service.js
│   │   └── shims/
│   │       ├── d3-array-default.js
│   │       └── d3-shape-default.js
│   ├── jobs/
│   │   ├── application_job.rb
│   │   ├── assistant_response_job.rb
│   │   ├── auto_categorize_job.rb
│   │   ├── auto_detect_merchants_job.rb
│   │   ├── data_cache_clear_job.rb
│   │   ├── destroy_job.rb
│   │   ├── family_data_export_job.rb
│   │   ├── family_reset_job.rb
│   │   ├── import_job.rb
│   │   ├── import_market_data_job.rb
│   │   ├── revert_import_job.rb
│   │   ├── rule_job.rb
│   │   ├── security_health_check_job.rb
│   │   ├── stripe_event_handler_job.rb
│   │   ├── sync_cleaner_job.rb
│   │   ├── sync_job.rb
│   │   └── user_purge_job.rb
│   ├── mailers/
│   │   ├── application_mailer.rb
│   │   ├── email_confirmation_mailer.rb
│   │   ├── invitation_mailer.rb
│   │   └── password_mailer.rb
│   ├── models/
│   │   ├── account/
│   │   │   ├── activity_feed_data.rb
│   │   │   ├── anchorable.rb
│   │   │   ├── chartable.rb
│   │   │   ├── current_balance_manager.rb
│   │   │   ├── linkable.rb
│   │   │   ├── market_data_importer.rb
│   │   │   ├── opening_balance_manager.rb
│   │   │   ├── reconcileable.rb
│   │   │   ├── reconciliation_manager.rb
│   │   │   ├── sync_complete_event.rb
│   │   │   └── syncer.rb
│   │   ├── account.rb
│   │   ├── account_import.rb
│   │   ├── address.rb
│   │   ├── api_key.rb
│   │   ├── application_record.rb
│   │   ├── assistant/
│   │   │   ├── broadcastable.rb
│   │   │   ├── configurable.rb
│   │   │   ├── function/
│   │   │   │   ├── get_accounts.rb
│   │   │   │   ├── get_balance_sheet.rb
│   │   │   │   ├── get_income_statement.rb
│   │   │   │   └── get_transactions.rb
│   │   │   ├── function.rb
│   │   │   ├── function_tool_caller.rb
│   │   │   ├── provided.rb
│   │   │   └── responder.rb
│   │   ├── assistant.rb
│   │   ├── assistant_message.rb
│   │   ├── balance/
│   │   │   ├── base_calculator.rb
│   │   │   ├── chart_series_builder.rb
│   │   │   ├── forward_calculator.rb
│   │   │   ├── materializer.rb
│   │   │   ├── reverse_calculator.rb
│   │   │   └── sync_cache.rb
│   │   ├── balance.rb
│   │   ├── balance_sheet/
│   │   │   ├── account_group.rb
│   │   │   ├── account_totals.rb
│   │   │   ├── classification_group.rb
│   │   │   ├── net_worth_series_builder.rb
│   │   │   └── sync_status_monitor.rb
│   │   ├── balance_sheet.rb
│   │   ├── budget.rb
│   │   ├── budget_category.rb
│   │   ├── category.rb
│   │   ├── chat/
│   │   │   └── debuggable.rb
│   │   ├── chat.rb
│   │   ├── concerns/
│   │   │   ├── accountable.rb
│   │   │   ├── enrichable.rb
│   │   │   ├── monetizable.rb
│   │   │   └── syncable.rb
│   │   ├── credit_card.rb
│   │   ├── crypto.rb
│   │   ├── current.rb
│   │   ├── data_enrichment.rb
│   │   ├── demo/
│   │   │   ├── data_cleaner.rb
│   │   │   └── generator.rb
│   │   ├── depository.rb
│   │   ├── developer_message.rb
│   │   ├── entry.rb
│   │   ├── entry_search.rb
│   │   ├── entryable.rb
│   │   ├── exchange_rate/
│   │   │   ├── importer.rb
│   │   │   └── provided.rb
│   │   ├── exchange_rate.rb
│   │   ├── family/
│   │   │   ├── auto_categorizer.rb
│   │   │   ├── auto_merchant_detector.rb
│   │   │   ├── auto_transfer_matchable.rb
│   │   │   ├── data_exporter.rb
│   │   │   ├── plaid_connectable.rb
│   │   │   ├── subscribeable.rb
│   │   │   ├── sync_complete_event.rb
│   │   │   └── syncer.rb
│   │   ├── family.rb
│   │   ├── family_export.rb
│   │   ├── family_merchant.rb
│   │   ├── holding/
│   │   │   ├── forward_calculator.rb
│   │   │   ├── gapfillable.rb
│   │   │   ├── materializer.rb
│   │   │   ├── portfolio_cache.rb
│   │   │   ├── portfolio_snapshot.rb
│   │   │   └── reverse_calculator.rb
│   │   ├── holding.rb
│   │   ├── impersonation_session.rb
│   │   ├── impersonation_session_log.rb
│   │   ├── import/
│   │   │   ├── account_mapping.rb
│   │   │   ├── account_type_mapping.rb
│   │   │   ├── category_mapping.rb
│   │   │   ├── mapping.rb
│   │   │   ├── row.rb
│   │   │   └── tag_mapping.rb
│   │   ├── import.rb
│   │   ├── income_statement/
│   │   │   ├── category_stats.rb
│   │   │   ├── family_stats.rb
│   │   │   └── totals.rb
│   │   ├── income_statement.rb
│   │   ├── investment.rb
│   │   ├── invitation.rb
│   │   ├── invite_code.rb
│   │   ├── loan.rb
│   │   ├── market_data_importer.rb
│   │   ├── measurement.rb
│   │   ├── merchant.rb
│   │   ├── message.rb
│   │   ├── mint_import.rb
│   │   ├── mobile_device.rb
│   │   ├── other_asset.rb
│   │   ├── other_liability.rb
│   │   ├── period.rb
│   │   ├── plaid_account/
│   │   │   ├── importer.rb
│   │   │   ├── investments/
│   │   │   │   ├── balance_calculator.rb
│   │   │   │   ├── holdings_processor.rb
│   │   │   │   ├── security_resolver.rb
│   │   │   │   └── transactions_processor.rb
│   │   │   ├── liabilities/
│   │   │   │   ├── credit_processor.rb
│   │   │   │   ├── mortgage_processor.rb
│   │   │   │   └── student_loan_processor.rb
│   │   │   ├── processor.rb
│   │   │   ├── transactions/
│   │   │   │   ├── category_matcher.rb
│   │   │   │   ├── category_taxonomy.rb
│   │   │   │   └── processor.rb
│   │   │   └── type_mappable.rb
│   │   ├── plaid_account.rb
│   │   ├── plaid_entry/
│   │   │   └── processor.rb
│   │   ├── plaid_item/
│   │   │   ├── accounts_snapshot.rb
│   │   │   ├── importer.rb
│   │   │   ├── provided.rb
│   │   │   ├── sync_complete_event.rb
│   │   │   ├── syncer.rb
│   │   │   └── webhook_processor.rb
│   │   ├── plaid_item.rb
│   │   ├── property.rb
│   │   ├── provider/
│   │   │   ├── exchange_rate_concept.rb
│   │   │   ├── github.rb
│   │   │   ├── llm_concept.rb
│   │   │   ├── openai/
│   │   │   │   ├── auto_categorizer.rb
│   │   │   │   ├── auto_merchant_detector.rb
│   │   │   │   ├── chat_config.rb
│   │   │   │   ├── chat_parser.rb
│   │   │   │   └── chat_stream_parser.rb
│   │   │   ├── openai.rb
│   │   │   ├── plaid.rb
│   │   │   ├── plaid_sandbox.rb
│   │   │   ├── registry.rb
│   │   │   ├── security_concept.rb
│   │   │   ├── stripe/
│   │   │   │   ├── event_processor.rb
│   │   │   │   └── subscription_event_processor.rb
│   │   │   ├── stripe.rb
│   │   │   └── synth.rb
│   │   ├── provider.rb
│   │   ├── provider_merchant.rb
│   │   ├── rejected_transfer.rb
│   │   ├── rule/
│   │   │   ├── action.rb
│   │   │   ├── action_executor/
│   │   │   │   ├── auto_categorize.rb
│   │   │   │   ├── auto_detect_merchants.rb
│   │   │   │   ├── set_transaction_category.rb
│   │   │   │   ├── set_transaction_merchant.rb
│   │   │   │   ├── set_transaction_name.rb
│   │   │   │   └── set_transaction_tags.rb
│   │   │   ├── action_executor.rb
│   │   │   ├── condition.rb
│   │   │   ├── condition_filter/
│   │   │   │   ├── transaction_amount.rb
│   │   │   │   ├── transaction_merchant.rb
│   │   │   │   └── transaction_name.rb
│   │   │   ├── condition_filter.rb
│   │   │   ├── registry/
│   │   │   │   └── transaction_resource.rb
│   │   │   └── registry.rb
│   │   ├── rule.rb
│   │   ├── security/
│   │   │   ├── health_checker.rb
│   │   │   ├── price/
│   │   │   │   └── importer.rb
│   │   │   ├── price.rb
│   │   │   ├── provided.rb
│   │   │   ├── resolver.rb
│   │   │   └── synth_combobox_option.rb
│   │   ├── security.rb
│   │   ├── series.rb
│   │   ├── session.rb
│   │   ├── setting.rb
│   │   ├── subscription.rb
│   │   ├── sync.rb
│   │   ├── tag.rb
│   │   ├── tagging.rb
│   │   ├── tool_call/
│   │   │   └── function.rb
│   │   ├── tool_call.rb
│   │   ├── trade/
│   │   │   └── create_form.rb
│   │   ├── trade.rb
│   │   ├── trade_import.rb
│   │   ├── transaction/
│   │   │   ├── ruleable.rb
│   │   │   ├── search.rb
│   │   │   └── transferable.rb
│   │   ├── transaction.rb
│   │   ├── transaction_import.rb
│   │   ├── transfer/
│   │   │   └── creator.rb
│   │   ├── transfer.rb
│   │   ├── trend.rb
│   │   ├── user.rb
│   │   ├── user_message.rb
│   │   ├── valuation/
│   │   │   └── name.rb
│   │   ├── valuation.rb
│   │   └── vehicle.rb
│   ├── services/
│   │   ├── api_rate_limiter.rb
│   │   └── noop_api_rate_limiter.rb
│   └── views/
│       ├── accountable_sparklines/
│       │   └── show.html.erb
│       ├── accounts/
│       │   ├── _account.html.erb
│       │   ├── _account_sidebar_tabs.html.erb
│       │   ├── _account_type.html.erb
│       │   ├── _accountable_group.html.erb
│       │   ├── _empty.html.erb
│       │   ├── _form.html.erb
│       │   ├── _logo.html.erb
│       │   ├── _summary_card.html.erb
│       │   ├── index/
│       │   │   ├── _account_groups.erb
│       │   │   └── _manual_accounts.html.erb
│       │   ├── index.html.erb
│       │   ├── new/
│       │   │   ├── _container.html.erb
│       │   │   └── _method_selector.html.erb
│       │   ├── new.html.erb
│       │   ├── show/
│       │   │   ├── _activity.html.erb
│       │   │   ├── _header.html.erb
│       │   │   └── _menu.html.erb
│       │   ├── show.html.erb
│       │   └── sparkline.html.erb
│       ├── api/
│       │   └── v1/
│       │       ├── accounts/
│       │       │   └── index.json.jbuilder
│       │       ├── chats/
│       │       │   ├── _chat.json.jbuilder
│       │       │   ├── index.json.jbuilder
│       │       │   └── show.json.jbuilder
│       │       ├── messages/
│       │       │   └── show.json.jbuilder
│       │       └── transactions/
│       │           ├── _transaction.json.jbuilder
│       │           ├── index.json.jbuilder
│       │           └── show.json.jbuilder
│       ├── assistant_messages/
│       │   ├── _assistant_message.html.erb
│       │   └── _tool_calls.html.erb
│       ├── budget_categories/
│       │   ├── _allocation_progress.erb
│       │   ├── _budget_category.html.erb
│       │   ├── _budget_category_donut.html.erb
│       │   ├── _budget_category_form.html.erb
│       │   ├── _confirm_button.html.erb
│       │   ├── _no_categories.html.erb
│       │   ├── _uncategorized_budget_category_form.html.erb
│       │   ├── index.html.erb
│       │   ├── show.html.erb
│       │   └── update.turbo_stream.erb
│       ├── budgets/
│       │   ├── _actuals_summary.html.erb
│       │   ├── _budget_categories.html.erb
│       │   ├── _budget_donut.html.erb
│       │   ├── _budget_header.html.erb
│       │   ├── _budget_nav.html.erb
│       │   ├── _budgeted_summary.html.erb
│       │   ├── _over_allocation_warning.html.erb
│       │   ├── _picker.html.erb
│       │   ├── edit.html.erb
│       │   └── show.html.erb
│       ├── categories/
│       │   ├── _badge.html.erb
│       │   ├── _category.html.erb
│       │   ├── _category_list_group.html.erb
│       │   ├── _color_avatar.html.erb
│       │   ├── _form.html.erb
│       │   ├── _menu.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── category/
│       │   ├── deletions/
│       │   │   └── new.html.erb
│       │   └── dropdowns/
│       │       ├── _row.html.erb
│       │       └── show.html.erb
│       ├── chats/
│       │   ├── _ai_avatar.html.erb
│       │   ├── _ai_consent.html.erb
│       │   ├── _ai_greeting.html.erb
│       │   ├── _chat.html.erb
│       │   ├── _chat_nav.html.erb
│       │   ├── _chat_title.html.erb
│       │   ├── _error.html.erb
│       │   ├── _thinking_indicator.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── credit_cards/
│       │   ├── _form.html.erb
│       │   ├── _overview.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── cryptos/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── depositories/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── developer_messages/
│       │   └── _developer_message.html.erb
│       ├── doorkeeper/
│       │   ├── applications/
│       │   │   ├── _delete_form.html.erb
│       │   │   ├── _form.html.erb
│       │   │   ├── edit.html.erb
│       │   │   ├── index.html.erb
│       │   │   ├── new.html.erb
│       │   │   └── show.html.erb
│       │   ├── authorizations/
│       │   │   ├── error.html.erb
│       │   │   ├── form_post.html.erb
│       │   │   ├── new.html.erb
│       │   │   └── show.html.erb
│       │   └── authorized_applications/
│       │       ├── _delete_form.html.erb
│       │       └── index.html.erb
│       ├── email_confirmation_mailer/
│       │   ├── confirmation_email.html.erb
│       │   └── confirmation_email.text.erb
│       ├── entries/
│       │   ├── _empty.html.erb
│       │   ├── _entry.html.erb
│       │   ├── _entry_group.html.erb
│       │   ├── _loading.html.erb
│       │   └── _selection_bar.html.erb
│       ├── family_exports/
│       │   ├── _list.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── family_merchants/
│       │   ├── _family_merchant.html.erb
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── holdings/
│       │   ├── _cash.html.erb
│       │   ├── _holding.html.erb
│       │   ├── _missing_price_tooltip.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── impersonation_sessions/
│       │   ├── _approval_bar.html.erb
│       │   └── _super_admin_bar.html.erb
│       ├── import/
│       │   ├── cleans/
│       │   │   └── show.html.erb
│       │   ├── configurations/
│       │   │   ├── _account_import.html.erb
│       │   │   ├── _mint_import.html.erb
│       │   │   ├── _trade_import.html.erb
│       │   │   ├── _transaction_import.html.erb
│       │   │   └── show.html.erb
│       │   ├── confirms/
│       │   │   ├── _mappings.html.erb
│       │   │   └── show.html.erb
│       │   ├── mappings/
│       │   │   └── _form.html.erb
│       │   ├── rows/
│       │   │   ├── _form.html.erb
│       │   │   └── show.html.erb
│       │   └── uploads/
│       │       └── show.html.erb
│       ├── imports/
│       │   ├── _empty.html.erb
│       │   ├── _failure.html.erb
│       │   ├── _import.html.erb
│       │   ├── _importing.html.erb
│       │   ├── _nav.html.erb
│       │   ├── _ready.html.erb
│       │   ├── _revert_failure.html.erb
│       │   ├── _success.html.erb
│       │   ├── _table.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── investments/
│       │   ├── _form.html.erb
│       │   ├── _value_tooltip.html.erb
│       │   ├── edit.html.erb
│       │   ├── new.html.erb
│       │   └── tabs/
│       │       └── _holdings.html.erb
│       ├── invitation_mailer/
│       │   └── invite_email.html.erb
│       ├── invitations/
│       │   └── new.html.erb
│       ├── invite_codes/
│       │   ├── _invite_code.html.erb
│       │   └── index.html.erb
│       ├── layouts/
│       │   ├── application.html.erb
│       │   ├── auth.html.erb
│       │   ├── blank.html.erb
│       │   ├── doorkeeper/
│       │   │   ├── admin.html.erb
│       │   │   └── application.html.erb
│       │   ├── imports.html.erb
│       │   ├── lookbooks.html.erb
│       │   ├── mailer.html.erb
│       │   ├── mailer.text.erb
│       │   ├── onboardings.html.erb
│       │   ├── settings.html.erb
│       │   ├── shared/
│       │   │   ├── _breadcrumbs.html.erb
│       │   │   ├── _confirm_dialog.html.erb
│       │   │   ├── _footer.html.erb
│       │   │   ├── _head.html.erb
│       │   │   ├── _htmldoc.html.erb
│       │   │   ├── _nav_item.html.erb
│       │   │   └── _page_header.html.erb
│       │   └── wizard.html.erb
│       ├── loans/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   ├── new.html.erb
│       │   └── tabs/
│       │       └── _overview.html.erb
│       ├── messages/
│       │   └── _chat_form.html.erb
│       ├── mfa/
│       │   ├── backup_codes.html.erb
│       │   ├── new.html.erb
│       │   └── verify.html.erb
│       ├── onboardings/
│       │   ├── _logout.html.erb
│       │   ├── _onboarding_nav.html.erb
│       │   ├── goals.html.erb
│       │   ├── preferences.html.erb
│       │   ├── show.html.erb
│       │   └── trial.html.erb
│       ├── other_assets/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── other_liabilities/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── pages/
│       │   ├── changelog.html.erb
│       │   ├── dashboard/
│       │   │   ├── _balance_sheet.html.erb
│       │   │   ├── _cashflow_sankey.html.erb
│       │   │   ├── _group_weight.html.erb
│       │   │   ├── _net_worth_chart.html.erb
│       │   │   └── _no_accounts_graph_placeholder.html.erb
│       │   ├── dashboard.html.erb
│       │   ├── feedback.html.erb
│       │   └── redis_configuration_error.html.erb
│       ├── password_mailer/
│       │   └── password_reset.html.erb
│       ├── password_resets/
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── passwords/
│       │   └── edit.html.erb
│       ├── plaid_items/
│       │   ├── _auto_link_opener.html.erb
│       │   ├── _plaid_item.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── properties/
│       │   ├── _form.html.erb
│       │   ├── _form_alert.html.erb
│       │   ├── _form_tab.html.erb
│       │   ├── _form_tabs.html.erb
│       │   ├── _overview_fields.html.erb
│       │   ├── address.html.erb
│       │   ├── balances.html.erb
│       │   ├── edit.html.erb
│       │   ├── new.html.erb
│       │   └── tabs/
│       │       └── _overview.html.erb
│       ├── pwa/
│       │   ├── manifest.json.erb
│       │   └── service-worker.js
│       ├── registrations/
│       │   └── new.html.erb
│       ├── rule/
│       │   ├── actions/
│       │   │   └── _action.html.erb
│       │   └── conditions/
│       │       ├── _condition.html.erb
│       │       └── _condition_group.html.erb
│       ├── rules/
│       │   ├── _category_rule_cta.html.erb
│       │   ├── _form.html.erb
│       │   ├── _rule.html.erb
│       │   ├── confirm.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── securities/
│       │   ├── _combobox_security.turbo_stream.erb
│       │   └── index.turbo_stream.erb
│       ├── sessions/
│       │   └── new.html.erb
│       ├── settings/
│       │   ├── _section.html.erb
│       │   ├── _settings_nav.html.erb
│       │   ├── _settings_nav_item.html.erb
│       │   ├── _settings_nav_link_large.html.erb
│       │   ├── _user_avatar.html.erb
│       │   ├── _user_avatar_field.html.erb
│       │   ├── api_keys/
│       │   │   ├── created.html.erb
│       │   │   ├── created.turbo_stream.erb
│       │   │   ├── new.html.erb
│       │   │   └── show.html.erb
│       │   ├── billings/
│       │   │   └── show.html.erb
│       │   ├── hostings/
│       │   │   ├── _danger_zone_settings.html.erb
│       │   │   ├── _invite_code_settings.html.erb
│       │   │   ├── _synth_settings.html.erb
│       │   │   └── show.html.erb
│       │   ├── preferences/
│       │   │   └── show.html.erb
│       │   ├── profiles/
│       │   │   └── show.html.erb
│       │   └── securities/
│       │       └── show.html.erb
│       ├── shared/
│       │   ├── _app_version.html.erb
│       │   ├── _color_avatar.html.erb
│       │   ├── _form_errors.html.erb
│       │   ├── _logo.html.erb
│       │   ├── _money_field.html.erb
│       │   ├── _pagination.html.erb
│       │   ├── _progress_circle.html.erb
│       │   ├── _ruler.html.erb
│       │   ├── _sparkline.html.erb
│       │   ├── _text_tooltip.erb
│       │   ├── _transaction_type_tabs.html.erb
│       │   ├── _trend_change.html.erb
│       │   └── notifications/
│       │       ├── _alert.html.erb
│       │       ├── _cta.html.erb
│       │       └── _notice.html.erb
│       ├── subscriptions/
│       │   ├── _plan_choice.html.erb
│       │   └── upgrade.html.erb
│       ├── tag/
│       │   └── deletions/
│       │       └── new.html.erb
│       ├── tags/
│       │   ├── _badge.html.erb
│       │   ├── _form.html.erb
│       │   ├── _tag.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── trades/
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _trade.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── transactions/
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _selection_bar.html.erb
│       │   ├── _summary.html.erb
│       │   ├── _transaction.html.erb
│       │   ├── _transaction_category.html.erb
│       │   ├── _transfer_match.html.erb
│       │   ├── bulk_updates/
│       │   │   └── new.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   ├── searches/
│       │   │   ├── _form.html.erb
│       │   │   ├── _menu.html.erb
│       │   │   ├── _search.html.erb
│       │   │   └── filters/
│       │   │       ├── _account_filter.html.erb
│       │   │       ├── _amount_filter.html.erb
│       │   │       ├── _badge.html.erb
│       │   │       ├── _category_filter.html.erb
│       │   │       ├── _date_filter.html.erb
│       │   │       ├── _merchant_filter.html.erb
│       │   │       ├── _tag_filter.html.erb
│       │   │       └── _type_filter.html.erb
│       │   └── show.html.erb
│       ├── transfer_matches/
│       │   ├── _matching_fields.html.erb
│       │   └── new.html.erb
│       ├── transfers/
│       │   ├── _account_links.html.erb
│       │   ├── _form.html.erb
│       │   ├── new.html.erb
│       │   ├── show.html.erb
│       │   └── update.turbo_stream.erb
│       ├── user_messages/
│       │   └── _user_message.html.erb
│       ├── users/
│       │   └── _user_menu.html.erb
│       ├── valuations/
│       │   ├── _confirmation_contents.html.erb
│       │   ├── _header.html.erb
│       │   ├── _valuation.html.erb
│       │   ├── confirm_create.html.erb
│       │   ├── confirm_update.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       └── vehicles/
│           ├── _form.html.erb
│           ├── edit.html.erb
│           ├── new.html.erb
│           └── tabs/
│               └── _overview.html.erb
├── bin/
│   ├── brakeman
│   ├── bundle
│   ├── dev
│   ├── docker-entrypoint
│   ├── importmap
│   ├── rails
│   ├── rake
│   ├── render-build.sh
│   ├── rubocop
│   ├── setup
│   └── update_structure.sh
├── biome.json
├── compose.example.yml
├── config/
│   ├── application.rb
│   ├── boot.rb
│   ├── brakeman.ignore
│   ├── cable.yml
│   ├── credentials.yml.enc
│   ├── currencies.yml
│   ├── database.yml
│   ├── environment.rb
│   ├── environments/
│   │   ├── development.rb
│   │   ├── production.rb
│   │   └── test.rb
│   ├── i18n-tasks.yml
│   ├── importmap.rb
│   ├── initializers/
│   │   ├── active_record_encryption.rb
│   │   ├── assets.rb
│   │   ├── content_security_policy.rb
│   │   ├── doorkeeper.rb
│   │   ├── doorkeeper_csrf_protection.rb
│   │   ├── doorkeeper_layout.rb
│   │   ├── enable_yjit.rb
│   │   ├── filter_parameter_logging.rb
│   │   ├── generator.rb
│   │   ├── inflections.rb
│   │   ├── intercom.rb
│   │   ├── mini_profiler.rb
│   │   ├── pagy.rb
│   │   ├── permissions_policy.rb
│   │   ├── plaid.rb
│   │   ├── rack_attack.rb
│   │   ├── sentry.rb
│   │   ├── sidekiq.rb
│   │   └── version.rb
│   ├── locales/
│   │   ├── defaults/
│   │   │   ├── af.yml
│   │   │   ├── ar.yml
│   │   │   ├── az.yml
│   │   │   ├── be.yml
│   │   │   ├── bg.yml
│   │   │   ├── bn.yml
│   │   │   ├── bs.yml
│   │   │   ├── ca.yml
│   │   │   ├── cs.yml
│   │   │   ├── cy.yml
│   │   │   ├── da.yml
│   │   │   ├── de-AT.yml
│   │   │   ├── de-CH.yml
│   │   │   ├── de-DE.yml
│   │   │   ├── de.yml
│   │   │   ├── dz.yml
│   │   │   ├── el-CY.yml
│   │   │   ├── el.yml
│   │   │   ├── en-AU.yml
│   │   │   ├── en-CA.yml
│   │   │   ├── en-CY.yml
│   │   │   ├── en-GB.yml
│   │   │   ├── en-IE.yml
│   │   │   ├── en-IN.yml
│   │   │   ├── en-NZ.yml
│   │   │   ├── en-TT.yml
│   │   │   ├── en-US.yml
│   │   │   ├── en-ZA.yml
│   │   │   ├── en.yml
│   │   │   ├── eo.yml
│   │   │   ├── es-419.yml
│   │   │   ├── es-AR.yml
│   │   │   ├── es-CL.yml
│   │   │   ├── es-CO.yml
│   │   │   ├── es-CR.yml
│   │   │   ├── es-EC.yml
│   │   │   ├── es-ES.yml
│   │   │   ├── es-MX.yml
│   │   │   ├── es-NI.yml
│   │   │   ├── es-PA.yml
│   │   │   ├── es-PE.yml
│   │   │   ├── es-US.yml
│   │   │   ├── es-VE.yml
│   │   │   ├── es.yml
│   │   │   ├── et.yml
│   │   │   ├── eu.yml
│   │   │   ├── fa.yml
│   │   │   ├── fi.yml
│   │   │   ├── fr-CA.yml
│   │   │   ├── fr-CH.yml
│   │   │   ├── fr-FR.yml
│   │   │   ├── fr.yml
│   │   │   ├── fy.yml
│   │   │   ├── gd.yml
│   │   │   ├── gl.yml
│   │   │   ├── he.yml
│   │   │   ├── hi-IN.yml
│   │   │   ├── hi.yml
│   │   │   ├── hr.yml
│   │   │   ├── hu.yml
│   │   │   ├── id.yml
│   │   │   ├── is.yml
│   │   │   ├── it-CH.yml
│   │   │   ├── it.yml
│   │   │   ├── ja.yml
│   │   │   ├── ka.yml
│   │   │   ├── kk.yml
│   │   │   ├── km.yml
│   │   │   ├── kn.yml
│   │   │   ├── ko.yml
│   │   │   ├── lb.yml
│   │   │   ├── lo.yml
│   │   │   ├── lt.yml
│   │   │   ├── lv.yml
│   │   │   ├── mg.yml
│   │   │   ├── mk.yml
│   │   │   ├── ml.yml
│   │   │   ├── mn.yml
│   │   │   ├── mr-IN.yml
│   │   │   ├── ms.yml
│   │   │   ├── nb.yml
│   │   │   ├── ne.yml
│   │   │   ├── nl.yml
│   │   │   ├── nn.yml
│   │   │   ├── oc.yml
│   │   │   ├── or.yml
│   │   │   ├── pa.yml
│   │   │   ├── pl.yml
│   │   │   ├── pt-BR.yml
│   │   │   ├── pt.yml
│   │   │   ├── rm.yml
│   │   │   ├── ro.yml
│   │   │   ├── ru.yml
│   │   │   ├── sc.yml
│   │   │   ├── sk.yml
│   │   │   ├── sl.yml
│   │   │   ├── sq.yml
│   │   │   ├── sr.yml
│   │   │   ├── st.yml
│   │   │   ├── sv-FI.yml
│   │   │   ├── sv-SE.yml
│   │   │   ├── sv.yml
│   │   │   ├── sw.yml
│   │   │   ├── ta.yml
│   │   │   ├── te.yml
│   │   │   ├── th.yml
│   │   │   ├── tl.yml
│   │   │   ├── tr.yml
│   │   │   ├── tt.yml
│   │   │   ├── ug.yml
│   │   │   ├── uk.yml
│   │   │   ├── ur.yml
│   │   │   ├── uz.yml
│   │   │   ├── vi.yml
│   │   │   ├── wo.yml
│   │   │   ├── zh-CN.yml
│   │   │   └── zh-TW.yml
│   │   ├── doorkeeper.en.yml
│   │   ├── mailers/
│   │   │   └── invitation_mailer/
│   │   │       └── en.yml
│   │   ├── models/
│   │   │   ├── account/
│   │   │   │   └── en.yml
│   │   │   ├── address/
│   │   │   │   └── en.yml
│   │   │   ├── entry/
│   │   │   │   └── en.yml
│   │   │   ├── import/
│   │   │   │   └── en.yml
│   │   │   ├── time_series/
│   │   │   │   └── value/
│   │   │   │       └── en.yml
│   │   │   ├── transfer/
│   │   │   │   └── en.yml
│   │   │   ├── trend/
│   │   │   │   └── en.yml
│   │   │   └── user/
│   │   │       └── en.yml
│   │   └── views/
│   │       ├── accounts/
│   │       │   └── en.yml
│   │       ├── application/
│   │       │   └── en.yml
│   │       ├── categories/
│   │       │   └── en.yml
│   │       ├── category/
│   │       │   ├── deletions/
│   │       │   │   └── en.yml
│   │       │   └── dropdowns/
│   │       │       └── en.yml
│   │       ├── credit_cards/
│   │       │   └── en.yml
│   │       ├── cryptos/
│   │       │   └── en.yml
│   │       ├── depositories/
│   │       │   └── en.yml
│   │       ├── email_confirmation_mailer/
│   │       │   └── en.yml
│   │       ├── entries/
│   │       │   └── en.yml
│   │       ├── holdings/
│   │       │   └── en.yml
│   │       ├── impersonation_sessions/
│   │       │   └── en.yml
│   │       ├── imports/
│   │       │   └── en.yml
│   │       ├── investments/
│   │       │   └── en.yml
│   │       ├── invitation_mailer/
│   │       │   └── en.yml
│   │       ├── invitations/
│   │       │   └── en.yml
│   │       ├── invite_codes/
│   │       │   └── en.yml
│   │       ├── layout/
│   │       │   └── en.yml
│   │       ├── loans/
│   │       │   └── en.yml
│   │       ├── merchants/
│   │       │   └── en.yml
│   │       ├── mfa/
│   │       │   └── en.yml
│   │       ├── onboardings/
│   │       │   └── en.yml
│   │       ├── other_assets/
│   │       │   └── en.yml
│   │       ├── other_liabilities/
│   │       │   └── en.yml
│   │       ├── pages/
│   │       │   └── en.yml
│   │       ├── password_mailer/
│   │       │   └── en.yml
│   │       ├── password_resets/
│   │       │   └── en.yml
│   │       ├── passwords/
│   │       │   └── en.yml
│   │       ├── plaid_items/
│   │       │   └── en.yml
│   │       ├── properties/
│   │       │   └── en.yml
│   │       ├── registrations/
│   │       │   └── en.yml
│   │       ├── sessions/
│   │       │   └── en.yml
│   │       ├── settings/
│   │       │   ├── api_keys/
│   │       │   │   └── en.yml
│   │       │   ├── en.yml
│   │       │   ├── hostings/
│   │       │   │   └── en.yml
│   │       │   └── securities/
│   │       │       └── en.yml
│   │       ├── shared/
│   │       │   └── en.yml
│   │       ├── subscriptions/
│   │       │   └── en.yml
│   │       ├── tag/
│   │       │   └── deletions/
│   │       │       └── en.yml
│   │       ├── tags/
│   │       │   └── en.yml
│   │       ├── trades/
│   │       │   └── en.yml
│   │       ├── transactions/
│   │       │   └── en.yml
│   │       ├── transfers/
│   │       │   └── en.yml
│   │       ├── users/
│   │       │   └── en.yml
│   │       ├── valuations/
│   │       │   └── en.yml
│   │       └── vehicles/
│   │           └── en.yml
│   ├── puma.rb
│   ├── routes.rb
│   ├── schedule.yml
│   ├── sidekiq.yml
│   └── storage.yml
├── config.ru
├── db/
│   ├── migrate/
│   │   ├── 20240201183314_enable_uuid.rb
│   │   ├── 20240201184038_create_families.rb
│   │   ├── 20240201184212_create_users.rb
│   │   ├── 20240202015428_create_accounts.rb
│   │   ├── 20240202191425_create_account_loans.rb
│   │   ├── 20240202191746_add_accountable_to_account.rb
│   │   ├── 20240202192214_create_account_depositories.rb
│   │   ├── 20240202192231_create_account_credits.rb
│   │   ├── 20240202192238_create_account_investments.rb
│   │   ├── 20240202192312_create_account_properties.rb
│   │   ├── 20240202192319_create_account_vehicles.rb
│   │   ├── 20240202192327_create_account_other_assets.rb
│   │   ├── 20240202192333_create_account_other_liabilities.rb
│   │   ├── 20240202230325_create_invite_codes.rb
│   │   ├── 20240203030754_remove_type_from_accounts.rb
│   │   ├── 20240203050018_add_token_index_to_invite_codes.rb
│   │   ├── 20240206031739_replace_money_field.rb
│   │   ├── 20240209153232_add_currency_to_families.rb
│   │   ├── 20240209174912_redo_money_storage.rb
│   │   ├── 20240209200519_create_currencies.rb
│   │   ├── 20240209200924_create_exchange_rates.rb
│   │   ├── 20240210155058_create_good_jobs.rb
│   │   ├── 20240212150110_create_account_balances.rb
│   │   ├── 20240215201527_create_valuations.rb
│   │   ├── 20240221004818_remove_valuation_type.rb
│   │   ├── 20240222144849_add_status_to_account.rb
│   │   ├── 20240223162105_create_transactions.rb
│   │   ├── 20240227142457_rename_account_balance.rb
│   │   ├── 20240302145715_add_classification_to_accounts.rb
│   │   ├── 20240306193345_add_is_active_to_account.rb
│   │   ├── 20240307082827_create_transaction_categories.rb
│   │   ├── 20240308121431_remove_currency_table.rb
│   │   ├── 20240308214956_add_notes_and_excluded_to_transaction.rb
│   │   ├── 20240309180636_add_sync_status_fields_to_account.rb
│   │   ├── 20240313141813_update_unique_indexes_for_account_balance_and_exchange_rate.rb
│   │   ├── 20240313203622_remove_converted_balance_from_account.rb
│   │   ├── 20240319154732_create_account_cryptos.rb
│   │   ├── 20240325064211_add_uniq_index_to_users_email.rb
│   │   ├── 20240401213443_add_last_sync_date_to_accounts.rb
│   │   ├── 20240403192649_add_last_login_at_to_users.rb
│   │   ├── 20240404112829_change_transaction_category_delete_behavior.rb
│   │   ├── 20240410183531_create_settings.rb
│   │   ├── 20240411102931_add_last_seen_upgrade_to_user.rb
│   │   ├── 20240425000110_add_role_to_users.rb
│   │   ├── 20240426162500_create_active_storage_tables.active_storage.rb
│   │   ├── 20240426191312_add_transaction_merchants.rb
│   │   ├── 20240430111641_add_active_to_users.rb
│   │   ├── 20240502205006_create_imports.rb
│   │   ├── 20240520074309_add_admin_role_to_current_users.rb
│   │   ├── 20240522133147_create_tags.rb
│   │   ├── 20240522151453_create_taggings.rb
│   │   ├── 20240524203959_change_account_error_columns_default.rb
│   │   ├── 20240612164751_create_institutions.rb
│   │   ├── 20240612164944_add_institution_to_accounts.rb
│   │   ├── 20240614120946_create_transfers.rb
│   │   ├── 20240614121110_add_transfer_fields_to_transaction.rb
│   │   ├── 20240619125949_rename_accountable_tables.rb
│   │   ├── 20240620114307_rename_categories_table.rb
│   │   ├── 20240620122201_rename_merchants_table.rb
│   │   ├── 20240620125026_rename_transfer_table.rb
│   │   ├── 20240620221801_rename_valuation_table.rb
│   │   ├── 20240621212528_rename_transactions_table.rb
│   │   ├── 20240624160611_create_account_entries.rb
│   │   ├── 20240624161153_migrate_entryables.rb
│   │   ├── 20240624164119_remove_old_columns_from_entryables.rb
│   │   ├── 20240628104551_move_transfers_association_from_transactions_to_entries.rb
│   │   ├── 20240706151026_rename_rate_fields.rb
│   │   ├── 20240707130331_create_account_syncs.rb
│   │   ├── 20240709113713_create_good_job_execution_error_backtrace.rb
│   │   ├── 20240709113714_create_good_job_process_lock_ids.rb
│   │   ├── 20240709113715_create_good_job_process_lock_indexes.rb
│   │   ├── 20240709152243_create_good_job_execution_duration.rb
│   │   ├── 20240710182529_create_securities.rb
│   │   ├── 20240710182728_create_security_prices.rb
│   │   ├── 20240710184048_create_account_trades.rb
│   │   ├── 20240710184249_create_account_holdings.rb
│   │   ├── 20240717113535_remove_default_from_account_balance.rb
│   │   ├── 20240725163339_add_last_synced_at_to_family.rb
│   │   ├── 20240731191344_change_primary_identifier_for_security.rb
│   │   ├── 20240807153618_add_currency_field_to_trade.rb
│   │   ├── 20240813170608_fix_invalid_accountable_data.rb
│   │   ├── 20240815125404_create_issues.rb
│   │   ├── 20240815190722_remove_warnings_from_sync.rb
│   │   ├── 20240816071555_add_col_sep_to_imports.rb
│   │   ├── 20240817144454_rename_import_raw_csv_str_to_raw_file_str.rb
│   │   ├── 20240822174006_create_addresses.rb
│   │   ├── 20240822180845_add_property_attributes.rb
│   │   ├── 20240823125526_add_details_to_vehicle.rb
│   │   ├── 20240911143158_add_last_synced_at_institution.rb
│   │   ├── 20240921170426_change_import_owner.rb
│   │   ├── 20240925112218_add_import_types.rb
│   │   ├── 20241001181256_add_locale_preference.rb
│   │   ├── 20241003163448_create_sessions.rb
│   │   ├── 20241007211438_add_billing_to_families.rb
│   │   ├── 20241008122449_add_debt_account_views.rb
│   │   ├── 20241009132959_add_notes_to_entry.rb
│   │   ├── 20241009214601_add_super_admin_to_users.rb
│   │   ├── 20241017162347_create_impersonation_sessions.rb
│   │   ├── 20241017162536_create_impersonation_session_logs.rb
│   │   ├── 20241017204250_add_accounts_indexes.rb
│   │   ├── 20241018201653_add_account_mode.rb
│   │   ├── 20241022170439_create_stock_exchanges.rb
│   │   ├── 20241022192319_fix_user_role_column_type.rb
│   │   ├── 20241022221544_add_onboarding_fields.rb
│   │   ├── 20241023195438_add_stock_exchange_reference.rb
│   │   ├── 20241024142537_add_subscription_timestamp_to_session.rb
│   │   ├── 20241025174650_add_mic_to_securities.rb
│   │   ├── 20241025182612_add_search_vector_to_securities.rb
│   │   ├── 20241029125406_add_reference_to_security_prices.rb
│   │   ├── 20241029184115_remove_prices_missing_issue.rb
│   │   ├── 20241029234028_remove_search_vector.rb
│   │   ├── 20241030121302_fix_not_null_stock_exchange_data.rb
│   │   ├── 20241030151105_remove_account_mode.rb
│   │   ├── 20241030222235_create_invitations.rb
│   │   ├── 20241106193743_add_plaid_domain.rb
│   │   ├── 20241108150422_add_unique_email_index_to_invitations.rb
│   │   ├── 20241114164118_add_products_to_plaid_item.rb
│   │   ├── 20241122183828_change_loan_interest_rate_precision.rb.rb
│   │   ├── 20241126211249_add_logo_url_to_security.rb
│   │   ├── 20241204235400_add_balance_components.rb
│   │   ├── 20241207002408_add_family_timezone.rb
│   │   ├── 20241212141453_add_merchant_logo.rb
│   │   ├── 20241217141716_add_enrichment_setting.rb
│   │   ├── 20241218132503_add_enriched_name_field.rb
│   │   ├── 20241219151540_add_region_to_plaid_item.rb
│   │   ├── 20241219174803_add_parent_category.rb
│   │   ├── 20241227142333_add_error_trace_to_syncs.rb
│   │   ├── 20241231140709_reverse_transfer_relations.rb
│   │   ├── 20250108182147_create_budgets.rb
│   │   ├── 20250108200055_create_budget_categories.rb
│   │   ├── 20250110012347_category_classification.rb
│   │   ├── 20250120210449_align_transfer_cascade_behavior.rb
│   │   ├── 20250124224316_create_rejected_transfers.rb
│   │   ├── 20250128203303_store_transaction_filters_in_session.rb
│   │   ├── 20250130191533_add_email_confirmation_to_users.rb
│   │   ├── 20250130214500_remove_email_confirmation_sent_at_from_users.rb
│   │   ├── 20250131171943_remove_email_confirmation_token_from_users.rb
│   │   ├── 20250206003115_remove_import_status_enum.rb
│   │   ├── 20250206141452_add_institution_details_to_plaid_items.rb
│   │   ├── 20250206151825_add_mfa_fields_to_users.rb
│   │   ├── 20250206204404_add_constraints_to_account_holdings.rb
│   │   ├── 20250207011850_add_exchange_operating_mic_to_securities.rb
│   │   ├── 20250207014022_add_number_format_to_imports.rb
│   │   ├── 20250207194638_adjust_securities_indexes.rb
│   │   ├── 20250211161238_make_ticker_not_null.rb
│   │   ├── 20250212163624_add_status_to_plaid_items.rb
│   │   ├── 20250212213301_add_user_sidebar_preference.rb
│   │   ├── 20250220153958_update_imports_for_operating_mic_v2.rb
│   │   ├── 20250220200735_add_default_lucide_icon_to_categories.rb
│   │   ├── 20250303141007_add_optional_account_for_import.rb
│   │   ├── 20250304140435_add_default_period_to_users.rb
│   │   ├── 20250304200956_add_signage_type_to_imports.rb
│   │   ├── 20250315191233_remove_ticker_from_security_prices.rb
│   │   ├── 20250316103753_remove_issues.rb
│   │   ├── 20250316122019_security_price_unique_index.rb
│   │   ├── 20250318212559_remove_good_job.rb
│   │   ├── 20250319145426_remove_self_host_upgrades.rb
│   │   ├── 20250319212839_create_ai_chats.rb
│   │   ├── 20250405210514_add_initial_balance_field.rb
│   │   ├── 20250410144939_add_theme_to_users.rb
│   │   ├── 20250411140604_add_parent_syncs.rb
│   │   ├── 20250413141446_table_renames.rb
│   │   ├── 20250416235317_add_rules_engine.rb
│   │   ├── 20250416235420_add_data_enrichments.rb
│   │   ├── 20250416235758_merchant_and_category_enrichment.rb
│   │   ├── 20250429021255_add_name_to_rules.rb
│   │   ├── 20250501172430_add_user_goals.rb
│   │   ├── 20250502164951_create_subscriptions.rb
│   │   ├── 20250509182903_dynamic_last_synced.rb
│   │   ├── 20250512171654_update_sync_timestamps.rb
│   │   ├── 20250513122703_add_uniqueness_to_subscriptions.rb
│   │   ├── 20250514214242_add_metadata_to_session.rb
│   │   ├── 20250516180846_remove_stock_exchanges.rb
│   │   ├── 20250518181619_add_auto_sync_preference_to_family.rb
│   │   ├── 20250521112347_add_security_resolver_fields.rb
│   │   ├── 20250522201031_stronger_unique_index_on_security.rb
│   │   ├── 20250523131455_add_raw_payloads_to_plaid_accounts.rb
│   │   ├── 20250605031616_add_index_to_sync_status.rb
│   │   ├── 20250610181219_add_sync_timestamps_to_family.rb
│   │   ├── 20250612150749_create_doorkeeper_tables.rb
│   │   ├── 20250612154522_fix_doorkeeper_resource_owner_id_for_uuid.rb
│   │   ├── 20250613002027_create_api_keys.rb
│   │   ├── 20250613100842_add_display_key_to_api_keys.rb
│   │   ├── 20250613101036_remove_key_from_api_keys.rb
│   │   ├── 20250613101051_remove_key_index_from_api_keys.rb
│   │   ├── 20250613152743_fix_doorkeeper_access_grants_resource_owner_id_for_uuid.rb
│   │   ├── 20250616183654_add_kind_to_transactions.rb
│   │   ├── 20250618104425_add_source_to_api_keys.rb
│   │   ├── 20250618110104_create_mobile_devices.rb
│   │   ├── 20250618110736_add_owner_to_oauth_applications.rb
│   │   ├── 20250618120703_add_oauth_application_to_mobile_devices.rb
│   │   ├── 20250620204550_update_excluded_transactions_to_one_time.rb
│   │   ├── 20250623162207_update_outdated_timezones.rb
│   │   ├── 20250701161640_add_account_status.rb
│   │   ├── 20250702173231_fix_mobile_devices_unique_constraint.rb
│   │   ├── 20250710225721_add_valuation_kind.rb
│   │   ├── 20250718120146_add_indexes_to_core_models.rb
│   │   ├── 20250719121103_add_start_end_columns_to_balances.rb
│   │   └── 20250724115507_create_family_exports.rb
│   ├── schema.rb
│   ├── seeds/
│   │   ├── .keep
│   │   └── oauth_applications.rb
│   └── seeds.rb
├── docs/
│   ├── api/
│   │   └── chats.md
│   └── hosting/
│       └── docker.md
├── lib/
│   ├── assets/
│   │   └── .keep
│   ├── money/
│   │   ├── arithmetic.rb
│   │   ├── currency.rb
│   │   └── formatting.rb
│   ├── money.rb
│   ├── semver.rb
│   └── tasks/
│       ├── benchmarking.rake
│       ├── data_migration.rake
│       ├── demo_data.rake
│       ├── invites.rake
│       ├── securities.rake
│       └── stripe.rake
├── log/
│   └── .keep
├── package.json
├── perf.rake
├── public/
│   ├── 404.html
│   ├── 406-unsupported-browser.html
│   ├── 422.html
│   ├── 426.html
│   ├── 500.html
│   ├── browserconfig.xml
│   ├── robots.txt
│   └── site.webmanifest
├── storage/
│   └── .keep
├── test/
│   ├── application_system_test_case.rb
│   ├── channels/
│   │   └── application_cable/
│   │       └── connection_test.rb
│   ├── components/
│   │   └── previews/
│   │       ├── alert_component_preview.rb
│   │       ├── button_component_preview.rb
│   │       ├── dialog_component_preview.rb
│   │       ├── disclosure_component_preview.rb
│   │       ├── filled_icon_component_preview.rb
│   │       ├── link_component_preview.rb
│   │       ├── menu_component_preview.rb
│   │       ├── tabs_component_preview/
│   │       │   ├── custom.html.erb
│   │       │   └── default.html.erb
│   │       ├── tabs_component_preview.rb
│   │       ├── toggle_component_preview.rb
│   │       └── tooltip_component_preview.rb
│   ├── controllers/
│   │   ├── accountable_sparklines_controller_test.rb
│   │   ├── accounts_controller_test.rb
│   │   ├── api/
│   │   │   └── v1/
│   │   │       ├── accounts_controller_test.rb
│   │   │       ├── auth_controller_test.rb
│   │   │       ├── base_controller_test.rb
│   │   │       ├── chats_controller_test.rb
│   │   │       ├── messages_controller_test.rb
│   │   │       ├── transactions_controller_test.rb
│   │   │       └── usage_controller_test.rb
│   │   ├── categories_controller_test.rb
│   │   ├── category/
│   │   │   └── deletions_controller_test.rb
│   │   ├── chats_controller_test.rb
│   │   ├── concerns/
│   │   │   ├── auto_sync_test.rb
│   │   │   └── onboardable_test.rb
│   │   ├── credit_cards_controller_test.rb
│   │   ├── cryptos_controller_test.rb
│   │   ├── currencies_controller_test.rb
│   │   ├── current_sessions_controller_test.rb
│   │   ├── depositories_controller_test.rb
│   │   ├── email_confirmations_controller_test.rb
│   │   ├── family_exports_controller_test.rb
│   │   ├── family_merchants_controller_test.rb
│   │   ├── holdings_controller_test.rb
│   │   ├── impersonation_sessions_controller_test.rb
│   │   ├── import/
│   │   │   ├── cleans_controller_test.rb
│   │   │   ├── configurations_controller_test.rb
│   │   │   ├── confirms_controller_test.rb
│   │   │   ├── mappings_controller_test.rb
│   │   │   ├── rows_controller_test.rb
│   │   │   └── uploads_controller_test.rb
│   │   ├── imports_controller_test.rb
│   │   ├── investments_controller_test.rb
│   │   ├── invitations_controller_test.rb
│   │   ├── invite_codes_controller_test.rb
│   │   ├── loans_controller_test.rb
│   │   ├── messages_controller_test.rb
│   │   ├── mfa_controller_test.rb
│   │   ├── onboardings_controller_test.rb
│   │   ├── other_assets_controller_test.rb
│   │   ├── other_liabilities_controller_test.rb
│   │   ├── pages_controller_test.rb
│   │   ├── password_resets_controller_test.rb
│   │   ├── plaid_items_controller_test.rb
│   │   ├── properties_controller_test.rb
│   │   ├── registrations_controller_test.rb
│   │   ├── rules_controller_test.rb
│   │   ├── sessions_controller_test.rb
│   │   ├── settings/
│   │   │   ├── api_keys_controller_test.rb
│   │   │   ├── billings_controller_test.rb
│   │   │   ├── hostings_controller_test.rb
│   │   │   ├── preferences_controller_test.rb
│   │   │   └── profiles_controller_test.rb
│   │   ├── subscriptions_controller_test.rb
│   │   ├── tag/
│   │   │   └── deletions_controller_test.rb
│   │   ├── tags_controller_test.rb
│   │   ├── trades_controller_test.rb
│   │   ├── transactions/
│   │   │   ├── bulk_deletions_controller_test.rb
│   │   │   └── bulk_updates_controller_test.rb
│   │   ├── transactions_controller_test.rb
│   │   ├── transfer_matches_controller_test.rb
│   │   ├── transfers_controller_test.rb
│   │   ├── users_controller_test.rb
│   │   ├── valuations_controller_test.rb
│   │   ├── vehicles_controller_test.rb
│   │   └── webhooks_controller_test.rb
│   ├── data_migrations/
│   │   └── balance_component_migrator_test.rb
│   ├── fixtures/
│   │   ├── accounts.yml
│   │   ├── active_storage/
│   │   │   ├── attachments.yml
│   │   │   └── blobs.yml
│   │   ├── addresses.yml
│   │   ├── api_keys.yml
│   │   ├── balances.yml
│   │   ├── budgets.yml
│   │   ├── categories.yml
│   │   ├── chats.yml
│   │   ├── credit_cards.yml
│   │   ├── cryptos.yml
│   │   ├── depositories.yml
│   │   ├── entries.yml
│   │   ├── exchange_rates.yml
│   │   ├── families.yml
│   │   ├── family_exports.yml
│   │   ├── files/
│   │   │   └── imports/
│   │   │       ├── accounts.csv
│   │   │       ├── invalid.csv
│   │   │       ├── mint.csv
│   │   │       ├── trades.csv
│   │   │       ├── transactions.csv
│   │   │       └── valid.csv
│   │   ├── holdings.yml
│   │   ├── impersonation_session_logs.yml
│   │   ├── impersonation_sessions.yml
│   │   ├── import/
│   │   │   ├── mappings.yml
│   │   │   └── rows.yml
│   │   ├── imports.yml
│   │   ├── investments.yml
│   │   ├── invitations.yml
│   │   ├── loans.yml
│   │   ├── merchants.yml
│   │   ├── messages.yml
│   │   ├── mobile_devices.yml
│   │   ├── other_assets.yml
│   │   ├── other_liabilities.yml
│   │   ├── plaid_accounts.yml
│   │   ├── plaid_items.yml
│   │   ├── properties.yml
│   │   ├── rule/
│   │   │   ├── actions.yml
│   │   │   └── conditions.yml
│   │   ├── rules.yml
│   │   ├── securities.yml
│   │   ├── security/
│   │   │   └── prices.yml
│   │   ├── sessions.yml
│   │   ├── subscriptions.yml
│   │   ├── syncs.yml
│   │   ├── taggings.yml
│   │   ├── tags.yml
│   │   ├── tool_calls.yml
│   │   ├── trades.yml
│   │   ├── transactions.yml
│   │   ├── transfers.yml
│   │   ├── users.yml
│   │   ├── valuations.yml
│   │   └── vehicles.yml
│   ├── helpers/
│   │   ├── .keep
│   │   └── application_helper_test.rb
│   ├── i18n_test.rb
│   ├── integration/
│   │   ├── oauth_basic_test.rb
│   │   ├── oauth_mobile_test.rb
│   │   └── rack_attack_test.rb
│   ├── interfaces/
│   │   ├── accountable_resource_interface_test.rb
│   │   ├── entryable_resource_interface_test.rb
│   │   ├── exchange_rate_provider_interface_test.rb
│   │   ├── import_interface_test.rb
│   │   ├── llm_interface_test.rb
│   │   ├── security_provider_interface_test.rb
│   │   └── syncable_interface_test.rb
│   ├── jobs/
│   │   ├── family_data_export_job_test.rb
│   │   ├── import_job_test.rb
│   │   ├── stripe_event_handler_job_test.rb
│   │   └── sync_job_test.rb
│   ├── lib/
│   │   ├── money/
│   │   │   └── currency_test.rb
│   │   └── money_test.rb
│   ├── mailers/
│   │   ├── email_confirmation_mailer_test.rb
│   │   ├── password_mailer_test.rb
│   │   └── previews/
│   │       ├── email_confirmation_mailer_preview.rb
│   │       └── password_mailer_preview.rb
│   ├── models/
│   │   ├── account/
│   │   │   ├── activity_feed_data_test.rb
│   │   │   ├── chartable_test.rb
│   │   │   ├── current_balance_manager_test.rb
│   │   │   ├── entry_test.rb
│   │   │   ├── market_data_importer_test.rb
│   │   │   ├── opening_balance_manager_test.rb
│   │   │   ├── reconciliation_manager_test.rb
│   │   │   └── transaction_test.rb
│   │   ├── account_import_test.rb
│   │   ├── account_test.rb
│   │   ├── address_test.rb
│   │   ├── api_key_test.rb
│   │   ├── assistant_message_test.rb
│   │   ├── assistant_test.rb
│   │   ├── balance/
│   │   │   ├── chart_series_builder_test.rb
│   │   │   ├── forward_calculator_test.rb
│   │   │   ├── materializer_test.rb
│   │   │   └── reverse_calculator_test.rb
│   │   ├── balance_sheet_test.rb
│   │   ├── budget_test.rb
│   │   ├── category_test.rb
│   │   ├── chat_test.rb
│   │   ├── concerns/
│   │   │   └── enrichable_test.rb
│   │   ├── current_test.rb
│   │   ├── developer_message_test.rb
│   │   ├── exchange_rate/
│   │   │   └── importer_test.rb
│   │   ├── exchange_rate_test.rb
│   │   ├── family/
│   │   │   ├── auto_categorizer_test.rb
│   │   │   ├── auto_merchant_detector_test.rb
│   │   │   ├── auto_transfer_matchable_test.rb
│   │   │   ├── data_exporter_test.rb
│   │   │   ├── subscribeable_test.rb
│   │   │   └── syncer_test.rb
│   │   ├── family_export_test.rb
│   │   ├── family_test.rb
│   │   ├── holding/
│   │   │   ├── forward_calculator_test.rb
│   │   │   ├── materializer_test.rb
│   │   │   ├── portfolio_cache_test.rb
│   │   │   ├── portfolio_snapshot_test.rb
│   │   │   └── reverse_calculator_test.rb
│   │   ├── holding_test.rb
│   │   ├── impersonation_session_test.rb
│   │   ├── income_statement_test.rb
│   │   ├── invite_code_test.rb
│   │   ├── loan_test.rb
│   │   ├── market_data_importer_test.rb
│   │   ├── mobile_device_test.rb
│   │   ├── period_test.rb
│   │   ├── plaid_account/
│   │   │   ├── importer_test.rb
│   │   │   ├── investments/
│   │   │   │   ├── balance_calculator_test.rb
│   │   │   │   ├── holdings_processor_test.rb
│   │   │   │   ├── security_resolver_test.rb
│   │   │   │   └── transactions_processor_test.rb
│   │   │   ├── liabilities/
│   │   │   │   ├── credit_processor_test.rb
│   │   │   │   ├── mortgage_processor_test.rb
│   │   │   │   └── student_loan_processor_test.rb
│   │   │   ├── processor_test.rb
│   │   │   ├── transactions/
│   │   │   │   ├── category_matcher_test.rb
│   │   │   │   └── processor_test.rb
│   │   │   └── type_mappable_test.rb
│   │   ├── plaid_entry/
│   │   │   └── processor_test.rb
│   │   ├── plaid_item/
│   │   │   ├── accounts_snapshot_test.rb
│   │   │   └── importer_test.rb
│   │   ├── plaid_item_test.rb
│   │   ├── provider/
│   │   │   ├── openai_test.rb
│   │   │   ├── plaid_test.rb
│   │   │   ├── registry_test.rb
│   │   │   ├── stripe/
│   │   │   │   └── subscription_event_processor_test.rb
│   │   │   ├── stripe_test.rb
│   │   │   └── synth_test.rb
│   │   ├── provider_test.rb
│   │   ├── rule/
│   │   │   ├── action_test.rb
│   │   │   └── condition_test.rb
│   │   ├── rule_test.rb
│   │   ├── security/
│   │   │   ├── health_checker_test.rb
│   │   │   ├── price/
│   │   │   │   └── importer_test.rb
│   │   │   ├── price_test.rb
│   │   │   └── resolver_test.rb
│   │   ├── security_test.rb
│   │   ├── subscription_test.rb
│   │   ├── sync_test.rb
│   │   ├── tag_test.rb
│   │   ├── trade_import_test.rb
│   │   ├── trade_test.rb
│   │   ├── transaction/
│   │   │   └── search_test.rb
│   │   ├── transaction_import_test.rb
│   │   ├── transfer/
│   │   │   └── creator_test.rb
│   │   ├── transfer_test.rb
│   │   ├── trend_test.rb
│   │   ├── user_message_test.rb
│   │   ├── user_test.rb
│   │   └── valuation/
│   │       └── name_test.rb
│   ├── services/
│   │   ├── api_rate_limiter_test.rb
│   │   └── noop_api_rate_limiter_test.rb
│   ├── support/
│   │   ├── balance_test_helper.rb
│   │   ├── entries_test_helper.rb
│   │   ├── ledger_testing_helper.rb
│   │   ├── provider_test_helper.rb
│   │   └── securities_test_helper.rb
│   ├── system/
│   │   ├── accounts_test.rb
│   │   ├── categories_test.rb
│   │   ├── chats_test.rb
│   │   ├── imports_test.rb
│   │   ├── onboardings_test.rb
│   │   ├── settings/
│   │   │   └── api_keys_test.rb
│   │   ├── settings_test.rb
│   │   ├── trades_test.rb
│   │   ├── transactions_test.rb
│   │   └── transfers_test.rb
│   ├── test_helper.rb
│   └── vcr_cassettes/
│       ├── git_repository_provider/
│       │   └── fetch_latest_release_notes.yml
│       ├── openai/
│       │   ├── auto_categorize.yml
│       │   ├── auto_detect_merchants.yml
│       │   └── chat/
│       │       ├── basic_response.yml
│       │       ├── basic_streaming_response.yml
│       │       ├── error.yml
│       │       ├── function_calls.yml
│       │       └── streaming_function_calls.yml
│       ├── plaid/
│       │   ├── access_token.yml
│       │   ├── exchange_public_token.yml
│       │   ├── get_item.yml
│       │   ├── get_item_accounts.yml
│       │   ├── get_item_investments.yml
│       │   ├── get_item_liabilities.yml
│       │   └── link_token.yml
│       ├── stripe/
│       │   ├── checkout_session.yml
│       │   └── create_checkout_session.yml
│       └── synth/
│           ├── exchange_rate.yml
│           ├── exchange_rates.yml
│           ├── health.yml
│           ├── security_info.yml
│           ├── security_price.yml
│           ├── security_prices.yml
│           ├── security_search.yml
│           └── usage.yml
├── tmp/
│   └── .keep
└── vendor/
    ├── .keep
    └── javascript/
        ├── .keep
        ├── @floating-ui--core.js
        ├── @floating-ui--dom.js
        ├── @floating-ui--utils--dom.js
        ├── @floating-ui--utils.js
        ├── @github--hotkey.js
        ├── @simonwep--pickr.js
        ├── d3-array.js
        ├── d3-axis.js
        ├── d3-brush.js
        ├── d3-chord.js
        ├── d3-color.js
        ├── d3-contour.js
        ├── d3-delaunay.js
        ├── d3-dispatch.js
        ├── d3-drag.js
        ├── d3-dsv.js
        ├── d3-ease.js
        ├── d3-fetch.js
        ├── d3-force.js
        ├── d3-format.js
        ├── d3-geo.js
        ├── d3-hierarchy.js
        ├── d3-interpolate.js
        ├── d3-path.js
        ├── d3-polygon.js
        ├── d3-quadtree.js
        ├── d3-random.js
        ├── d3-sankey.js
        ├── d3-scale-chromatic.js
        ├── d3-scale.js
        ├── d3-selection.js
        ├── d3-shape.js
        ├── d3-time-format.js
        ├── d3-time.js
        ├── d3-timer.js
        ├── d3-transition.js
        ├── d3-zoom.js
        ├── d3.js
        ├── delaunator.js
        ├── internmap.js
        └── robust-predicates.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .cursor/rules/cursor_rules.mdc
================================================
---
description: Guidelines for creating and maintaining Cursor rules to ensure consistency and effectiveness.
globs: .cursor/rules/*.mdc
alwaysApply: true
---

- **Required Rule Structure:**
  ```markdown
  ---
  description: Clear, one-line description of what the rule enforces
  globs: path/to/files/*.ext, other/path/**/*
  alwaysApply: boolean
  ---

  - **Main Points in Bold**
    - Sub-points with details
    - Examples and explanations
  ```

- **File References:**
  - Use `[filename](mdc:path/to/file)` ([filename](mdc:filename)) to reference files
  - Example: [prisma.mdc](mdc:.cursor/rules/prisma.mdc) for rule references
  - Example: [schema.prisma](mdc:prisma/schema.prisma) for code references

- **Code Examples:**
  - Use language-specific code blocks
  ```typescript
  // ✅ DO: Show good examples
  const goodExample = true;
  
  // ❌ DON'T: Show anti-patterns
  const badExample = false;
  ```

- **Rule Content Guidelines:**
  - Start with high-level overview
  - Include specific, actionable requirements
  - Show examples of correct implementation
  - Reference existing code when possible
  - Keep rules DRY by referencing other rules

- **Rule Maintenance:**
  - Update rules when new patterns emerge
  - Add examples from actual codebase
  - Remove outdated patterns
  - Cross-reference related rules

- **Best Practices:**
  - Use bullet points for clarity
  - Keep descriptions concise
  - Include both DO and DON'T examples
  - Reference actual code over theoretical examples
  - Use consistent formatting across rules 

================================================
FILE: .cursor/rules/general-rules.mdc
================================================
---
description: Miscellaneous rules to get the AI to behave
globs: *
alwaysApply: true
---
# General rules for AI 

- Use `Current.user` for the current user. Do NOT use `current_user`.
- Use `Current.family` for the current family. Do NOT use `current_family`.
- Prior to generating any code, carefully read the project conventions and guidelines
  - Read [project-design.mdc](mdc:.cursor/rules/project-design.mdc) to understand the codebase
  - Read [project-conventions.mdc](mdc:.cursor/rules/project-conventions.mdc) to understand _how_ to write code for the codebase
  - Read [ui-ux-design-guidelines.mdc](mdc:.cursor/rules/ui-ux-design-guidelines.mdc) to understand how to implement frontend code specifically
- Ignore i18n methods and files. Hardcode strings in English for now to optimize speed of development.

## Prohibited actions

- Do not run `rails server` in your responses.
- Do not run `touch tmp/restart.txt`
- Do not run `rails credentials`
- Do not automatically run migrations

================================================
FILE: .cursor/rules/project-conventions.mdc
================================================
---
description: 
globs: 
alwaysApply: true
---
This rule serves as high-level documentation for how you should write code for the Maybe codebase. 

## Project Tech Stack

- Web framework: Ruby on Rails
  - Minitest + fixtures for testing
  - Propshaft for asset pipeline
  - Hotwire Turbo/Stimulus for SPA-like UI/UX
  - TailwindCSS for styles
  - Lucide Icons for icons
  - OpenAI for AI chat
- Database: PostgreSQL
- Jobs: Sidekiq + Redis
- External
  - Payments: Stripe
  - User bank data syncing: Plaid 
  - Market data: Synth (our custom API)

## Project conventions

These conventions should be used when writing code for Maybe.

### Convention 1: Minimize dependencies, vanilla Rails is plenty

Dependencies are a natural part of building software, but we aim to minimize them when possible to keep this open-source codebase easy to understand, maintain, and contribute to.

- Push Rails to its limits before adding new dependencies
- When a new dependency is added, there must be a strong technical or business reason to add it
- When adding dependencies, you should favor old and reliable over new and flashy 

### Convention 2: Leverage POROs and concerns over "service objects"

This codebase adopts a "skinny controller, fat models" convention.  Furthermore, we put almost _everything_ directly in the `app/models/` folder and avoid separate folders for business logic such as `app/services/`.

- Organize large pieces of business logic into Rails concerns and POROs (Plain ole' Ruby Objects)
- While a Rails concern _may_ offer shared functionality (i.e. "duck types"), it can also be a "one-off" concern that is only included in one place for better organization and readability.
- When concerns are used for code organization, they should be organized around the "traits" of a model; not for simply moving code to another spot in the codebase.
- When possible, models should answer questions about themselves—for example, we might have a method, `account.balance_series` that returns a time-series of the account's most recent balances.  We prefer this over something more service-like such as `AccountSeries.new(account).call`.

### Convention 3: Leverage Hotwire, write semantic HTML, CSS, and JS, prefer server-side solutions

- Native HTML is always preferred over JS-based components
  - Example 1: Use `<dialog>` element for modals instead of creating a custom component
  - Example 2: Use `<details><summary>...</summary></details>` for disclosures rather than custom components
- Leverage Turbo frames to break up the page over JS-driven client-side solutions
  - Example 1: A good example of turbo frame usage is in [application.html.erb](mdc:app/views/layouts/application.html.erb) where we load [chats_controller.rb](mdc:app/controllers/chats_controller.rb) actions in a turbo frame in the global layout
- Leverage query params in the URL for state over local storage and sessions.  If absolutely necessary, utilize the DB for persistent state.
- Use Turbo streams to enhance functionality, but do not solely depend on it
- Format currencies, numbers, dates, and other values server-side, then pass to Stimulus controllers for display only
- Keep client-side code for where it truly shines.  For example, @bulk_select_controller.js is a case where server-side solutions would degrade the user experience significantly.  When bulk-selecting entries, client-side solutions are the way to go and Stimulus provides the right toolset to achieve this.
- Always use the `icon` helper in [application_helper.rb](mdc:app/helpers/application_helper.rb) for icons.  NEVER use `lucide_icon` helper directly.

The Hotwire suite (Turbo/Stimulus) works very well with these native elements and we optimize for this.

### Convention 4: Optimize for simplicitly and clarity

All code should maximize readability and simplicity.

- Prioritize good OOP domain design over performance
- Only focus on performance for critical and global areas of the codebase; otherwise, don't sweat the small stuff.
  - Example 1: be mindful of loading large data payloads in global layouts
  - Example 2: Avoid N+1 queries

### Convention 5: Use ActiveRecord for complex validations, DB for simple ones, keep business logic out of DB

- Enforce `null` checks, unique indexes, and other simple validations in the DB
- ActiveRecord validations _may_ mirror the DB level ones, but not 100% necessary.  These are for convenience when error handling in forms.  Always prefer client-side form validation when possible.
- Complex validations and business logic should remain in ActiveRecord


================================================
FILE: .cursor/rules/project-design.mdc
================================================
---
description: This rule explains the system architecture and data flow of the Rails app
globs: *
alwaysApply: true
---

This file outlines how the codebase is structured and how data flows through the app.

This is a personal finance application built in Ruby on Rails.  The primary domain entities for this app are outlined below.  For an authoritative overview of the relationships, [schema.rb](mdc:db/schema.rb) is the source of truth.

## App Modes

The Maybe app runs in two distinct "modes", dictated by `Rails.application.config.app_mode`, which can be `managed` or `self_hosted`.

- "Managed" - in managed mode, the Maybe team operates and manages servers for users
- "Self Hosted" - in self hosted mode, users host the Maybe app on their own infrastructure, typically through Docker Compose.  We have an example [docker-compose.example.yml](mdc:docker-compose.example.yml) file that runs [Dockerfile](mdc:Dockerfile) for this mode.

## Families and Users

- `Family` - all Stripe subscriptions, financial accounts, and the majority of preferences are stored at the [family.rb](mdc:app/models/family.rb) level.
- `User` - all [session.rb](mdc:app/models/session.rb) happen at the [user.rb](mdc:app/models/user.rb) level.  A user belongs to a `Family` and can either be an `admin` or a `member`.  Typically, a `Family` has a single admin, or "head of household" that manages finances while there will be several `member` users who can see the family's finances from varying perspectives.

## Currency Preference

Each `Family` selects a currency preference.  This becomes the "main" currency in which all records are "normalized" to via [exchange_rate.rb](mdc:app/models/exchange_rate.rb) records so that the Maybe app can calculate metrics, historical graphs, and other insights in a single family currency.

## Accounts

The center of the app's domain is the [account.rb](mdc:app/models/account.rb).  This represents a single financial account that has a `balance` and `currency`.  For example, an `Account` could be "Chase Checking", which is a single financial account at Chase Bank.  A user could have multiple accounts at a single institution (i.e. "Chase Checking", "Chase Credit Card", "Chase Savings") or an account could be a standalone account, such as "My Home" (a primary residence).

### Accountables

In the app, [account.rb](mdc:app/models/account.rb) is a Rails "delegated type" with the following subtypes (separate DB tables).  Each account has a `classification` or either `asset` or `liability`.  While the types are a flat hierarchy, below, they have been organized by their classification:

- Asset accountables
  - [depository.rb](mdc:app/models/depository.rb) - a typical "bank account" such as a savings or checking account
  - [investment.rb](mdc:app/models/investment.rb) - an account that has "holdings" such as a brokerage, 401k, etc.
  - [crypto.rb](mdc:app/models/crypto.rb) - an account that tracks the value of one or more crypto holdings
  - [property.rb](mdc:app/models/property.rb) - an account that tracks the value of a physical property such as a house or rental property
  - [vehicle.rb](mdc:app/models/vehicle.rb) - an account that tracks the value of a vehicle
  - [other_asset.rb](mdc:app/models/other_asset.rb) - an asset that cannot be classified by the other account types.  For example, "jewelry".
- Liability accountables
  - [credit_card.rb](mdc:app/models/credit_card.rb) - an account that tracks the debt owed on a credit card
  - [loan.rb](mdc:app/models/loan.rb) - an account that tracks the debt owed on a loan (i.e. mortgage, student loan)
  - [other_liability.rb](mdc:app/models/other_liability.rb) - a liability that cannot be classified by the other account types.  For example, "IOU to a friend"

### Account Balances

An account [balance.rb](mdc:app/models/account/balance.rb) represents a single balance value for an account on a specific `date`.  A series of balance records is generated daily for each account and is how we show a user's historical balance graph.  

- For simple accounts like a "Checking Account", the balance represents the amount of cash in the account for a date.  
- For a more complex account like "Investment Brokerage", the `balance` represents the combination of the "cash balance" + "holdings value".  Each accountable type has different components that make up the "balance", but in all cases, the "balance" represents "How much the account is worth" (when `classification` is `asset`) or "How much is owed on the account" (when `classification` is `liability`)

All balances are calculated daily by [balance_calculator.rb](mdc:app/models/account/balance_calculator.rb).

### Account Holdings

An account [holding.rb](mdc:app/models/holding.rb) applies to [investment.rb](mdc:app/models/investment.rb) type accounts and represents a `qty` of a certain [security.rb](mdc:app/models/security.rb) at a specific `price` on a specific `date`.

For investment accounts with holdings, [base_calculator.rb](mdc:app/models/holding/base_calculator.rb) is used to calculate the daily historical holding quantities and prices, which are then rolled up into a final "Balance" for the account in [base_calculator.rb](mdc:app/models/account/balance/base_calculator.rb).

### Account Entries

An account [entry.rb](mdc:app/models/entry.rb) is also a Rails "delegated type".  `Entry` represents any record that _modifies_ an `Account` [balance.rb](mdc:app/models/account/balance.rb) and/or [holding.rb](mdc:app/models/holding.rb).  Therefore, every entry must have a `date`, `amount`, and `currency`.

The `amount` of an [entry.rb](mdc:app/models/entry.rb) is a signed value.  A _negative_ amount is an "inflow" of money to that account.  A _positive_ value is an "outflow" of money from that account.  For example:

- A negative amount for a credit card account represents a "payment" to that account, which _reduces_ its balance (since it is a `liability`)
- A negative amount for a checking account represents an "income" to that account, which _increases_ its balance (since it is an `asset`)
- A negative amount for an investment/brokerage trade represents a "sell" transaction, which _increases_ the cash balance of the account 

There are 3 entry types, defined as [entryable.rb](mdc:app/models/entryable.rb) records: 

- `Valuation` - an account [valuation.rb](mdc:app/models/valuation.rb) is an entry that says, "here is the value of this account on this date".  It is an absolute measure of an account value / debt.  If there is an `Valuation` of 5,000 for today's date, that means that the account balance will be 5,000 today.
- `Transaction` - an account [transaction.rb](mdc:app/models/transaction.rb) is an entry that alters the account balance by the `amount`.  This is the most common type of entry and can be thought of as an "income" or "expense".  
- `Trade` - an account [trade.rb](mdc:app/models/trade.rb) is an entry that only applies to an investment account.  This represents a "buy" or "sell" of a holding and has a `qty` and `price`.

### Account Transfers

A [transfer.rb](mdc:app/models/transfer.rb) represents a movement of money between two accounts.  A transfer has an inflow [transaction.rb](mdc:app/models/transaction.rb) and an outflow [transaction.rb](mdc:app/models/transaction.rb).  The Maybe system auto-matches transfers based on the following criteria:

- Must be from different accounts
- Must be within 4 days of each other
- Must be the same currency
- Must be opposite values

There are two primary forms of a transfer:

- Regular transfer - a normal movement of money between two accounts.  For example, "Transfer $500 from Checking account to Brokerage account". 
- Debt payment - a special form of transfer where the _receiver_ of funds is a [loan.rb](mdc:app/models/loan.rb) type account.  

Regular transfers are typically _excluded_ from income and expense calculations while a debt payment is considered an "expense".

## Plaid Items

A [plaid_item.rb](mdc:app/models/plaid_item.rb) represents a "connection" maintained by our external data provider, Plaid in the "hosted" mode of the app.  An "Item" has 1 or more [plaid_account.rb](mdc:app/models/plaid_account.rb) records, which are each associated 1:1 with an internal Maybe [account.rb](mdc:app/models/account.rb).

All relevant metadata about the item and its underlying accounts are stored on [plaid_item.rb](mdc:app/models/plaid_item.rb) and [plaid_account.rb](mdc:app/models/plaid_account.rb), while the "normalized" data is then stored on internal Maybe domain models.

## "Syncs"

The Maybe app has the concept of a [syncable.rb](mdc:app/models/concerns/syncable.rb), which represents any model which can have its data "synced" in the background.  "Syncables" include:

- `Account` - an account "sync" will sync account holdings, balances, and enhance transaction metadata
- `PlaidItem` - a Plaid Item "sync" fetches data from Plaid APIs, normalizes that data, stores it on internal Maybe models, and then finally performs an "Account sync" for each of the underlying accounts created from the Plaid Item.
- `Family` - a Family "sync" loops through the family's Plaid Items and individual Accounts and "syncs" each of them.  A family is synced once per day, automatically through [auto_sync.rb](mdc:app/controllers/concerns/auto_sync.rb).

Each "sync" creates a [sync.rb](mdc:app/models/sync.rb) record in the database, which keeps track of the status of the sync, any errors that it encounters, and acts as an "audit table" for synced data.

Below are brief descriptions of each type of sync in more detail.

### Account Syncs

The most important type of sync is the account sync.  It is orchestrated by the account's `sync_data` method, which performs a few important tasks:

- Auto-matches transfer records for the account
- Calculates daily [balance.rb](mdc:app/models/account/balance.rb) records for the account from `account.start_date` to `Date.current` using [base_calculator.rb](mdc:app/models/account/balance/base_calculator.rb)
  - Balances are dependent on the calculation of [holding.rb](mdc:app/models/holding.rb), which uses [base_calculator.rb](mdc:app/models/account/holding/base_calculator.rb) 
- Enriches transaction data if enabled by user

An account sync happens every time an [entry.rb](mdc:app/models/entry.rb) is updated.

### Plaid Item Syncs

A Plaid Item sync is an ETL (extract, transform, load) operation:

1. [plaid_item.rb](mdc:app/models/plaid_item.rb) fetches data from the external Plaid API
2. [plaid_item.rb](mdc:app/models/plaid_item.rb) creates and loads this data to [plaid_account.rb](mdc:app/models/plaid_account.rb) records
3. [plaid_item.rb](mdc:app/models/plaid_item.rb) and [plaid_account.rb](mdc:app/models/plaid_account.rb) transform and load data to [account.rb](mdc:app/models/account.rb) and [entry.rb](mdc:app/models/entry.rb), the internal Maybe representations of the data.

### Family Syncs

A family sync happens once daily via [auto_sync.rb](mdc:app/controllers/concerns/auto_sync.rb).  A family sync is an "orchestrator" of Account and Plaid Item syncs.

## Data Providers

The Maybe app utilizes several 3rd party data services to calculate historical account balances, enrich data, and more.  Since the app can be run in both "hosted" and "self hosted" mode, this means that data providers are _optional_ for self hosted users and must be configured.

Because of this optionality, data providers must be configured at _runtime_ through [registry.rb](mdc:app/models/provider/registry.rb) utilizing [setting.rb](mdc:app/models/setting.rb) for runtime parameters like API keys:

There are two types of 3rd party data in the Maybe app:

1. "Concept" data
2. One-off data

### "Concept" data

Since the app is self hostable, users may prefer using different providers for generic data like exchange rates and security prices.  When data is generic enough where we can easily swap out different providers, we call it a data "concept".

Each "concept" has an interface defined in the `app/models/provider/concepts` directory.

```
app/models/
  exchange_rate/
    provided.rb # <- Responsible for selecting the concept provider from the registry
  provider.rb # <- Base provider class
  provider/
    registry.rb <- Defines available providers by concept
    concepts/
      exchange_rate.rb <- defines the interface required for the exchange rate concept
    synth.rb # <- Concrete provider implementation
```

### One-off data

For data that does not fit neatly into a "concept", an interface is not required and the concrete provider may implement ad-hoc methods called directly in code.  For example, the [synth.rb](mdc:app/models/provider/synth.rb) provider has a `usage` method that is only applicable to this specific provider.  This should be called directly without any abstractions:

```rb
class SomeModel < Application
  def synth_usage
    Provider::Registry.get_provider(:synth)&.usage
  end
end
```

## "Provided" Concerns

In general, domain models should not be calling [registry.rb](mdc:app/models/provider/registry.rb) directly.  When 3rd party data is required for a domain model, we use the `Provided` concern within that model's namespace.  This concern is primarily responsible for:

- Choosing the provider to use for this "concept"
- Providing convenience methods on the model for accessing data

For example, [exchange_rate.rb](mdc:app/models/exchange_rate.rb) has a [provided.rb](mdc:app/models/exchange_rate/provided.rb) concern with the following convenience methods:

```rb
module ExchangeRate::Provided
  extend ActiveSupport::Concern

  class_methods do
    def provider
      registry = Provider::Registry.for_concept(:exchange_rates)
      registry.get_provider(:synth)
    end

    def find_or_fetch_rate(from:, to:, date: Date.current, cache: true)
      # Implementation 
    end

    def sync_provider_rates(from:, to:, start_date:, end_date: Date.current)
      # Implementation 
    end
  end
end
```

This exposes a generic access pattern where the caller does not care _which_ provider has been chosen for the concept of exchange rates and can get a predictable response:

```rb
def access_patterns_example
  # Call exchange rate provider directly
  ExchangeRate.provider.fetch_exchange_rate(from: "USD", to: "CAD", date: Date.current)

  # Call convenience method
  ExchangeRate.sync_provider_rates(from: "USD", to: "CAD", start_date: 2.days.ago.to_date)
end
```

## Concrete provider implementations

Each 3rd party data provider should have a class under the `Provider::` namespace that inherits from `Provider` and returns `with_provider_response`, which will return a `Provider::ProviderResponse` object:

```rb
class ConcreteProvider < Provider
  def fetch_some_data
    with_provider_response do
      ExampleData.new(
        example: "data"
      )
    end
  end
end
```

The `with_provider_response` automatically catches provider errors, so concrete provider classes should raise when valid data is not possible:

```rb
class ConcreteProvider < Provider
  def fetch_some_data
    with_provider_response do
      data = nil

      # Raise an error if data cannot be returned
      raise ProviderError.new("Could not find the data you need") if data.nil?

      data
    end
  end
end
```


================================================
FILE: .cursor/rules/self_improve.mdc
================================================
---
description: Guidelines for continuously improving Cursor rules based on emerging code patterns and best practices.
globs: **/*
alwaysApply: true
---

- **Rule Improvement Triggers:**
  - New code patterns not covered by existing rules
  - Repeated similar implementations across files
  - Common error patterns that could be prevented
  - New libraries or tools being used consistently
  - Emerging best practices in the codebase

- **Analysis Process:**
  - Compare new code with existing rules
  - Identify patterns that should be standardized
  - Look for references to external documentation
  - Check for consistent error handling patterns
  - Monitor test patterns and coverage

- **Rule Updates:**
  - **Add New Rules When:**
    - A new technology/pattern is used in 3+ files
    - Common bugs could be prevented by a rule
    - Code reviews repeatedly mention the same feedback
    - New security or performance patterns emerge

  - **Modify Existing Rules When:**
    - Better examples exist in the codebase
    - Additional edge cases are discovered
    - Related rules have been updated
    - Implementation details have changed

- **Example Pattern Recognition:**
  ```typescript
  // If you see repeated patterns like:
  const data = await prisma.user.findMany({
    select: { id: true, email: true },
    where: { status: 'ACTIVE' }
  });
  
  // Consider adding to [prisma.mdc](mdc:.cursor/rules/prisma.mdc):
  // - Standard select fields
  // - Common where conditions
  // - Performance optimization patterns
  ```

- **Rule Quality Checks:**
  - Rules should be actionable and specific
  - Examples should come from actual code
  - References should be up to date
  - Patterns should be consistently enforced

- **Continuous Improvement:**
  - Monitor code review comments
  - Track common development questions
  - Update rules after major refactors
  - Add links to relevant documentation
  - Cross-reference related rules

- **Rule Deprecation:**
  - Mark outdated patterns as deprecated
  - Remove rules that no longer apply
  - Update references to deprecated rules
  - Document migration paths for old patterns

- **Documentation Updates:**
  - Keep examples synchronized with code
  - Update references to external docs
  - Maintain links between related rules
  - Document breaking changes
Follow [cursor_rules.mdc](mdc:.cursor/rules/cursor_rules.mdc) for proper rule formatting and structure.


================================================
FILE: .cursor/rules/stimulus_conventions.mdc
================================================
---
description: 
globs: 
alwaysApply: false
---
This rule describes how to write Stimulus controllers.

- **Use declarative actions, not imperative event listeners**
  - Instead of assigning a Stimulus target and binding it to an event listener in the initializer, always write Controllers + ERB views declaratively by using Stimulus actions in ERB to call methods in the Stimulus JS controller.  Below are good vs. bad code.

  BAD code:

  ```js
  // BAD!!!! DO NOT DO THIS!!
  // Imperative - controller does all the work
  export default class extends Controller {
    static targets = ["button", "content"]

    connect() {
      this.buttonTarget.addEventListener("click", this.toggle.bind(this))
    }

    toggle() {
      this.contentTarget.classList.toggle("hidden")
      this.buttonTarget.textContent = this.contentTarget.classList.contains("hidden") ? "Show" : "Hide"
    }
  }
  ```

  GOOD code:

  ```erb
  <!-- Declarative - HTML declares what happens -->

  <div data-controller="toggle">
    <button data-action="click->toggle#toggle" data-toggle-target="button">Show</button>
    <div data-toggle-target="content" class="hidden">Hello World!</div>
  </div>
  ```

  ```js
  // Declarative - controller just responds
  export default class extends Controller {
    static targets = ["button", "content"]

    toggle() {
      this.contentTarget.classList.toggle("hidden")
      this.buttonTarget.textContent = this.contentTarget.classList.contains("hidden") ? "Show" : "Hide"
    }
  }
  ```

- **Keep Stimulus controllers lightweight and simple**
  - Always aim for less than 7 controller targets. Any more is a sign of too much complexity.
  - Use private methods and expose a clear public API

- **Keep Stimulus controllers focused on what they do best**
  - Domain logic does NOT belong in a Stimulus controller
  - Stimulus controllers should aim for a single responsibility, or a group of highly related responsibilities
  - Make good use of Stimulus's callbacks, actions, targets, values, and classes

- **Component controllers should not be used outside the component**
  - If a Stimulus controller is in the app/components directory, it should only be used in its component view. It should not be used anywhere in app/views.



================================================
FILE: .cursor/rules/testing.mdc
================================================
---
description: 
globs: test/**
alwaysApply: false
---
Use this rule to learn how to write tests for the Maybe codebase.

Due to the open-source nature of this project, we have chosen Minitest + Fixtures for testing to maximize familiarity and predictability.

- **General testing rules**
  - Always use Minitest and fixtures for testing, NEVER rspec or factories
  - Keep fixtures to a minimum.  Most models should have 2-3 fixtures maximum that represent the "base cases" for that model.  "Edge cases" should be created on the fly, within the context of the test which it is needed.
  - For tests that require a large number of fixture records to be created, use Rails helpers to help create the records needed for the test, then inline the creation. For example, [entries_test_helper.rb](mdc:test/support/entries_test_helper.rb) provides helpers to easily do this.

- **Write minimal, effective tests**
  - Use system tests sparingly as they increase the time to complete the test suite
  - Only write tests for critical and important code paths
  - Write tests as you go, when required
  - Take a practical approach to testing.  Tests are effective when their presence _significantly increases confidence in the codebase_.

  Below are examples of necessary vs. unnecessary tests:

  ```rb
  # GOOD!!
  # Necessary test - in this case, we're testing critical domain business logic
  test "syncs balances" do
    Holding::Syncer.any_instance.expects(:sync_holdings).returns([]).once

    @account.expects(:start_date).returns(2.days.ago.to_date)

    Balance::ForwardCalculator.any_instance.expects(:calculate).returns(
      [
        Balance.new(date: 1.day.ago.to_date, balance: 1000, cash_balance: 1000, currency: "USD"),
        Balance.new(date: Date.current, balance: 1000, cash_balance: 1000, currency: "USD")
      ]
    )

    assert_difference "@account.balances.count", 2 do
      Balance::Syncer.new(@account, strategy: :forward).sync_balances
    end
  end

  # BAD!!
  # Unnecessary test - in this case, this is simply testing ActiveRecord's functionality
  test "saves balance" do 
    balance_record = Balance.new(balance: 100, currency: "USD")

    assert balance_record.save
  end
  ```

- **Test boundaries correctly**
  - Distinguish between commands and query methods. Test output of query methods; test that commands were called with the correct params. See an example below:

  ```rb
  class ExampleClass
    def do_something
      result = 2 + 2

      CustomEventProcessor.process_result(result)

      result
    end
  end

  class ExampleClass < ActiveSupport::TestCase
    test "boundaries are tested correctly" do 
      result = ExampleClass.new.do_something

      # GOOD - we're only testing that the command was received, not internal implementation details
      # The actual tests for CustomEventProcessor belong in a different test suite!
      CustomEventProcessor.expects(:process_result).with(4).once

      # GOOD - we're testing the implementation of ExampleClass inside its own test suite
      assert_equal 4, result
    end
  end
  ```

  - Never test the implementation details of one class in another classes test suite

- **Stubs and mocks**
  - Use `mocha` gem 
  - Always prefer `OpenStruct` when creating mock instances, or in complex cases, a mock class
  - Only mock what's necessary. If you're not testing return values, don't mock a return value.




================================================
FILE: .cursor/rules/ui-ux-design-guidelines.mdc
================================================
---
description: This file describes Maybe's design system and how views should be styled
globs: app/views/**,app/helpers/**,app/javascript/controllers/**
alwaysApply: true
---
Use the rules below when:

- You are writing HTML
- You are writing CSS
- You are writing styles in a JavaScript Stimulus controller

## Rules for AI (mandatory)

The codebase uses TailwindCSS v4.x (the newest version) with a custom design system defined in [maybe-design-system.css](mdc:app/assets/tailwind/maybe-design-system.css)

- Always start by referencing [maybe-design-system.css](mdc:app/assets/tailwind/maybe-design-system.css) to see the base primitives, functional tokens, and component tokens we use in the codebase
- Always prefer using the functional "tokens" defined in @maybe-design-system.css when possible.
  - Example 1: use `text-primary` rather than `text-white`
  - Example 2: use `bg-container` rather than `bg-white`
  - Example 3: use `border border-primary` rather than `border border-gray-200` 
- Never create new styles in [maybe-design-system.css](mdc:app/assets/tailwind/maybe-design-system.css) or [application.css](mdc:app/assets/tailwind/application.css) without explicitly receiving permission to do so
- Always generate semantic HTML


================================================
FILE: .cursor/rules/view_conventions.mdc
================================================
---
description: 
globs: app/views/**,app/javascript/**,app/components/**/*.js
alwaysApply: false
---
Use this rule to learn how to write ERB views, partials, and Stimulus controllers should be incorporated into them.

- **Component vs. Partial Decision Making**
  - **Use ViewComponents when:**
    - Element has complex logic or styling patterns
    - Element will be reused across multiple views/contexts
    - Element needs structured styling with variants/sizes (like buttons, badges)
    - Element requires interactive behavior or Stimulus controllers
    - Element has configurable slots or complex APIs
    - Element needs accessibility features or ARIA support
  
  - **Use Partials when:**
    - Element is primarily static HTML with minimal logic
    - Element is used in only one or few specific contexts
    - Element is simple template content (like CTAs, static sections)
    - Element doesn't need variants, sizes, or complex configuration
    - Element is more about content organization than reusable functionality

- **Prefer components over partials**
  - If there is a component available for the use case in app/components, use it
  - If there is no component, look for a partial
  - If there is no partial, decide between component or partial based on the criteria above

- **Examples of Component vs. Partial Usage**
  ```erb
  <%# Component: Complex, reusable with variants and interactivity %>
  <%= render DialogComponent.new(variant: :drawer) do |dialog| %>
    <% dialog.with_header(title: "Account Settings") %>
    <% dialog.with_body { "Dialog content here" } %>
  <% end %>
  
  <%# Component: Interactive with complex styling options %>
  <%= render ButtonComponent.new(text: "Save Changes", variant: "primary", confirm: "Are you sure?") %>
  
  <%# Component: Reusable with variants %>
  <%= render FilledIconComponent.new(icon: "credit-card", variant: :surface) %>
  
  <%# Partial: Static template content %>
  <%= render "shared/logo" %>
  
  <%# Partial: Simple, context-specific content with basic styling %>
  <%= render "shared/trend_change", trend: @account.trend, comparison_label: "vs last month" %>
  
  <%# Partial: Simple divider/utility %>
  <%= render "shared/ruler", classes: "my-4" %>
  
  <%# Partial: Simple form utility %>
  <%= render "shared/form_errors", model: @account %>
  ```

- **Keep domain logic out of the views**
   ```erb
    <%# BAD!!! %>

    <%# This belongs in the component file, not the template file! %>
    <% button_classes = { class: "bg-blue-500 hover:bg-blue-600" } %>

    <%= tag.button class: button_classes do %>
      Save Account
    <% end %>

    <%# GOOD! %>

    <%= tag.button class: computed_button_classes do %>
      Save Account
    <% end %>
    ```

- **Stimulus Integration in Views**
  - Always use the **declarative approach** when integrating Stimulus controllers
  - The ERB template should declare what happens, the Stimulus controller should respond
  - Refer to [stimulus_conventions.mdc](mdc:.cursor/rules/stimulus_conventions.mdc) to learn how to incorporate them into 

  GOOD Stimulus controller integration into views:

  ```erb
  <!-- Declarative - HTML declares what happens -->

  <div data-controller="toggle">
    <button data-action="click->toggle#toggle" data-toggle-target="button">Show</button>
    <div data-toggle-target="content" class="hidden">Hello World!</div>
  </div>
  ```

- **Stimulus Controller Placement Guidelines**
  - **Component controllers** (in `app/components/`) should only be used within their component templates
  - **Global controllers** (in `app/javascript/controllers/`) can be used across any view
  - Pass data from Rails to Stimulus using `data-*-value` attributes, not inline JavaScript
  - Use Stimulus targets to reference DOM elements, not manual `getElementById` calls

- **Naming Conventions**
  - **Components**: Use `ComponentName` suffix (e.g., `ButtonComponent`, `DialogComponent`, `FilledIconComponent`)
  - **Partials**: Use underscore prefix (e.g., `_trend_change.html.erb`, `_form_errors.html.erb`, `_sync_indicator.html.erb`)
  - **Shared partials**: Place in `app/views/shared/` directory for reusable content
  - **Context-specific partials**: Place in relevant controller view directory (e.g., `accounts/_account_sidebar_tabs.html.erb`)

================================================
FILE: .devcontainer/Dockerfile
================================================
ARG RUBY_VERSION=3.4.4
FROM ruby:${RUBY_VERSION}-slim-bullseye

RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
  && apt-get -y install --no-install-recommends \
  apt-utils \
  build-essential \
  curl \
  git \
  imagemagick \
  iproute2 \
  libpq-dev \
  libyaml-dev \
  libyaml-0-2 \
  openssh-client \
  postgresql-client \
  vim

RUN gem install bundler
RUN gem install foreman

# Install Node.js 20
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs

WORKDIR /workspace


================================================
FILE: .devcontainer/devcontainer.json
================================================
{
  "name": "Maybe",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "containerEnv": {
    "GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}",
    "GITHUB_USER": "${localEnv:GITHUB_USER}"
  },
  "remoteEnv": {
    "PATH": "/workspace/bin:${containerEnv:PATH}"
  },
  "postCreateCommand": "bundle install && npm install",
  "customizations": {
    "vscode": {
      "extensions": [
        "biomejs.biome",
        "EditorConfig.EditorConfig"
      ]
    }
  }
}


================================================
FILE: .devcontainer/docker-compose.yml
================================================
x-db-env: &db_env
  POSTGRES_USER: postgres
  POSTGRES_DB: postgres
  POSTGRES_PASSWORD: postgres

x-rails-env: &rails_env
  DB_HOST: db
  HOST: "0.0.0.0"
  POSTGRES_USER: postgres
  POSTGRES_PASSWORD: postgres
  BUNDLE_PATH: /bundle
  REDIS_URL: redis://redis:6379/1

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile

    volumes:
      - ..:/workspace:cached
      - bundle_cache:/bundle

    ports:
      - "3000:3000"

    command: sleep infinity

    environment:
      <<: *rails_env

    depends_on:
      - db
      - redis

  worker:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    command: bundle exec sidekiq
    restart: unless-stopped
    environment:
      <<: *rails_env
    depends_on:
      - redis

  redis:
    image: redis:latest
    ports:
      - "6379:6379"
    restart: unless-stopped
    volumes:
      - redis-data:/data
  db:
    image: postgres:latest
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      <<: *db_env
    ports:
      - "5432:5432"

volumes:
  postgres-data:
  redis-data:
  bundle_cache:


================================================
FILE: .dockerignore
================================================
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.

# Ignore git directory.
/.git/
/.gitignore

# Ignore bundler config.
/.bundle

# Ignore all environment files (except templates).
/.env*
!/.env*.erb

# Ignore all default key files.
/config/master.key
/config/credentials/*.key

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/.keep

# Ignore assets.
/node_modules/
/app/assets/builds/*
!/app/assets/builds/.keep
/public/assets

# Ignore CI service files.
/.github

# Ignore Docker-related files
/.dockerignore
/Dockerfile*


================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2

================================================
FILE: .env.example
================================================
# ================================ PLEASE READ ===========================================================
# This file outlines all the possible environment variables supported by the Maybe app for self hosting.
#
# If you're a developer setting up your local environment, please use `.env.local.example` instead.
# ========================================================================================================

# Required self-hosting vars
# --------------------------------------------------------------------------------------------------------

# Enables self hosting features (should be set to true unless you know what you're doing)
SELF_HOSTED=true

# Secret key used to encrypt credentials (https://api.rubyonrails.org/v7.1.3.2/classes/Rails/Application.html#method-i-secret_key_base)
# Has to be a random string, generated eg. by running `openssl rand -hex 64`
SECRET_KEY_BASE=secret-value

# Optional self-hosting vars
# --------------------------------------------------------------------------------------------------------

# Optional: Synth API Key for exchange rates + stock prices
# (you can also set this in your self-hosted settings page)
# Get it here: https://synthfinance.com/
SYNTH_API_KEY=

# Custom port config
# For users who have other applications listening at 3000, this allows them to set a value puma will listen to.
PORT=3000

# SMTP Configuration
# This is only needed if you intend on sending emails from your Maybe instance (such as for password resets or email financial reports).
# Resend.com is a good option that offers a free tier for sending emails.
SMTP_ADDRESS=
SMTP_PORT=465
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_TLS_ENABLED=true

# Address that emails are sent from
EMAIL_SENDER=

# Database Configuration
DB_HOST=localhost # May need to be changed to `DB_HOST=db` if using devcontainer
DB_PORT=5432
POSTGRES_PASSWORD=postgres
POSTGRES_USER=postgres

# App Domain
# This is the domain that your Maybe instance will be hosted at. It is used to generate links in emails and other places.
APP_DOMAIN=

# Disable enforcing SSL connections
# DISABLE_SSL=true

# Active Record Encryption Keys (Optional)
# These keys are used to encrypt sensitive data like API keys in the database.
# If not provided, they will be automatically generated based on your SECRET_KEY_BASE.
# You can generate your own keys by running: rails db:encryption:init
# ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=
# ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=
# ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=

# ======================================================================================================
# Active Storage Configuration - responsible for storing file uploads
# ======================================================================================================
#
# * Defaults to disk storage but you can also use Amazon S3 or Cloudflare R2
# * Set the appropriate environment variables to use these services.
# * Ensure libvips is installed on your system for image processing - https://github.com/libvips/libvips
#
# Amazon S3
# ==========
# ACTIVE_STORAGE_SERVICE=amazon <- Enables Amazon S3 storage
# S3_ACCESS_KEY_ID=
# S3_SECRET_ACCESS_KEY=
# S3_REGION= # defaults to `us-east-1` if not set
# S3_BUCKET=
#
# Cloudflare R2
# =============
# ACTIVE_STORAGE_SERVICE=cloudflare <- Enables Cloudflare R2 storage
# CLOUDFLARE_ACCOUNT_ID=
# CLOUDFLARE_ACCESS_KEY_ID=
# CLOUDFLARE_SECRET_ACCESS_KEY=
# CLOUDFLARE_BUCKET=
#


================================================
FILE: .env.local.example
================================================
# To enable / disable self-hosting features.
SELF_HOSTED=false

# Enable Synth market data (careful, this will use your API credits)
SYNTH_API_KEY=yourapikeyhere


================================================
FILE: .env.test.example
================================================
SELF_HOSTED=false

# ================
# Data Providers
# ---------------------------------------------------------------------------------
# Uncomment and fill in live keys when you need to generate a VCR cassette fixture
# ================

# SYNTH_API_KEY=<add live key here>

# ================
# Miscellaneous
# ================

# Set to true if you want SimpleCov reports generated
COVERAGE=false

# Set to true to run test suite serially
DISABLE_PARALLELIZATION=false

================================================
FILE: .erb_lint.yml
================================================
EnableDefaultLinters: true
linters:
  Rubocop:
    enabled: true
    only: [Style/StringLiterals]
    rubocop_config:
      Style/StringLiterals:
        Enabled: true
        EnforcedStyle: double_quotes

================================================
FILE: .gitattributes
================================================
# See https://git-scm.com/docs/gitattributes for more about git attribute files.

# Mark the database schema as having been generated.
db/schema.rb linguist-generated

# Mark any vendored files as having been vendored.
vendor/* linguist-vendored
config/credentials/*.yml.enc diff=rails_credentials
config/credentials.yml.enc diff=rails_credentials


================================================
FILE: .github/DISCUSSION_TEMPLATE/feature-requests.yml
================================================
title: Feature Request
body:
  - type: markdown
    attributes:
      value: |
        Thanks for your interest in Maybe!  Please follow the template below to submit your feature request.  You can visit our [roadmap](https://github.com/orgs/maybe-finance/projects/13) to see what's currently planned.
  - type: textarea
    attributes:
      label: Describe the feature
      description: Provide a clear and concise description of the feature you would like.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Why is this feature important?
      description: Tell us what specific problem(s) this feature solves for you or other users.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Additional context, screenshots, and relevant links
      description: Provide additional info to help us evaluate whether this feature is a good fit for the product.


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Open a bug report when you experience broken functionality within the latest
  version of the Maybe app
title: 'Bug: [Add descriptive title here]'
labels: ''
assignees: ''

---

## Before you start (required)

### General checklist

- [ ] I have removed personal / sensitive data from screenshots and logs
- [ ] I have searched [existing issues](https://github.com/maybe-finance/maybe/issues?q=is:issue) and [discussions](https://github.com/maybe-finance/maybe/discussions) to ensure this is not a duplicate issue
    
### How are you using Maybe?

- [ ] I am a paying Maybe customer (hosted version)
  - Paying Maybe users can also open requests in Intercom (if there is sensitive info involved)
- [ ] I am a self-hosted user

### Self hoster checklist

_Paying, hosted users should delete this entire section._

If you are a self-hosted user, please complete all of the information below.  Issues with incomplete information will be marked as `Needs Info` to help our small team prioritize bug fixes.

- Self hosted app commit SHA (find in user menu): [enter commit sha here]
  - [ ] I have confirmed that my app's commit is the latest version of Maybe
- Where are you hosting?
  - [ ] Render
  - [ ] Docker Compose
  - [ ] Umbrel
  - [ ] Other (please specify)

---

## Bug description

A clear and concise description of what the bug is.

### To Reproduce

Be as specific as possible so Maybe maintainers can quickly reproduce the bug you're experiencing.

Steps to reproduce the behavior:

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

### Expected behavior

What is the intended behavior that you would expect?

### Screenshots and/or recordings

We highly recommend providing additional context with screenshots and/or screen recordings.  This will _significantly_ improve the chances of the bug being addressed and fixed quickly.


================================================
FILE: .github/ISSUE_TEMPLATE/other.md
================================================
---
name: Other
about: All other issues
title: ''
labels: ''
assignees: ''

---

## Before you start (required)

### Is this a bug?

A bug is _broken functionality_ of the app (i.e. it prevents you from using the app).  For bugs, please use the ["Bug Report" template](https://github.com/maybe-finance/maybe/issues) instead.

### Is this a bug with _sensitive info_?

If you are a _paying_ Maybe user, you can open a support request in Intercom.

### Is this a feature request?

A feature request is functionality that you would like that is not already on our [Roadmap](https://github.com/maybe-finance/maybe/wiki/Roadmap).

All feature requests should be opened in a [Feature request Discussion](https://github.com/maybe-finance/maybe/discussions/categories/feature-requests).

Be sure to search existing discussions prior to opening a new feature request.

### Is this related to Docker and/or hosting for self hosting?

If you are having a Docker configuration issue, please do not open a Github issue unless you've identified a bug in our Dockerfile.  To get help with self hosting, there are several options:

- **First**: Read our [Docker hosting guide](https://github.com/maybe-finance/maybe/tree/main/docs/hosting/docker.md) and follow it step-by-step
- Open a [Docker Discussion](https://github.com/maybe-finance/maybe/discussions/categories/docker-compose-hosting)

---

## Issue description

If your issue does not fall into the categories above, please provide a **descriptive and complete** overview of your issue.


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: bundler
    directory: "/"
    schedule:
      interval: weekly
    open-pull-requests-limit: 10
  - package-ecosystem: github-actions
    directory: "/"
    schedule:
      interval: weekly
    open-pull-requests-limit: 10


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  workflow_call:

jobs:
  scan_ruby:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Scan for security vulnerabilities in Ruby dependencies
        run: bin/brakeman --no-pager

  scan_js:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Scan for security vulnerabilities in JavaScript dependencies
        run: bin/importmap audit

  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Lint code for consistent style
        run: bin/rubocop -f github

  lint_js:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js environment
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"

      - name: Install dependencies
        run: npm install
        shell: bash

      - name: Lint/Format js code
        run: npm run lint

  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    env:
      PLAID_CLIENT_ID: foo
      PLAID_SECRET: bar
      DATABASE_URL: postgres://postgres:postgres@localhost:5432
      REDIS_URL: redis://localhost:6379
      RAILS_ENV: test

    services:
      postgres:
        image: postgres
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
        ports:
          - 5432:5432
        options: --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3

      redis:
        image: redis
        ports:
          - 6379:6379
        options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3

    steps:
      - name: Install packages
        run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable curl libvips postgresql-client libpq-dev

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: DB setup and smoke test
        run: |
          bin/rails db:create
          bin/rails db:schema:load
          bin/rails db:seed

      - name: Unit and integration tests
        run: bin/rails test

      - name: System tests
        run: DISABLE_PARALLELIZATION=true bin/rails test:system

      - name: Keep screenshots from failed system tests
        uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: screenshots
          path: ${{ github.workspace }}/tmp/screenshots
          if-no-files-found: ignore


================================================
FILE: .github/workflows/pr.yml
================================================
name: Pull Request

on:
  pull_request:

jobs:
  ci:
    uses: ./.github/workflows/ci.yml

================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish Docker image

on:
  workflow_dispatch:
    inputs:
      ref:
        description: 'Git ref (tag or commit SHA) to build'
        required: true
        type: string 
        default: 'main'
  push:
    tags:
      - 'v*'
    branches:
      - main

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

permissions:
  contents: read

jobs:
  ci:
    uses: ./.github/workflows/ci.yml

  build:
    name: Build docker image
    needs: [ ci ]

    timeout-minutes: 60

    runs-on: ubuntu-latest

    permissions:
      contents: read
      packages: write

    steps:
      - name: Check out the repo
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.ref || github.ref }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to the container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          flavor: latest=auto
          tags: |
            type=sha,format=long
            type=semver,pattern={{version}}
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
            type=raw,value=stable,enable=${{ startsWith(github.ref, 'refs/tags/v') }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v6
        id: build
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: 'linux/amd64,linux/arm64'
          cache-from: type=gha
          cache-to: type=gha,mode=max
          provenance: false
          # https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#adding-a-description-to-multi-arch-images
          outputs: type=image,name=target,annotation-index.org.opencontainers.image.description=A multi-arch Docker image for the Maybe Rails app
          build-args: BUILD_COMMIT_SHA=${{ github.sha }}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
#   git config --global core.excludesfile '~/.gitignore_global'

# Ignore bundler config.
/.bundle
/vendor/bundle

# Ignore all environment files (except templates).
/.env*
!/.env*.erb
!.env*.example

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep

/public/assets

# Ignore master key for decrypting credentials and more.
/config/master.key

/app/assets/builds/*
!/app/assets/builds/.keep

# Ignore Jetbrains IDEs
.idea

# Ignore VS Code
.vscode/*
!.vscode/extensions.json
!.vscode/*.code-snippets

# Ignore macOS specific files
*/.DS_Store
.DS_Store

# Ignore .devcontainer files
compose-dev.yaml

# Ignore asdf ruby version file
.tool-versions

# Ignore GCP keyfile
gcp-storage-keyfile.json

coverage
.cursorrules
.cursor/rules/structure.mdc
.cursor/rules/agent.mdc

# Ignore node related files
node_modules

compose.yml

plaid_test_accounts/

# Added by Claude Task Master
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
dev-debug.log
# Dependency directories
node_modules/
# Environment variables
.env
# Editor directories and files
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.roo*
# OS specific
# Task files
.taskmaster/
tasks.json
.taskmaster/tasks/
.taskmaster/reports/
.taskmaster/state.json
*.mcp.json
scripts/
.cursor/mcp.json
.taskmasterconfig
.windsurfrules
.cursor/rules/dev_workflow.mdc
.cursor/rules/taskmaster.mdc


================================================
FILE: .rubocop.yml
================================================
inherit_gem:
  rubocop-rails-omakase: rubocop.yml
  
Layout/IndentationWidth:
  Enabled: true

Layout/IndentationStyle:
  EnforcedStyle: spaces
  IndentationWidth: 2

Layout/IndentationConsistency:
  Enabled: true

Layout/SpaceInsidePercentLiteralDelimiters:
  Enabled: true

================================================
FILE: .ruby-version
================================================
3.4.4


================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Common Development Commands

### Development Server
- `bin/dev` - Start development server (Rails, Sidekiq, Tailwind CSS watcher)
- `bin/rails server` - Start Rails server only
- `bin/rails console` - Open Rails console

### Testing
- `bin/rails test` - Run all tests
- `bin/rails test:db` - Run tests with database reset
- `bin/rails test:system` - Run system tests only (use sparingly - they take longer)
- `bin/rails test test/models/account_test.rb` - Run specific test file
- `bin/rails test test/models/account_test.rb:42` - Run specific test at line

### Linting & Formatting
- `bin/rubocop` - Run Ruby linter
- `npm run lint` - Check JavaScript/TypeScript code
- `npm run lint:fix` - Fix JavaScript/TypeScript issues
- `npm run format` - Format JavaScript/TypeScript code
- `bin/brakeman` - Run security analysis

### Database
- `bin/rails db:prepare` - Create and migrate database
- `bin/rails db:migrate` - Run pending migrations
- `bin/rails db:rollback` - Rollback last migration
- `bin/rails db:seed` - Load seed data

### Setup
- `bin/setup` - Initial project setup (installs dependencies, prepares database)

## Pre-Pull Request CI Workflow

ALWAYS run these commands before opening a pull request:

1. **Tests** (Required):
   - `bin/rails test` - Run all tests (always required)
   - `bin/rails test:system` - Run system tests (only when applicable, they take longer)

2. **Linting** (Required):
   - `bin/rubocop -f github -a` - Ruby linting with auto-correct
   - `bundle exec erb_lint ./app/**/*.erb -a` - ERB linting with auto-correct

3. **Security** (Required):
   - `bin/brakeman --no-pager` - Security analysis

Only proceed with pull request creation if ALL checks pass.

## General Development Rules

### Authentication Context
- Use `Current.user` for the current user. Do NOT use `current_user`.
- Use `Current.family` for the current family. Do NOT use `current_family`.

### Development Guidelines
- Prior to generating any code, carefully read the project conventions and guidelines
- Ignore i18n methods and files. Hardcode strings in English for now to optimize speed of development
- Do not run `rails server` in your responses
- Do not run `touch tmp/restart.txt`
- Do not run `rails credentials`
- Do not automatically run migrations

## High-Level Architecture

### Application Modes
The Maybe app runs in two distinct modes:
- **Managed**: The Maybe team operates and manages servers for users (Rails.application.config.app_mode = "managed")
- **Self Hosted**: Users host the Maybe app on their own infrastructure, typically through Docker Compose (Rails.application.config.app_mode = "self_hosted")

### Core Domain Model
The application is built around financial data management with these key relationships:
- **User** → has many **Accounts** → has many **Transactions**
- **Account** types: checking, savings, credit cards, investments, crypto, loans, properties
- **Transaction** → belongs to **Category**, can have **Tags** and **Rules**
- **Investment accounts** → have **Holdings** → track **Securities** via **Trades**

### API Architecture
The application provides both internal and external APIs:
- Internal API: Controllers serve JSON via Turbo for SPA-like interactions
- External API: `/api/v1/` namespace with Doorkeeper OAuth and API key authentication
- API responses use Jbuilder templates for JSON rendering
- Rate limiting via Rack Attack with configurable limits per API key

### Sync & Import System
Two primary data ingestion methods:
1. **Plaid Integration**: Real-time bank account syncing
   - `PlaidItem` manages connections
   - `Sync` tracks sync operations
   - Background jobs handle data updates
2. **CSV Import**: Manual data import with mapping
   - `Import` manages import sessions
   - Supports transaction and balance imports
   - Custom field mapping with transformation rules

### Background Processing
Sidekiq handles asynchronous tasks:
- Account syncing (`SyncAccountsJob`)
- Import processing (`ImportDataJob`)
- AI chat responses (`CreateChatResponseJob`)
- Scheduled maintenance via sidekiq-cron

### Frontend Architecture
- **Hotwire Stack**: Turbo + Stimulus for reactive UI without heavy JavaScript
- **ViewComponents**: Reusable UI components in `app/components/`
- **Stimulus Controllers**: Handle interactivity, organized alongside components
- **Charts**: D3.js for financial visualizations (time series, donut, sankey)
- **Styling**: Tailwind CSS v4.x with custom design system
  - Design system defined in `app/assets/tailwind/maybe-design-system.css`
  - Always use functional tokens (e.g., `text-primary` not `text-white`)
  - Prefer semantic HTML elements over JS components
  - Use `icon` helper for icons, never `lucide_icon` directly

### Multi-Currency Support
- All monetary values stored in base currency (user's primary currency)
- Exchange rates fetched from Synth API
- `Money` objects handle currency conversion and formatting
- Historical exchange rates for accurate reporting

### Security & Authentication
- Session-based auth for web users
- API authentication via:
  - OAuth2 (Doorkeeper) for third-party apps
  - API keys with JWT tokens for direct API access
- Scoped permissions system for API access
- Strong parameters and CSRF protection throughout

### Testing Philosophy
- Comprehensive test coverage using Rails' built-in Minitest
- Fixtures for test data (avoid FactoryBot)
- Keep fixtures minimal (2-3 per model for base cases)
- VCR for external API testing
- System tests for critical user flows (use sparingly)
- Test helpers in `test/support/` for common scenarios
- Only test critical code paths that significantly increase confidence
- Write tests as you go, when required

### Performance Considerations
- Database queries optimized with proper indexes
- N+1 queries prevented via includes/joins
- Background jobs for heavy operations
- Caching strategies for expensive calculations
- Turbo Frames for partial page updates

### Development Workflow
- Feature branches merged to `main`
- Docker support for consistent environments
- Environment variables via `.env` files
- Lookbook for component development (`/lookbook`)
- Letter Opener for email preview in development

## Project Conventions

### Convention 1: Minimize Dependencies
- Push Rails to its limits before adding new dependencies
- Strong technical/business reason required for new dependencies
- Favor old and reliable over new and flashy

### Convention 2: Skinny Controllers, Fat Models
- Business logic in `app/models/` folder, avoid `app/services/`
- Use Rails concerns and POROs for organization
- Models should answer questions about themselves: `account.balance_series` not `AccountSeries.new(account).call`

### Convention 3: Hotwire-First Frontend
- **Native HTML preferred over JS components**
  - Use `<dialog>` for modals, `<details><summary>` for disclosures
- **Leverage Turbo frames** for page sections over client-side solutions
- **Query params for state** over localStorage/sessions
- **Server-side formatting** for currencies, numbers, dates
- **Always use `icon` helper** in `application_helper.rb`, NEVER `lucide_icon` directly

### Convention 4: Optimize for Simplicity
- Prioritize good OOP domain design over performance
- Focus performance only on critical/global areas (avoid N+1 queries, mindful of global layouts)

### Convention 5: Database vs ActiveRecord Validations
- Simple validations (null checks, unique indexes) in DB
- ActiveRecord validations for convenience in forms (prefer client-side when possible)
- Complex validations and business logic in ActiveRecord

## TailwindCSS Design System

### Design System Rules
- **Always reference `app/assets/tailwind/maybe-design-system.css`** for primitives and tokens
- **Use functional tokens** defined in design system:
  - `text-primary` instead of `text-white`
  - `bg-container` instead of `bg-white`
  - `border border-primary` instead of `border border-gray-200`
- **NEVER create new styles** in design system files without permission
- **Always generate semantic HTML**

## Component Architecture

### ViewComponent vs Partials Decision Making

**Use ViewComponents when:**
- Element has complex logic or styling patterns
- Element will be reused across multiple views/contexts
- Element needs structured styling with variants/sizes
- Element requires interactive behavior or Stimulus controllers
- Element has configurable slots or complex APIs
- Element needs accessibility features or ARIA support

**Use Partials when:**
- Element is primarily static HTML with minimal logic
- Element is used in only one or few specific contexts
- Element is simple template content
- Element doesn't need variants, sizes, or complex configuration
- Element is more about content organization than reusable functionality

**Component Guidelines:**
- Prefer components over partials when available
- Keep domain logic OUT of view templates
- Logic belongs in component files, not template files

### Stimulus Controller Guidelines

**Declarative Actions (Required):**
```erb
<!-- GOOD: Declarative - HTML declares what happens -->
<div data-controller="toggle">
  <button data-action="click->toggle#toggle" data-toggle-target="button">Show</button>
  <div data-toggle-target="content" class="hidden">Hello World!</div>
</div>
```

**Controller Best Practices:**
- Keep controllers lightweight and simple (< 7 targets)
- Use private methods and expose clear public API
- Single responsibility or highly related responsibilities
- Component controllers stay in component directory, global controllers in `app/javascript/controllers/`
- Pass data via `data-*-value` attributes, not inline JavaScript

## Testing Philosophy

### General Testing Rules
- **ALWAYS use Minitest + fixtures** (NEVER RSpec or factories)
- Keep fixtures minimal (2-3 per model for base cases)
- Create edge cases on-the-fly within test context
- Use Rails helpers for large fixture creation needs

### Test Quality Guidelines
- **Write minimal, effective tests** - system tests sparingly
- **Only test critical and important code paths**
- **Test boundaries correctly:**
  - Commands: test they were called with correct params
  - Queries: test output
  - Don't test implementation details of other classes

### Testing Examples

```ruby
# GOOD - Testing critical domain business logic
test "syncs balances" do
  Holding::Syncer.any_instance.expects(:sync_holdings).returns([]).once
  assert_difference "@account.balances.count", 2 do
    Balance::Syncer.new(@account, strategy: :forward).sync_balances
  end
end

# BAD - Testing ActiveRecord functionality
test "saves balance" do 
  balance_record = Balance.new(balance: 100, currency: "USD")
  assert balance_record.save
end
```

### Stubs and Mocks
- Use `mocha` gem
- Prefer `OpenStruct` for mock instances
- Only mock what's necessary

================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Maybe

It means so much that you're interested in contributing to Maybe! Seriously. Thank you. The entire community benefits from these contributions!

## House Rules

- Before contributing, familiarize yourself with our project conventions. You should read through our [Project Conventions Rule](https://github.com/maybe-finance/maybe/.cursor/rules/project-conventions.mdc), which is intended for LLMs, but is also an excellent primer on how we write code for Maybe.
- While totally optional, consider using Cursor + VSCode as it will automatically apply our project conventions to your code via the `.cursor/rules` directory.
- Before contributing, please check if it already exists in [issues](https://github.com/maybe-finance/maybe/issues) or [PRs](https://github.com/maybe-finance/maybe/pulls)
- Given the speed at which we're moving on the codebase, we don't assign issues or "give" issues to anyone.
- When multiple PRs are submitted for the same issue, we take the one that most succinctly & efficiently solves a given problem and stays within the scope of work.
- Priority is generally given to previous committers as they've proven familiarity with the codebase and product.

## What should I contribute?

As we are still in the early days of this project, we recommend [heading over to the Wiki](https://github.com/maybe-finance/maybe/wiki) to get a better idea of _what_ to contribute.

In general, _full features_ that get us closer to [our Vision](https://github.com/maybe-finance/maybe/wiki/Vision) are the most valuable contributions at this stage.

## Development

### Setup

To get setup for local development, you have two options:

1. [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) with VSCode (see the `.devcontainer` folder)
2. Local Development
   - [Mac Setup Guide](https://github.com/maybe-finance/maybe/wiki/Mac-Dev-Setup-Guide)
   - [Linux Setup Guide](https://github.com/maybe-finance/maybe/wiki/Linux-Dev-Setup-Guide)
   - [Windows Setup Guide](https://github.com/maybe-finance/maybe/wiki/Windows-Dev-Setup-Guide)

### Making a Pull Request

1. Fork the repo
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request, and be sure to check the [Allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) option while creating your PR. This allows maintainers to collaborate with you on your PR if needed.
6. If possible, [link your pull request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) by adding the appropriate keyword (e.g. `fixes issue #XXX`)
7. Before requesting a review, please make sure that all [Github Checks](https://docs.github.com/en/rest/checks?apiVersion=2022-11-28) have passed and your branch is up-to-date with the `main` branch. After doing so, request a review and wait for a maintainer's approval.

All PRs should target the `main` branch.


================================================
FILE: Dockerfile
================================================
# syntax = docker/dockerfile:1

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.4.4
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim AS base

# Rails app lives here
WORKDIR /rails

# Install base packages
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl libvips postgresql-client libyaml-0-2

# Set production environment
ARG BUILD_COMMIT_SHA
ENV RAILS_ENV="production" \
    BUNDLE_DEPLOYMENT="1" \
    BUNDLE_PATH="/usr/local/bundle" \
    BUNDLE_WITHOUT="development" \
    BUILD_COMMIT_SHA=${BUILD_COMMIT_SHA}
    
# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build gems
RUN apt-get install --no-install-recommends -y build-essential libpq-dev git pkg-config libyaml-dev

# Install application gems
COPY .ruby-version Gemfile Gemfile.lock ./
RUN bundle install

RUN rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git

RUN bundle exec bootsnap precompile --gemfile -j 0

# Copy application code
COPY . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile -j 0 app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile

# Final stage for app image
FROM base

# Clean up installation packages to reduce image size
RUN rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
    useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
    chown -R rails:rails db log storage tmp
USER 1000:1000

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]


================================================
FILE: Gemfile
================================================
source "https://rubygems.org"

ruby file: ".ruby-version"

# Rails
gem "rails", "~> 7.2.2"

# Drivers
gem "pg", "~> 1.5"
gem "redis", "~> 5.4"

# Deployment
gem "puma", ">= 5.0"
gem "bootsnap", require: false

# Assets
gem "importmap-rails"
gem "propshaft"
gem "tailwindcss-rails"
gem "lucide-rails", github: "maybe-finance/lucide-rails"

# Hotwire + UI
gem "stimulus-rails"
gem "turbo-rails"
gem "view_component"

# https://github.com/lookbook-hq/lookbook/issues/712
# TODO: Remove max version constraint when fixed
gem "lookbook", "2.3.11"

gem "hotwire_combobox"

# Background Jobs
gem "sidekiq"
gem "sidekiq-cron"

# Monitoring
gem "vernier"
gem "rack-mini-profiler"
gem "sentry-ruby"
gem "sentry-rails"
gem "sentry-sidekiq"
gem "logtail-rails"
gem "skylight", groups: [ :production ]

# Active Storage
gem "aws-sdk-s3", "~> 1.177.0", require: false
gem "image_processing", ">= 1.2"

# Other
gem "ostruct"
gem "bcrypt", "~> 3.1"
gem "jwt"
gem "jbuilder"

# OAuth & API Security
gem "doorkeeper"
gem "rack-attack", "~> 6.6"
gem "faraday"
gem "faraday-retry"
gem "faraday-multipart"
gem "inline_svg"
gem "octokit"
gem "pagy"
gem "rails-settings-cached"
gem "tzinfo-data", platforms: %i[windows jruby]
gem "csv"
gem "redcarpet"
gem "stripe"
gem "intercom-rails"
gem "plaid"
gem "rotp", "~> 6.3"
gem "rqrcode", "~> 3.0"
gem "activerecord-import"
gem "rubyzip", "~> 2.3"

# State machines
gem "aasm"
gem "after_commit_everywhere", "~> 1.0"

# AI
gem "ruby-openai"

group :development, :test do
  gem "debug", platforms: %i[mri windows]
  gem "brakeman", require: false
  gem "rubocop-rails-omakase", require: false
  gem "i18n-tasks"
  gem "erb_lint"
  gem "dotenv-rails"
end

if ENV["BENCHMARKING_ENABLED"]
  gem "dotenv-rails", groups: [ :production ]
end

group :development do
  gem "hotwire-livereload"
  gem "letter_opener"
  gem "ruby-lsp-rails"
  gem "web-console"
  gem "faker"
  gem "benchmark-ips"
  gem "stackprof"
  gem "derailed_benchmarks"
  gem "foreman"
end

group :test do
  gem "capybara"
  gem "selenium-webdriver"
  gem "mocha"
  gem "vcr"
  gem "webmock"
  gem "climate_control"
  gem "simplecov", require: false
end


================================================
FILE: LICENSE
================================================
                    GNU AFFERO GENERAL PUBLIC LICENSE
                       Version 3, 19 November 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.

  A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate.  Many developers of free software are heartened and
encouraged by the resulting cooperation.  However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.

  The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community.  It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server.  Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.

  An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals.  This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU Affero General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Remote Network Interaction; Use with the GNU General Public License.

  Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software.  This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time.  Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source.  For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code.  There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

================================================
FILE: Procfile.dev
================================================
web: bundle exec ${DEBUG:+rdbg -O -n -c --} bin/rails server -b 0.0.0.0
css: bundle exec bin/rails tailwindcss:watch 2>/dev/null
worker: bundle exec sidekiq


================================================
FILE: README.md
================================================

<img width="1190" alt="maybe_hero" src="https://github.com/user-attachments/assets/5ed08763-a9ee-42b2-a436-e05038fcf573" />

# Maybe: The personal finance app for everyone

> [!IMPORTANT]
> This repository is no longer actively maintained. You can read more about this in our [final release](https://github.com/maybe-finance/maybe/releases/tag/v0.6.0).

## Maybe Hosting

Maybe is a fully working personal finance app that can be [self hosted with Docker](docs/hosting/docker.md).

## Forking and Attribution

This repo is no longer maintained. You’re free to fork it under the AGPLv3. To stay compliant and avoid trademark issues:

- Be sure to include the original [AGPLv3 license](https://github.com/maybe-finance/maybe/blob/main/LICENSE) and clearly state in your README that your fork is based on Maybe Finance but is **not affiliated with or endorsed by** Maybe Finance Inc.
- "Maybe" is a trademark of Maybe Finance Inc. and therefore, use of it is NOT allowed in forked repositories (or the logo)

## Local Development Setup

**If you are trying to _self-host_ the Maybe app, stop here. You
should [read this guide to get started](docs/hosting/docker.md).**

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

### Requirements

- See `.ruby-version` file for required Ruby version
- PostgreSQL >9.3 (ideally, latest stable version)

After cloning the repo, the basic setup commands are:

```sh
cd maybe
cp .env.local.example .env.local
bin/setup
bin/dev

# Optionally, load demo data
rake demo_data:default
```

And visit http://localhost:3000 to see the app. You can use the following
credentials to log in (generated by DB seed):

- Email: `user@maybe.local`
- Password: `password`

For further instructions, see guides below.

### Setup Guides

- [Mac dev setup guide](https://github.com/maybe-finance/maybe/wiki/Mac-Dev-Setup-Guide)
- [Linux dev setup guide](https://github.com/maybe-finance/maybe/wiki/Linux-Dev-Setup-Guide)
- [Windows dev setup guide](https://github.com/maybe-finance/maybe/wiki/Windows-Dev-Setup-Guide)
- Dev containers - visit [this guide](https://code.visualstudio.com/docs/devcontainers/containers) to learn more

## Copyright & license

Maybe is distributed under
an [AGPLv3 license](https://github.com/maybe-finance/maybe/blob/main/LICENSE). "
Maybe" is a trademark of Maybe Finance, Inc.


================================================
FILE: Rakefile
================================================
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require_relative "config/application"

Rails.application.load_tasks


================================================
FILE: app/assets/builds/.keep
================================================


================================================
FILE: app/assets/tailwind/application.css
================================================
@import 'tailwindcss';

@import "./maybe-design-system.css";

@import "./geist-font.css";
@import "./geist-mono-font.css";

@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";

@import "./simonweb_pickr.css";

@layer components {
  .pcr-app{
    position: static !important;
    background: none !important;
    box-shadow: none !important;
    padding: 0 !important;
    width: 100% !important;
  }
  .pcr-color-palette{
      height: 12em !important;
  }
  .pcr-palette{
      border-radius: 10px !important;
  }
  .pcr-palette:before{
      border-radius: 10px !important;
  }
  .pcr-color-chooser{
      height: 1.5em !important;
  }
  .pcr-picker{
      height: 20px !important;
      width: 20px !important;
  }
}

.combobox {
  .hw-combobox__main__wrapper,
  .hw-combobox__input {
    @apply bg-container text-primary w-full;
  }

  .hw-combobox__main__wrapper {
    @apply border-0 p-0 focus:border-0 ring-0 focus:ring-0 shadow-none focus:shadow-none focus-within:shadow-none;
  }

  .hw-combobox__listbox {
    @apply absolute top-[160%] right-0 w-full bg-transparent rounded z-30;
  }

  .hw-combobox__label {
    @apply block text-xs text-gray-500 peer-disabled:text-gray-400;
  }
  
  .hw-combobox__option {
    @apply bg-container hover:bg-container-hover;
  }

  .hw_combobox__pagination__wrapper {
    @apply h-px;

    &:only-child {
      @apply bg-transparent;
    }
  }

  --hw-border-color: rgba(0, 0, 0, 0.2);
  --hw-handle-width: 20px;
  --hw-handle-height: 20px;
  --hw-handle-offset-right: 0px;
}

/* Typography */
.prose {
  @apply max-w-none text-primary; 

  a {
    @apply text-link;
  }

  h2 {
    @apply text-xl font-medium text-primary;
  }

  h3 {
    @apply text-lg font-medium text-primary;
  }

  li {
    @apply m-0 text-primary;
  }

  details {
    @apply mb-4 rounded-xl mt-3.5;
  }

  summary {
    @apply flex items-center gap-1;
  }

  video {
    @apply m-0 rounded-b-xl;
  }
}

.prose--github-release-notes {
  .octicon {
    @apply inline-block overflow-visible align-text-bottom fill-current;
  }

  .dropdown-caret {
    @apply content-none border-4 border-b-0 border-transparent border-t-gray-500 size-0 inline-block;
  }

  .user-mention {
    @apply font-bold;
  }
}

.prose--ai-chat {
  @apply break-words;

  p, li {
    @apply text-sm text-primary;
  }

  scrollbar-width: thin;
  scrollbar-color: rgba(156, 163, 175, 0.5) transparent;

  ::-webkit-scrollbar {
    width: 6px;
  }

  ::-webkit-scrollbar-track {
    background: transparent;
  }

  ::-webkit-scrollbar-thumb {
    background-color: rgba(156, 163, 175, 0.5);
    border-radius: 3px; 
  }
}

/* Custom scrollbar implementation for Windows browsers */
.windows {
  ::-webkit-scrollbar {
    width: 4px;
  }

  ::-webkit-scrollbar-thumb {
    background: #d6d6d6;
    border-radius: 10px;
  }

  ::-webkit-scrollbar-thumb:hover {
    background: #a6a6a6;
  }  
}

.scrollbar {
  &::-webkit-scrollbar {
    width: 4px;
  }

  &::-webkit-scrollbar-thumb {
    background: #d6d6d6;
    border-radius: 10px;
  }

  &::-webkit-scrollbar-thumb:hover {
    background: #a6a6a6;
  }
}

================================================
FILE: app/assets/tailwind/geist-font.css
================================================


/* Variable font */
@font-face {
  font-family: 'Geist';
  src: url('./geist/Geist[wght].woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Static fonts (fallback) */
@supports not (font-variation-settings: normal) {
  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-Thin.woff2') format('woff2');
    font-weight: 100;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-ExtraLight.woff2') format('woff2');
    font-weight: 200;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-Light.woff2') format('woff2');
    font-weight: 300;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-Medium.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-ExtraBold.woff2') format('woff2');
    font-weight: 800;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist';
    src: url('./geist/Geist-Black.woff2') format('woff2');
    font-weight: 900;
    font-style: normal;
    font-display: swap;
  }
}


================================================
FILE: app/assets/tailwind/geist-mono-font.css
================================================
/* Variable font */
@font-face {
  font-family: 'Geist Mono';
  src: url('./geist_mono/GeistMono[wght].woff2') format('woff2-variations');
  font-weight: 100 950;
  font-style: normal;
  font-display: swap;
}

/* Static fonts (fallback) */
@supports not (font-variation-settings: normal) {
  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-Thin.woff2') format('woff2');
    font-weight: 100;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-UltraLight.woff2') format('woff2');
    font-weight: 200;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-Light.woff2') format('woff2');
    font-weight: 300;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-Medium.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-Black.woff2') format('woff2');
    font-weight: 900;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: 'Geist Mono';
    src: url('./geist_mono/GeistMono-UltraBlack.woff2') format('woff2');
    font-weight: 950;
    font-style: normal;
    font-display: swap;
  }
}


================================================
FILE: app/assets/tailwind/maybe-design-system/background-utils.css
================================================
@utility bg-surface {
  @apply bg-gray-50;

  @variant theme-dark {
    @apply bg-black;
  }
}

@utility bg-surface-hover {
  @apply bg-gray-100;

  @variant theme-dark {
    @apply bg-gray-900;
  }
}

@utility bg-surface-inset {
  @apply bg-gray-100;

  @variant theme-dark {
    @apply bg-gray-800;
  }
}

@utility bg-surface-inset-hover {
  @apply bg-gray-200;

  @variant theme-dark {
    @apply bg-gray-800;
  }
}

@utility bg-container {
  @apply bg-white;

  @variant theme-dark {
    @apply bg-gray-900;
  }
}

@utility bg-container-hover {
  @apply bg-gray-50;

  @variant theme-dark {
    @apply bg-gray-800;
  }
}

@utility bg-container-inset {
  @apply bg-gray-50;

  @variant theme-dark {
    @apply bg-gray-800;
  }
}

@utility bg-container-inset-hover {
  @apply bg-gray-100;

  @variant theme-dark {
    @apply bg-gray-700;
  }
}

@utility bg-inverse {
  @apply bg-gray-800;

  @variant theme-dark {
    @apply bg-white;
  }
}

@utility bg-inverse-hover {
  @apply bg-gray-700;

  @variant theme-dark {
    @apply bg-gray-100;
  }
}

@utility bg-overlay {
  background-color: --alpha(var(--color-gray-100) / 50%);

  @variant theme-dark {
    background-color: var(--color-alpha-black-900);
  }
}

@utility bg-loader {
  @apply bg-surface-inset animate-pulse;
}


================================================
FILE: app/assets/tailwind/maybe-design-system/border-utils.css
================================================
/* Custom shadow borders used for surfaces / containers  */
@utility shadow-border-xs {
  box-shadow: var(--shadow-xs), 0px 0px 0px 1px var(--color-alpha-black-50);

  @variant theme-dark {
    box-shadow: var(--shadow-xs), 0px 0px 0px 1px var(--color-alpha-white-50);
  }
}

@utility shadow-border-sm {
  box-shadow: var(--shadow-sm), 0px 0px 0px 1px var(--color-alpha-black-50);

  @variant theme-dark {
    box-shadow: var(--shadow-sm), 0px 0px 0px 1px var(--color-alpha-white-50);
  }
}

@utility shadow-border-md {
  box-shadow: var(--shadow-md), 0px 0px 0px 1px var(--color-alpha-black-50);

  @variant theme-dark {
    box-shadow: var(--shadow-md), 0px 0px 0px 1px var(--color-alpha-white-50);
  }
}

@utility shadow-border-lg {
  box-shadow: var(--shadow-lg), 0px 0px 0px 1px var(--color-alpha-black-50);

  @variant theme-dark {
    box-shadow: var(--shadow-lg), 0px 0px 0px 1px var(--color-alpha-white-50);
  }
}

@utility shadow-border-xl {
  box-shadow: var(--shadow-xl), 0px 0px 0px 1px var(--color-alpha-black-50);

  @variant theme-dark {
    box-shadow: var(--shadow-xl), 0px 0px 0px 1px var(--color-alpha-white-50);
  }
}

@utility border-primary {
  @apply border-alpha-black-300;

  @variant theme-dark {
    @apply border-alpha-white-400;
  }
}

@utility border-secondary {
  @apply border-alpha-black-200;

  @variant theme-dark {
    @apply border-alpha-white-300;
  }
}

@utility border-tertiary {
  @apply border-alpha-black-100;

  @variant theme-dark {
    @apply border-alpha-white-200;
  }
}

@utility border-divider {
  @apply border-tertiary;
}

@utility border-subdued {
  @apply border-alpha-black-50;

  @variant theme-dark {
    @apply border-alpha-white-100;
  }
}

@utility border-solid {
  @apply border-black;

  @variant theme-dark {
    @apply border-white;
  }
}

@utility border-destructive {
  @apply border-red-500;

  @variant theme-dark {
    @apply border-red-400;
  }
}


================================================
FILE: app/assets/tailwind/maybe-design-system/component-utils.css
================================================
/* Button Backgrounds */
@utility button-bg-primary {
  @apply bg-gray-900;
  /* Maps to fg-primary light */

  @variant theme-dark {
    @apply bg-white;
    /* Maps to fg-primary dark */
  }
}

@utility button-bg-primary-hover {
  @apply bg-gray-800;
  /* Maps to fg-primary-variant light */

  @variant theme-dark {
    @apply bg-gray-50;
    /* Maps to fg-primary-variant dark */
  }
}

@utility button-bg-secondary {
  @apply bg-gray-50; /* Maps to fg-secondary light */

  @variant theme-dark {
    @apply bg-gray-700; /* Maps to fg-secondary dark */
  }
}

@utility button-bg-secondary-hover {
  @apply bg-gray-100; /* Maps to fg-secondary-variant light */

  @variant theme-dark {
    @apply bg-gray-600; /* Maps to fg-secondary-variant dark */
  }
}

@utility button-bg-disabled {
  @apply bg-gray-50;

  @variant theme-dark {
    @apply bg-gray-700;
  }
}

@utility button-bg-destructive {
  @apply bg-red-500;

  @variant theme-dark {
    @apply bg-red-400;
  }
}

@utility button-bg-destructive-hover {
  @apply bg-red-600;

  @variant theme-dark {
    @apply bg-red-500;
  }
}

@utility button-bg-ghost-hover {
  @apply bg-gray-50;

  @variant theme-dark {
    @apply bg-gray-800 fg-inverse;
  }
}

@utility button-bg-outline-hover {
  @apply bg-gray-100;

  @variant theme-dark {
    @apply bg-gray-700;
  }
}

/* Tab Styles */
@utility tab-item-active {
  @apply bg-white;

  @variant theme-dark {
    @apply bg-gray-700;
  }
}

@utility tab-item-hover {
  @apply bg-gray-200;

  @variant theme-dark {
    @apply bg-gray-800;
  }
}

@utility tab-bg-group {
  @apply bg-gray-50;

  @variant theme-dark {
    @apply bg-alpha-black-700;
  }
}

@utility bg-nav-indicator {
  @apply bg-black;

  @variant theme-dark {
    @apply bg-white;
  }
}

================================================
FILE: app/assets/tailwind/maybe-design-system/foreground-utils.css
================================================
@utility fg-gray {
  @apply text-gray-500;

  @variant theme-dark {
    @apply text-gray-400;
  }
}

@utility fg-contrast {
  @apply text-gray-400;

  @variant theme-dark {
    @apply text-gray-500;
  }
}

@utility fg-inverse {
  @apply text-white;

  @variant theme-dark {
    @apply text-gray-900;
  }
}

@utility fg-primary {
  @apply text-gray-900;

  @variant theme-dark {
    @apply text-white;
  }
}

@utility fg-primary-variant {
  @apply text-gray-800;

  @variant theme-dark {
    @apply text-gray-50;
  }
}

@utility fg-secondary {
  @apply text-gray-50;

  @variant theme-dark {
    @apply text-gray-700;
  }
}

@utility fg-secondary-variant {
  @apply text-gray-100;

  @variant theme-dark {
    @apply text-gray-600;
  }
}

@utility fg-subdued {
  @apply text-gray-400;

  @variant theme-dark {
    @apply text-gray-500;
  }
}

================================================
FILE: app/assets/tailwind/maybe-design-system/text-utils.css
================================================
@utility text-primary {
  @apply text-gray-900;

  @variant theme-dark {
   @apply text-white;
  }
}

@utility text-inverse {
  @apply text-white;

  @variant theme-dark {
    @apply text-gray-900;
  }
}

@utility text-secondary {
  @apply text-gray-500;

  @variant theme-dark {
    @apply text-gray-400;
  }
}

@utility text-subdued {
  @apply text-gray-400;

  @variant theme-dark {
    @apply text-gray-600;
  }
}

@utility text-link {
  @apply text-blue-600;

  @variant theme-dark {
    @apply text-blue-500;
  }
}

================================================
FILE: app/assets/tailwind/maybe-design-system.css
================================================
/* 
  This file contains all of the Figma design tokens, components, etc. that 
  are used globally across the app. 

  One-off styling (3rd party overrides, etc.) should be done in the application.css file.
*/

@import './maybe-design-system/background-utils.css';
@import './maybe-design-system/foreground-utils.css';
@import './maybe-design-system/text-utils.css';
@import './maybe-design-system/border-utils.css';
@import './maybe-design-system/component-utils.css';

@custom-variant theme-dark (&:where([data-theme=dark], [data-theme=dark] *));

@theme {
  /* Font families */
  --font-sans: 'Geist', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

  /* Base colors */
  --color-white: #ffffff;
  --color-black: #0B0B0B;
  --color-success: var(--color-green-600);
  --color-warning: var(--color-yellow-600);
  --color-destructive: var(--color-red-600);
  --color-shadow: --alpha(var(--color-black) / 6%);

  /* Colors used in Stimulus controllers with SVGs (easier to define light/dark mode here than toggle within the controllers) */
  /* See @layer base block below for dark mode overrides */
  --budget-unused-fill: var(--color-gray-200);
  --budget-unallocated-fill: var(--color-gray-50);

  /* Gray scale */
  --color-gray-25: #FAFAFA;
  --color-gray-50: #F7F7F7;
  --color-gray-100: #F0F0F0;
  --color-gray-200: #E7E7E7;
  --color-gray-300: #CFCFCF;
  --color-gray-400: #9E9E9E;
  --color-gray-500: #737373;
  --color-gray-600: #5C5C5C;
  --color-gray-700: #363636;
  --color-gray-800: #242424;
  --color-gray-900: #171717;
  --color-gray: var(--color-gray-500);
  --color-gray-tint-5: --alpha(var(--color-gray-500) / 5%);
  --color-gray-tint-10: --alpha(var(--color-gray-500) / 10%);

  /* Alpha colors */
  --color-alpha-white-25: --alpha(var(--color-white) / 3%);
  --color-alpha-white-50: --alpha(var(--color-white) / 5%);
  --color-alpha-white-100: --alpha(var(--color-white) / 8%);
  --color-alpha-white-200: --alpha(var(--color-white) / 10%);
  --color-alpha-white-300: --alpha(var(--color-white) / 15%);
  --color-alpha-white-400: --alpha(var(--color-white) / 20%);
  --color-alpha-white-500: --alpha(var(--color-white) / 30%);
  --color-alpha-white-600: --alpha(var(--color-white) / 40%);
  --color-alpha-white-700: --alpha(var(--color-white) / 50%);
  --color-alpha-white-800: --alpha(var(--color-white) / 70%);
  --color-alpha-white-900: --alpha(var(--color-white) / 85%);

  --color-alpha-black-25: --alpha(var(--color-black) / 3%);
  --color-alpha-black-50: --alpha(var(--color-black) / 5%);
  --color-alpha-black-100: --alpha(var(--color-black) / 8%);
  --color-alpha-black-200: --alpha(var(--color-black) / 10%);
  --color-alpha-black-300: --alpha(var(--color-black) / 15%);
  --color-alpha-black-400: --alpha(var(--color-black) / 20%);
  --color-alpha-black-500: --alpha(var(--color-black) / 30%);
  --color-alpha-black-600: --alpha(var(--color-black) / 40%);
  --color-alpha-black-700: --alpha(var(--color-black) / 50%);
  --color-alpha-black-800: --alpha(var(--color-black) / 70%);
  --color-alpha-black-900: --alpha(var(--color-black) / 85%);

  /* Red scale */
  --color-red-25: #FFFBFB;
  --color-red-50: #FFF1F0;
  --color-red-100: #FFDEDB;
  --color-red-200: #FEB9B3;
  --color-red-300: #F88C86;
  --color-red-400: #ED4E4E;
  --color-red-500: #F13636;
  --color-red-600: #EC2222;
  --color-red-700: #C91313;
  --color-red-800: #A40E0E;
  --color-red-900: #7E0707;
  --color-red-tint-5: --alpha(var(--color-red-500) / 5%);
  --color-red-tint-10: --alpha(var(--color-red-500) / 10%);

  /* Green scale */
  --color-green-25: #F6FEF9;
  --color-green-50: #ECFDF3;
  --color-green-100: #D1FADF;
  --color-green-200: #A6F4C5;
  --color-green-300: #6CE9A6;
  --color-green-400: #32D583;
  --color-green-500: #12B76A;
  --color-green-600: #10A861;
  --color-green-700: #078C52;
  --color-green-800: #05603A;
  --color-green-900: #054F31;
  --color-green-tint-5: --alpha(var(--color-green-500) / 5%);
  --color-green-tint-10: --alpha(var(--color-green-500) / 10%);

  /* Yellow scale */
  --color-yellow-25: #FFFCF5;
  --color-yellow-50: #FFFAEB;
  --color-yellow-100: #FEF0C7;
  --color-yellow-200: #FEDF89;
  --color-yellow-300: #FEC84B;
  --color-yellow-400: #FDB022;
  --color-yellow-500: #F79009;
  --color-yellow-600: #DC6803;
  --color-yellow-700: #B54708;
  --color-yellow-800: #93370D;
  --color-yellow-900: #7A2E0E;
  --color-yellow-tint-5: --alpha(var(--color-yellow-500) / 5%);
  --color-yellow-tint-10: --alpha(var(--color-yellow-500) / 10%);

  /* Cyan scale */
  --color-cyan-25: #F5FEFF;
  --color-cyan-50: #ECFDFF;
  --color-cyan-100: #CFF9FE;
  --color-cyan-200: #A5F0FC;
  --color-cyan-300: #67E3F9;
  --color-cyan-400: #22CCEE;
  --color-cyan-500: #06AED4;
  --color-cyan-600: #088AB2;
  --color-cyan-700: #0E7090;
  --color-cyan-800: #155B75;
  --color-cyan-900: #155B75;
  --color-cyan-tint-5: --alpha(var(--color-cyan-500) / 5%);
  --color-cyan-tint-10: --alpha(var(--color-cyan-500) / 10%);

  /* Blue scale */
  --color-blue-25: #F5FAFF;
  --color-blue-50: #EFF8FF;
  --color-blue-100: #D1E9FF;
  --color-blue-200: #B2DDFF;
  --color-blue-300: #84CAFF;
  --color-blue-400: #53B1FD;
  --color-blue-500: #2E90FA;
  --color-blue-600: #1570EF;
  --color-blue-700: #175CD3;
  --color-blue-800: #1849A9;
  --color-blue-900: #194185;
  --color-blue-tint-5: --alpha(var(--color-blue-500) / 5%);
  --color-blue-tint-10: --alpha(var(--color-blue-500) / 10%);

  /* Indigo scale */
  --color-indigo-25: #F5F8FF;
  --color-indigo-50: #EFF4FF;
  --color-indigo-100: #E0EAFF;
  --color-indigo-200: #C7D7FE;
  --color-indigo-300: #A4BCFD;
  --color-indigo-400: #8098F9;
  --color-indigo-500: #6172F3;
  --color-indigo-600: #444CE7;
  --color-indigo-700: #3538CD;
  --color-indigo-800: #2D31A6;
  --color-indigo-900: #2D3282;
  --color-indigo-tint-5: --alpha(var(--color-indigo-500) / 5%);
  --color-indigo-tint-10: --alpha(var(--color-indigo-500) / 10%);

  /* Violet scale */
  --color-violet-25: #FBFAFF;
  --color-violet-50: #F5F3FF;
  --color-violet-100: #ECE9FE;
  --color-violet-200: #DDD6FE;
  --color-violet-300: #C3B5FD;
  --color-violet-400: #A48AFB;
  --color-violet-500: #875BF7;
  --color-violet-600: #7839EE;
  --color-violet-700: #6927DA;
  --color-violet-tint-5: --alpha(var(--color-violet-500) / 5%);
  --color-violet-tint-10: --alpha(var(--color-violet-500) / 10%);

  /* Fuchsia scale */
  --color-fuchsia-25: #FEFAFF;
  --color-fuchsia-50: #FDF4FF;
  --color-fuchsia-100: #FBE8FF;
  --color-fuchsia-200: #F6D0FE;
  --color-fuchsia-300: #EEAAFD;
  --color-fuchsia-400: #E478FA;
  --color-fuchsia-500: #D444F1;
  --color-fuchsia-600: #BA24D5;
  --color-fuchsia-700: #9F1AB1;
  --color-fuchsia-800: #821890;
  --color-fuchsia-900: #6F1877;
  --color-fuchsia-tint-5: --alpha(var(--color-fuchsia-500) / 5%);
  --color-fuchsia-tint-10: --alpha(var(--color-fuchsia-500) / 10%);

  /* Pink scale */
  --color-pink-25: #FFFAFC;
  --color-pink-50: #FEF0F7;
  --color-pink-100: #FFD1E2;
  --color-pink-200: #FFB1CE;
  --color-pink-300: #FD8FBA;
  --color-pink-400: #F86BA7;
  --color-pink-500: #F23E94;
  --color-pink-600: #D5327F;
  --color-pink-700: #BA256B;
  --color-pink-800: #9E1958;
  --color-pink-900: #840B45;
  --color-pink-tint-5: --alpha(var(--color-pink-500) / 5%);
  --color-pink-tint-10: --alpha(var(--color-pink-500) / 10%);

  /* Orange scale */
  --color-orange-25: #FFF9F5;
  --color-orange-50: #FFF4ED;
  --color-orange-100: #FFE6D5;
  --color-orange-200: #FFD6AE;
  --color-orange-300: #FF9C66;
  --color-orange-400: #FF692E;
  --color-orange-500: #FF4405;
  --color-orange-600: #E62E05;
  --color-orange-700: #BC1B06;
  --color-orange-800: #97180C;
  --color-orange-900: #771A0D;
  --color-orange-tint-5: --alpha(var(--color-orange-500) / 5%);
  --color-orange-tint-10: --alpha(var(--color-orange-500) / 10%);

  /* Border radius overrides */
  --border-radius-md: 8px;
  --border-radius-lg: 10px;

  --shadow-xs: 0px 1px 2px 0px --alpha(var(--color-black) / 6%);
  --shadow-sm: 0px 1px 6px 0px --alpha(var(--color-black) / 6%);
  --shadow-md: 0px 4px 8px -2px --alpha(var(--color-black) / 6%);
  --shadow-lg: 0px 12px 16px -4px --alpha(var(--color-black) / 6%);
  --shadow-xl: 0px 20px 24px -4px --alpha(var(--color-black) / 6%);

  --animate-stroke-fill: stroke-fill 3s 300ms forwards;

  @keyframes stroke-fill {
    0% {
      stroke-dashoffset: 43.9822971503;
    }

    100% {
      stroke-dashoffset: 0;
    }
  } 
}

/* Specific override for strong tags in prose under dark mode */
.prose:where([data-theme=dark], [data-theme=dark] *) strong {
  color: theme(colors.white) !important;
}

@layer base {
  [data-theme="dark"] { 
    --color-success: var(--color-green-500);
    --color-warning: var(--color-yellow-400);
    --color-destructive: var(--color-red-400);
    --color-shadow: --alpha(var(--color-white) / 8%);

    /* Dark mode overrides for colors used in Stimulus controllers with SVGs */
    --budget-unused-fill: var(--color-gray-500);
    --budget-unallocated-fill: var(--color-gray-700);

    --shadow-xs: 0px 1px 2px 0px --alpha(var(--color-white) / 8%);
    --shadow-sm: 0px 1px 6px 0px --alpha(var(--color-white) / 8%);
    --shadow-md: 0px 4px 8px -2px --alpha(var(--color-white) / 8%);
    --shadow-lg: 0px 12px 16px -4px --alpha(var(--color-white) / 8%);
    --shadow-xl: 0px 20px 24px -4px --alpha(var(--color-white) / 8%);
  }

  html {
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
  }

  button {
    @apply cursor-pointer focus-visible:outline-gray-900;
  }

  hr {
    @apply text-gray-200;
  }

  /* We control the sizing through DialogComponent, so reset this value */
  dialog:modal {
    max-width: 100dvw;
    max-height: 100dvh;
  }

  details>summary::-webkit-details-marker {
    @apply hidden;
  }

  details>summary {
    @apply list-none;
  }

  input[type='radio'] {
    @apply border-gray-300 text-indigo-600 focus:ring-indigo-600;
    /* Default light mode */

    @variant theme-dark {
      /* Dark mode radio button base and checked styles */
      @apply border-gray-600 bg-gray-700 checked:bg-blue-500 focus:ring-blue-500 focus:ring-offset-gray-800;
    }
  }
}

@layer components {
  /* Forms */
  .form-field {
    @apply flex flex-col gap-1 relative px-3 py-2 rounded-md border bg-container border-secondary shadow-xs w-full;
    @apply focus-within:border-secondary focus-within:shadow-none focus-within:ring-4 focus-within:ring-alpha-black-200;
    @apply transition-all duration-300;

    @variant theme-dark {
      @apply focus-within:ring-alpha-white-300;
    }

    /* Add styles for multiple select within form fields */
    select[multiple] {
      @apply py-2 pr-2 space-y-0.5 overflow-y-auto;

      option {
        @apply py-2 rounded-md;
      }

      option:checked {
        @apply after:content-['\2713'] bg-container-inset after:text-gray-500 after:ml-2;
      }

      option:active,
      option:focus {
        @apply bg-container-inset;
      }
    }
  }

  /* New form field structure components */
  .form-field__header {
    @apply flex items-center justify-between gap-2;
  }

  .form-field__body {
    @apply flex flex-col gap-1;
  }

  .form-field__actions {
    @apply flex items-center gap-1;
  }

  .form-field__label {
    @apply block text-xs text-secondary peer-disabled:text-subdued;
  }

  .form-field__input {
    @apply text-primary border-none bg-container text-sm opacity-100 w-full p-0;
    @apply focus:opacity-100 focus:outline-hidden focus:ring-0;
    @apply placeholder-shown:opacity-50;
    @apply disabled:text-subdued;
    @apply text-ellipsis overflow-hidden whitespace-nowrap;
    @apply transition-opacity duration-300;
    @apply placeholder:text-subdued;

    @variant theme-dark {
      &::-webkit-calendar-picker-indicator {
        filter: invert(1);
        cursor: pointer;
      }
    }
  }
  
  select.form-field__input {
    @apply pr-10 appearance-none;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
    background-position: right -0.15rem center;
    background-repeat: no-repeat;
    background-size: 1.25rem 1.25rem;
  }

  .form-field__radio {
    @apply text-primary;
  }

  .form-field__submit {
    @apply cursor-pointer rounded-lg bg-surface p-3 text-center text-white hover:bg-surface-hover;
  }

  /* Checkboxes */
  .checkbox {
    &[type='checkbox'] {
      @apply rounded-sm;
      @apply transition-colors duration-300;
    }
  }

  .checkbox--light {
    &[type='checkbox'] {
      @apply border-alpha-black-200 checked:bg-gray-900 checked:ring-gray-900 focus:ring-gray-900 focus-visible:ring-gray-900 checked:hover:bg-gray-500;
    }

    &[type='checkbox']:disabled {
      @apply cursor-not-allowed opacity-80 bg-gray-50 border-gray-200 checked:bg-gray-400 checked:ring-gray-400;
    }

    @variant theme-dark {
      &[type='checkbox'] {
        @apply ring-gray-900 checked:text-white;
        background-color: var(--color-gray-600);
      }
  
      &[type='checkbox']:disabled {
        @apply cursor-not-allowed opacity-80 ring-gray-600;
      }
  
      &[type='checkbox']:checked {
        background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
        background-color: var(--color-gray-600);
      }
    }
  }

  .checkbox--dark {
    &[type='checkbox'] {
      @apply ring-gray-900 checked:text-white;
    }

    &[type='checkbox']:disabled {
      @apply cursor-not-allowed opacity-80 ring-gray-600;
    }

    &[type='checkbox']:checked {
      background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='111827' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
    }
  }

  /* Tooltips */
  .tooltip {
    @apply hidden absolute;
  }

  .qrcode svg path {
    fill: var(--color-black);
    @variant theme-dark {
      fill: var(--color-white);
    }
  }
}

================================================
FILE: app/assets/tailwind/simonweb_pickr.css
================================================
/*! Pickr 1.9.1 MIT | https://github.com/Simonwep/pickr */
.pickr{position:relative;overflow:visible;transform:translateY(0)}.pickr *{box-sizing:border-box;outline:none;border:none;-webkit-appearance:none}.pickr .pcr-button{position:relative;height:2em;width:2em;padding:.5em;cursor:pointer;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif;border-radius:.15em;background:url("data:image/svg+xml;utf8, <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 50 50\" stroke=\"%2342445A\" stroke-width=\"5px\" stroke-linecap=\"round\"><path d=\"M45,45L5,5\"></path><path d=\"M45,5L5,45\"></path></svg>") no-repeat center;background-size:0;transition:all .3s}.pickr .pcr-button::before{position:absolute;content:"";top:0;left:0;width:100%;height:100%;background:url("data:image/svg+xml;utf8, <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 2 2\"><path fill=\"white\" d=\"M1,0H2V1H1V0ZM0,1H1V2H0V1Z\"/><path fill=\"gray\" d=\"M0,0H1V1H0V0ZM1,1H2V2H1V1Z\"/></svg>");background-size:.5em;border-radius:.15em;z-index:-1}.pickr .pcr-button::before{z-index:initial}.pickr .pcr-button::after{position:absolute;content:"";top:0;left:0;height:100%;width:100%;transition:background .3s;background:var(--pcr-color);border-radius:.15em}.pickr .pcr-button.clear{background-size:70%}.pickr .pcr-button.clear::before{opacity:0}.pickr .pcr-button.clear:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color)}.pickr .pcr-button.disabled{cursor:not-allowed}.pickr *,.pcr-app *{box-sizing:border-box;outline:none;border:none;-webkit-appearance:none}.pickr input:focus,.pickr input.pcr-active,.pickr button:focus,.pickr button.pcr-active,.pcr-app input:focus,.pcr-app input.pcr-active,.pcr-app button:focus,.pcr-app button.pcr-active{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color)}.pickr .pcr-palette,.pickr .pcr-slider,.pcr-app .pcr-palette,.pcr-app .pcr-slider{transition:box-shadow .3s}.pickr .pcr-palette:focus,.pickr .pcr-slider:focus,.pcr-app .pcr-palette:focus,.pcr-app .pcr-slider:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(0,0,0,.25)}.pcr-app{position:fixed;display:flex;flex-direction:column;z-index:10000;border-radius:.1em;background:#fff;opacity:0;visibility:hidden;transition:opacity .3s,visibility 0s .3s;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif;box-shadow:0 .15em 1.5em 0 rgba(0,0,0,.1),0 0 1em 0 rgba(0,0,0,.03);left:0;top:0}.pcr-app.visible{transition:opacity .3s;visibility:visible;opacity:1}.pcr-app .pcr-swatches{display:flex;flex-wrap:wrap;margin-top:.75em}.pcr-app .pcr-swatches.pcr-last{margin:0}@supports(display: grid){.pcr-app .pcr-swatches{display:grid;align-items:center;grid-template-columns:repeat(auto-fit, 1.75em)}}.pcr-app .pcr-swatches>button{font-size:1em;position:relative;width:calc(1.75em - 5px);height:calc(1.75em - 5px);border-radius:.15em;cursor:pointer;margin:2.5px;flex-shrink:0;justify-self:center;transition:all .15s;overflow:hidden;background:rgba(0,0,0,0);z-index:1}.pcr-app .pcr-swatches>button::before{position:absolute;content:"";top:0;left:0;width:100%;height:100%;background:url("data:image/svg+xml;utf8, <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 2 2\"><path fill=\"white\" d=\"M1,0H2V1H1V0ZM0,1H1V2H0V1Z\"/><path fill=\"gray\" d=\"M0,0H1V1H0V0ZM1,1H2V2H1V1Z\"/></svg>");background-size:6px;border-radius:.15em;z-index:-1}.pcr-app .pcr-swatches>button::after{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background:var(--pcr-color);border:1px solid rgba(0,0,0,.05);border-radius:.15em;box-sizing:border-box}.pcr-app .pcr-swatches>button:hover{filter:brightness(1.05)}.pcr-app .pcr-swatches>button:not(.pcr-active){box-shadow:none}.pcr-app .pcr-interaction{display:flex;flex-wrap:wrap;align-items:center;margin:0 -0.2em 0 -0.2em}.pcr-app .pcr-interaction>*{margin:0 .2em}.pcr-app .pcr-interaction input{letter-spacing:.07em;font-size:.75em;text-align:center;cursor:pointer;color:#75797e;background:#f1f3f4;border-radius:.15em;transition:all .15s;padding:.45em .5em;margin-top:.75em}.pcr-app .pcr-interaction input:hover{filter:brightness(0.975)}.pcr-app .pcr-interaction input:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(66,133,244,.75)}.pcr-app .pcr-interaction .pcr-result{color:#75797e;text-align:left;flex:1 1 8em;min-width:8em;transition:all .2s;border-radius:.15em;background:#f1f3f4;cursor:text}.pcr-app .pcr-interaction .pcr-result::-moz-selection{background:#4285f4;color:#fff}.pcr-app .pcr-interaction .pcr-result::selection{background:#4285f4;color:#fff}.pcr-app .pcr-interaction .pcr-type.active{color:#fff;background:#4285f4}.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear{color:#fff;width:auto}.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear{color:#fff}.pcr-app .pcr-interaction .pcr-save:hover,.pcr-app .pcr-interaction .pcr-cancel:hover,.pcr-app .pcr-interaction .pcr-clear:hover{filter:brightness(0.925)}.pcr-app .pcr-interaction .pcr-save{background:#4285f4}.pcr-app .pcr-interaction .pcr-clear,.pcr-app .pcr-interaction .pcr-cancel{background:#f44250}.pcr-app .pcr-interaction .pcr-clear:focus,.pcr-app .pcr-interaction .pcr-cancel:focus{box-shadow:0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(244,66,80,.75)}.pcr-app .pcr-selection .pcr-picker{position:absolute;height:18px;width:18px;border:2px solid #fff;border-radius:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none}.pcr-app .pcr-selection .pcr-color-palette,.pcr-app .pcr-selection .pcr-color-chooser,.pcr-app .pcr-selection .pcr-color-opacity{position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;display:flex;flex-direction:column;cursor:grab;cursor:-webkit-grab}.pcr-app .pcr-selection .pcr-color-palette:active,.pcr-app .pcr-selection .pcr-color-chooser:active,.pcr-app .pcr-selection .pcr-color-opacity:active{cursor:grabbing;cursor:-webkit-grabbing}.pcr-app[data-theme=monolith]{width:14.25em;max-width:95vw;padding:.8em}.pcr-app[data-theme=monolith] .pcr-selection{display:flex;flex-direction:column;justify-content:space-between;flex-grow:1}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-preview{position:relative;z-index:1;width:100%;height:1em;display:flex;flex-direction:row;justify-content:space-between;margin-bottom:.5em}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-preview::before{position:absolute;content:"";top:0;left:0;width:100%;height:100%;background:url("data:image/svg+xml;utf8, <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 2 2\"><path fill=\"white\" d=\"M1,0H2V1H1V0ZM0,1H1V2H0V1Z\"/><path fill=\"gray\" d=\"M0,0H1V1H0V0ZM1,1H2V2H1V1Z\"/></svg>");background-size:.5em;border-radius:.15em;z-index:-1}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-preview .pcr-last-color{cursor:pointer;transition:background-color .3s,box-shadow .3s;border-radius:.15em 0 0 .15em;z-index:2}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-preview .pcr-current-color{border-radius:0 .15em .15em 0}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-preview .pcr-last-color,.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-preview .pcr-current-color{background:var(--pcr-color);width:50%;height:100%}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-palette{width:100%;height:8em;z-index:1}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-palette .pcr-palette{border-radius:.15em;width:100%;height:100%}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-palette .pcr-palette::before{position:absolute;content:"";top:0;left:0;width:100%;height:100%;background:url("data:image/svg+xml;utf8, <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 2 2\"><path fill=\"white\" d=\"M1,0H2V1H1V0ZM0,1H1V2H0V1Z\"/><path fill=\"gray\" d=\"M0,0H1V1H0V0ZM1,1H2V2H1V1Z\"/></svg>");background-size:.5em;border-radius:.15em;z-index:-1}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-chooser,.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-opacity{height:.5em;margin-top:.75em}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-chooser .pcr-picker,.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-opacity .pcr-picker{top:50%;transform:translateY(-50%)}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-chooser .pcr-slider,.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-opacity .pcr-slider{flex-grow:1;border-radius:50em}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-chooser .pcr-slider{background:linear-gradient(to right, hsl(0, 100%, 50%), hsl(60, 100%, 50%), hsl(120, 100%, 50%), hsl(180, 100%, 50%), hsl(240, 100%, 50%), hsl(300, 100%, 50%), hsl(0, 100%, 50%))}.pcr-app[data-theme=monolith] .pcr-selection .pcr-color-opacity .pcr-slider{background:linear-gradient(to right, transparent, black),url("data:image/svg+xml;utf8, <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 2 2\"><path fill=\"white\" d=\"M1,0H2V1H1V0ZM0,1H1V2H0V1Z\"/><path fill=\"gray\" d=\"M0,0H1V1H0V0ZM1,1H2V2H1V1Z\"/></svg>");background-size:100%,.25em}

================================================
FILE: app/channels/application_cable/channel.rb
================================================
module ApplicationCable
  class Channel < ActionCable::Channel::Base
  end
end


================================================
FILE: app/channels/application_cable/connection.rb
================================================
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    rescue_from StandardError, with: :report_error

    private
      def report_error(e)
        Sentry.capture_exception(e)
      end
  end
end


================================================
FILE: app/components/DS/alert.html.erb
================================================
<div class="<%= container_classes %>">
  <%= helpers.icon icon_name, size: "sm", color: icon_color, class: "shrink-0" %>

  <div class="flex-1 text-sm">
    <%= message %>
  </div>
</div>


================================================
FILE: app/components/DS/alert.rb
================================================
class DS::Alert < DesignSystemComponent
  def initialize(message:, variant: :info)
    @message = message
    @variant = variant
  end

  private
    attr_reader :message, :variant

    def container_classes
      base_classes = "flex items-start gap-3 p-4 rounded-lg border"

      variant_classes = case variant
      when :info
        "bg-blue-50 text-blue-700 border-blue-200 theme-dark:bg-blue-900/20 theme-dark:text-blue-400 theme-dark:border-blue-800"
      when :success
        "bg-green-50 text-green-700 border-green-200 theme-dark:bg-green-900/20 theme-dark:text-green-400 theme-dark:border-green-800"
      when :warning
        "bg-yellow-50 text-yellow-700 border-yellow-200 theme-dark:bg-yellow-900/20 theme-dark:text-yellow-400 theme-dark:border-yellow-800"
      when :error, :destructive
        "bg-red-50 text-red-700 border-red-200 theme-dark:bg-red-900/20 theme-dark:text-red-400 theme-dark:border-red-800"
      end

      "#{base_classes} #{variant_classes}"
    end

    def icon_name
      case variant
      when :info
        "info"
      when :success
        "check-circle"
      when :warning
        "alert-triangle"
      when :error, :destructive
        "x-circle"
      end
    end

    def icon_color
      case variant
      when :success
        "success"
      when :warning
        "warning"
      when :error, :destructive
        "destructive"
      else
        "blue-600"
      end
    end
end


================================================
FILE: app/components/DS/button.html.erb
================================================
<%= container do %>
  <% if icon && (icon_position != :right) %>
    <%= helpers.icon(icon, size: size, color: icon_color, class: icon_classes) %>
  <% end %>

  <% unless icon_only? %>
    <%= text %>
  <% end %>

  <% if icon && icon_position == :right %>
    <%= helpers.icon(icon, size: size, color: icon_color) %>
  <% end %>
<% end %>


================================================
FILE: app/components/DS/button.rb
================================================
# frozen_string_literal: true

# An extension to `button_to` helper.  All options are passed through to the `button_to` helper with some additional
# options available.
class DS::Button < DS::Buttonish
  attr_reader :confirm

  def initialize(confirm: nil, **opts)
    super(**opts)
    @confirm = confirm
  end

  def container(&block)
    if href.present?
      button_to(href, **merged_opts, &block)
    else
      content_tag(:button, **merged_opts, &block)
    end
  end

  private
    def merged_opts
      merged_opts = opts.dup || {}
      extra_classes = merged_opts.delete(:class)
      href = merged_opts.delete(:href)
      data = merged_opts.delete(:data) || {}

      if confirm.present?
        data = data.merge(turbo_confirm: confirm.to_data_attribute)
      end

      if frame.present?
        data = data.merge(turbo_frame: frame)
      end

      merged_opts.merge(
        class: class_names(container_classes, extra_classes),
        data: data
      )
    end
end


================================================
FILE: app/components/DS/buttonish.rb
================================================
class DS::Buttonish < DesignSystemComponent
  VARIANTS = {
    primary: {
      container_classes: "text-inverse bg-inverse hover:bg-inverse-hover disabled:bg-gray-500 theme-dark:disabled:bg-gray-400",
      icon_classes: "fg-inverse"
    },
    secondary: {
      container_classes: "text-primary bg-gray-50 theme-dark:bg-gray-700 hover:bg-gray-100 theme-dark:hover:bg-gray-600 disabled:bg-gray-200 theme-dark:disabled:bg-gray-600",
      icon_classes: "fg-primary"
    },
    destructive: {
      container_classes: "text-inverse bg-red-500 theme-dark:bg-red-400 hover:bg-red-600 theme-dark:hover:bg-red-500 disabled:bg-red-200 theme-dark:disabled:bg-red-600",
      icon_classes: "fg-white"
    },
    outline: {
      container_classes: "text-primary border border-secondary bg-transparent hover:bg-surface-hover",
      icon_classes: "fg-gray"
    },
    outline_destructive: {
      container_classes: "text-destructive border border-secondary bg-transparent hover:bg-gray-100 theme-dark:hover:bg-gray-700",
      icon_classes: "fg-gray"
    },
    ghost: {
      container_classes: "text-primary bg-transparent hover:bg-gray-100 theme-dark:hover:bg-gray-700",
      icon_classes: "fg-gray"
    },
    icon: {
      container_classes: "hover:bg-gray-100 theme-dark:hover:bg-gray-700",
      icon_classes: "fg-gray"
    },
    icon_inverse: {
      container_classes: "bg-inverse hover:bg-inverse-hover",
      icon_classes: "fg-inverse"
    }
  }.freeze

  SIZES = {
    sm: {
      container_classes: "px-2 py-1",
      icon_container_classes: "inline-flex items-center justify-center w-8 h-8",
      radius_classes: "rounded-md",
      text_classes: "text-sm"
    },
    md: {
      container_classes: "px-3 py-2",
      icon_container_classes: "inline-flex items-center justify-center w-9 h-9",
      radius_classes: "rounded-lg",
      text_classes: "text-sm"
    },
    lg: {
      container_classes: "px-4 py-3",
      icon_container_classes: "inline-flex items-center justify-center w-10 h-10",
      radius_classes: "rounded-xl",
      text_classes: "text-base"
    }
  }.freeze

  attr_reader :variant, :size, :href, :icon, :icon_position, :text, :full_width, :extra_classes, :frame, :opts

  def initialize(variant: :primary, size: :md, href: nil, text: nil, icon: nil, icon_position: :left, full_width: false, frame: nil, **opts)
    @variant = variant.to_s.underscore.to_sym
    @size = size.to_sym
    @href = href
    @icon = icon
    @icon_position = icon_position.to_sym
    @text = text
    @full_width = full_width
    @extra_classes = opts.delete(:class)
    @frame = frame
    @opts = opts
  end

  def call
    raise NotImplementedError, "Buttonish is an abstract class and cannot be instantiated directly."
  end

  def container_classes(override_classes = nil)
    class_names(
      "font-medium whitespace-nowrap",
      merged_base_classes,
      full_width ? "w-full justify-center" : nil,
      container_size_classes,
      size_data.dig(:text_classes),
      variant_data.dig(:container_classes)
    )
  end

  def container_size_classes
    icon_only? ? size_data.dig(:icon_container_classes) : size_data.dig(:container_classes)
  end

  def icon_color
    # Map variant to icon color for the icon helper
    case variant
    when :primary, :icon_inverse
      :white
    when :destructive, :outline_destructive
      :destructive
    else
      :default
    end
  end

  def icon_classes
    class_names(
      variant_data.dig(:icon_classes)
    )
  end

  def icon_only?
    variant.in?([ :icon, :icon_inverse ])
  end

  private
    def variant_data
      self.class::VARIANTS.dig(variant)
    end

    def size_data
      self.class::SIZES.dig(size)
    end

    # Make sure that user can override common classes like `hidden`
    def merged_base_classes
      base_display_classes = "inline-flex items-center gap-1"
      base_radius_classes = size_data.dig(:radius_classes)

      extra_classes_list = (extra_classes || "").split

      has_display_override = extra_classes_list.any? { |c| permitted_display_override_classes.include?(c) }
      has_radius_override = extra_classes_list.any? { |c| permitted_radius_override_classes.include?(c) }

      base_classes = []

      unless has_display_override
        base_classes << base_display_classes
      end

      unless has_radius_override
        base_classes << base_radius_classes
      end

      class_names(
        base_classes,
        extra_classes
      )
    end

    def permitted_radius_override_classes
      [ "rounded-full" ]
    end

    def permitted_display_override_classes
      [ "hidden", "flex" ]
    end
end


================================================
FILE: app/components/DS/dialog.html.erb
================================================
<%= wrapper_element do %>
  <%= tag.dialog class: "w-full h-full bg-transparent theme-dark:backdrop:bg-alpha-black-900 backdrop:bg-overlay #{drawer? ? "lg:p-3" : "lg:p-1"}", **merged_opts do %>
    <%= tag.div class: dialog_outer_classes do %>
      <%= tag.div class: dialog_inner_classes, data: { DS__dialog_target: "content" } do %>
        <div class="grow overflow-y-auto py-4 space-y-4 flex flex-col">
          <% if header? %>
            <%= header %>
          <% end %>

          <% if body? %>
            <div class="px-4 grow">
              <%= body %>

              <% if sections.any? %>
                <div class="space-y-4">
                  <% sections.each do |section| %>
                    <%= section %>
                  <% end %>
                </div>
              <% end %>
            </div>
          <% end %>

          <%# Optional, for customizing dialogs %>
          <%= content %>
        </div>

        <% if actions? %>
          <div class="flex items-center gap-2 justify-end p-4">
            <% actions.each do |action| %>
              <%= action %>
            <% end %>
          </div>
        <% end %>
      <% end %>
    <% end %>
  <% end %>
<% end %>


================================================
FILE: app/components/DS/dialog.rb
================================================
class DS::Dialog < DesignSystemComponent
  renders_one :header, ->(title: nil, subtitle: nil, hide_close_icon: false, **opts, &block) do
    content_tag(:header, class: "px-4 flex flex-col gap-2", **opts) do
      title_div = content_tag(:div, class: "flex items-center justify-between gap-2") do
        title = content_tag(:h2, title, class: class_names("font-medium text-primary", drawer? ? "text-lg" : "")) if title
        close_icon = render DS::Button.new(variant: "icon", class: "ml-auto", icon: "x", tabindex: "-1", data: { action: "DS--dialog#close" }) unless hide_close_icon
        safe_join([ title, close_icon ].compact)
      end

      subtitle = content_tag(:p, subtitle, class: "text-sm text-secondary") if subtitle

      block_content = capture(&block) if block

      safe_join([ title_div, subtitle, block_content ].compact)
    end
  end

  renders_one :body

  renders_many :actions, ->(cancel_action: false, **button_opts) do
    merged_opts = if cancel_action
      button_opts.merge(type: "button", data: { action: "DS--dialog#close" })
    else
      button_opts
    end

    render DS::Button.new(**merged_opts)
  end

  renders_many :sections, ->(title:, **disclosure_opts, &block) do
    render DS::Disclosure.new(title: title, align: :right, **disclosure_opts) do
      block.call
    end
  end

  attr_reader :variant, :auto_open, :reload_on_close, :width, :disable_frame, :opts

  VARIANTS = %w[modal drawer].freeze
  WIDTHS = {
    sm: "lg:max-w-[300px]",
    md: "lg:max-w-[550px]",
    lg: "lg:max-w-[700px]",
    full: "lg:max-w-full"
  }.freeze

  def initialize(variant: "modal", auto_open: true, reload_on_close: false, width: "md", frame: nil, disable_frame: false, **opts)
    @variant = variant.to_sym
    @auto_open = auto_open
    @reload_on_close = reload_on_close
    @width = width.to_sym
    @frame = frame
    @disable_frame = disable_frame
    @opts = opts
  end

  def frame
    @frame || variant
  end

  # Caller must "opt-out" of using the default turbo-frame based on the variant
  def wrapper_element(&block)
    if disable_frame
      content_tag(:div, &block)
    else
      content_tag("turbo-frame", id: frame, &block)
    end
  end

  def dialog_outer_classes
    variant_classes = if drawer?
      "items-end justify-end"
    else
      "items-center justify-center"
    end

    class_names(
      "flex h-full w-full",
      variant_classes
    )
  end

  def dialog_inner_classes
    variant_classes = if drawer?
      "lg:w-[550px] h-full"
    else
      class_names(
        "max-h-full",
        WIDTHS[width]
      )
    end

    class_names(
      "flex flex-col bg-container rounded-xl shadow-border-xs mx-3 lg:mx-0 w-full overflow-hidden",
      variant_classes
    )
  end

  def merged_opts
    merged_opts = opts.dup
    data = merged_opts.delete(:data) || {}

    data[:controller] = [ "DS--dialog", "hotkey", data[:controller] ].compact.join(" ")
    data[:DS__dialog_auto_open_value] = auto_open
    data[:DS__dialog_reload_on_close_value] = reload_on_close
    data[:action] = [ "mousedown->DS--dialog#clickOutside", data[:action] ].compact.join(" ")
    data[:hotkey] = "esc:DS--dialog#close"
    merged_opts[:data] = data

    merged_opts
  end

  def drawer?
    variant == :drawer
  end
end


================================================
FILE: app/components/DS/dialog_controller.js
================================================
import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="dialog"
export default class extends Controller {
  static targets = ["content"]

  static values = {
    autoOpen: { type: Boolean, default: false },
    reloadOnClose: { type: Boolean, default: false },
  };

  connect() {
    if (this.element.open) return;
    if (this.autoOpenValue) {
      this.element.showModal();
    }
  }
  
  // If the user clicks anywhere outside of the visible content, close the dialog
  clickOutside(e) {
    if (!this.contentTarget.contains(e.target)) {
      this.close();
    }
  }

  close() {
    this.element.close();

    if (this.reloadOnCloseValue) {
      Turbo.visit(window.location.href);
    }
  }
}


================================================
FILE: app/components/DS/disclosure.html.erb
================================================
<details class="group" <%= "open" if open %>>
  <%= tag.summary class: class_names(
    "px-3 py-2 rounded-xl cursor-pointer flex items-center justify-between bg-surface"
  ) do %>
    <% if summary_content? %>
      <%= summary_content %>
    <% else %>
      <div class="flex items-center gap-3">
        <% if align == :left %>
          <%= helpers.icon "chevron-right", class: "group-open:transform group-open:rotate-90" %>
        <% end %>

        <%= tag.span class: class_names("font-medium", align == :left ? "text-sm text-primary" : "text-xs uppercase text-secondary") do %>
          <%= title %>
        <% end %>
      </div>

      <% if align == :right %>
        <%= helpers.icon "chevron-down", class: "group-open:transform group-open:rotate-180" %>
      <% end %>
    <% end %>
  <% end %>

  <div class="mt-2">
    <%= content %>
  </div>
</details>


================================================
FILE: app/components/DS/disclosure.rb
================================================
class DS::Disclosure < DesignSystemComponent
  renders_one :summary_content

  attr_reader :title, :align, :open, :opts

  def initialize(title: nil, align: "right", open: false, **opts)
    @title = title
    @align = align.to_sym
    @open = open
    @opts = opts
  end
end


================================================
FILE: app/components/DS/filled_icon.html.erb
================================================
<%= tag.div style: transparent? ? container_styles : nil,
            class: container_classes do %>
  <% if icon %>
    <%= helpers.icon(icon, size: icon_size, color: "current") %>
  <% elsif text %>
    <%= tag.span text.first, class: text_classes %>
  <% end %>
<% end %>


================================================
FILE: app/components/DS/filled_icon.rb
================================================
class DS::FilledIcon < DesignSystemComponent
  attr_reader :icon, :text, :hex_color, :size, :rounded, :variant

  VARIANTS = %i[default text surface container inverse].freeze

  SIZES = {
    sm: {
      container_size: "w-6 h-6",
      container_radius: "rounded-md",
      icon_size: "sm",
      text_size: "text-xs"
    },
    md: {
      container_size: "w-8 h-8",
      container_radius: "rounded-lg",
      icon_size: "md",
      text_size: "text-xs"
    },
    lg: {
      container_size: "w-9 h-9",
      container_radius: "rounded-xl",
      icon_size: "lg",
      text_size: "text-sm"
    }
  }.freeze

  def initialize(variant: :default, icon: nil, text: nil, hex_color: nil, size: "md", rounded: false)
    @variant = variant.to_sym
    @icon = icon
    @text = text
    @hex_color = hex_color
    @size = size.to_sym
    @rounded = rounded
  end

  def container_classes
    class_names(
      "flex justify-center items-center shrink-0",
      size_classes,
      radius_classes,
      transparent? ? "border" : solid_bg_class
    )
  end

  def icon_size
    SIZES[size][:icon_size]
  end

  def text_classes
    class_names(
      "text-center font-medium uppercase",
      SIZES[size][:text_size]
    )
  end

  def container_styles
    <<~STYLE.strip
      background-color: #{transparent_bg_color};
      border-color: #{transparent_border_color};
      color: #{custom_fg_color};
    STYLE
  end

  def transparent?
    variant.in?(%i[default text])
  end

  private
    def solid_bg_class
      case variant
      when :surface
        "bg-surface-inset"
      when :container
        "bg-container-inset"
      when :inverse
        "bg-container"
      end
    end

    def size_classes
      SIZES[size][:container_size]
    end

    def radius_classes
      rounded ? "rounded-full" : SIZES[size][:container_radius]
    end

    def custom_fg_color
      hex_color || "var(--color-gray-500)"
    end

    def transparent_bg_color
      "color-mix(in oklab, #{custom_fg_color} 10%, transparent)"
    end

    def transparent_border_color
      "color-mix(in oklab, #{custom_fg_color} 10%, transparent)"
    end
end


================================================
FILE: app/components/DS/link.html.erb
================================================
<%= link_to href, **merged_opts do %>
  <% if icon && (icon_position != "right") %>
    <%= helpers.icon(icon, size: size, color: icon_color) %>
  <% end %>

  <% unless icon_only? %>
    <%= text %>
  <% end %>

  <% if icon && icon_position == "right" %>
    <%= helpers.icon(icon, size: size, color: icon_color) %>
  <% end %>
<% end %>


================================================
FILE: app/components/DS/link.rb
================================================
# An extension to `link_to` helper.  All options are passed through to the `link_to` helper with some additional
# options available.
class DS::Link < DS::Buttonish
  attr_reader :frame

  VARIANTS = VARIANTS.reverse_merge(
    default: {
      container_classes: "",
      icon_classes: "fg-gray"
    }
  ).freeze

  def merged_opts
    merged_opts = opts.dup || {}
    data = merged_opts.delete(:data) || {}

    if frame
      data = data.merge(turbo_frame: frame)
    end

    merged_opts.merge(
      class: class_names(container_classes, extra_classes),
      data: data
    )
  end

  private
    def container_size_classes
      super unless variant == :default
    end
end


================================================
FILE: app/components/DS/menu.html.erb
================================================
<%= tag.div data: { controller: "DS--menu", DS__menu_placement_value: placement, DS__menu_offset_value: offset, testid: testid } do %>
  <% if variant == :icon %>
    <%= render DS::Button.new(variant: "icon", icon: icon_vertical ? "more-vertical" : "more-horizontal", data: { DS__menu_target: "button" }) %>
  <% elsif variant == :button %>
    <%= button %>
  <% elsif variant == :avatar %>
    <button data-DS--menu-target="button">
      <div class="w-9 h-9 cursor-pointer">
        <%= render "settings/user_avatar", avatar_url: avatar_url, initials: initials %>
      </div>
    </button>
  <% end %>

  <div data-DS--menu-target="content" class="px-2 lg:px-0 max-w-full hidden z-50">
    <div class="mx-auto min-w-[200px] shadow-border-xs bg-container rounded-lg">
      <%= header %>

      <%= tag.div class: class_names("py-1" => !no_padding) do %>
        <% items.each do |item| %>
          <%= item %>
        <% end %>

        <%= custom_content %>
      <% end %>
    </div>
  </div>
<% end %>


================================================
FILE: app/components/DS/menu.rb
================================================
# frozen_string_literal: true

class DS::Menu < DesignSystemComponent
  attr_reader :variant, :avatar_url, :initials, :placement, :offset, :icon_vertical, :no_padding, :testid

  renders_one :button, ->(**button_options, &block) do
    options_with_target = button_options.merge(data: { DS__menu_target: "button" })

    if block
      content_tag(:button, **options_with_target, &block)
    else
      DS::Button.new(**options_with_target)
    end
  end

  renders_one :header, ->(&block) do
    content_tag(:div, class: "border-b border-tertiary", &block)
  end

  renders_one :custom_content

  renders_many :items, DS::MenuItem

  VARIANTS = %i[icon button avatar].freeze

  def initialize(variant: "icon", avatar_url: nil, initials: nil, placement: "bottom-end", offset: 12, icon_vertical: false, no_padding: false, testid: nil)
    @variant = variant.to_sym
    @avatar_url = avatar_url
    @initials = initials
    @placement = placement
    @offset = offset
    @icon_vertical = icon_vertical
    @no_padding = no_padding
    @testid = testid

    raise ArgumentError, "Invalid variant: #{@variant}" unless VARIANTS.include?(@variant)
  end
end


================================================
FILE: app/components/DS/menu_controller.js
================================================
import {
  autoUpdate,
  computePosition,
  flip,
  offset,
  shift,
} from "@floating-ui/dom";
import { Controller } from "@hotwired/stimulus";

/**
 * A "menu" can contain arbitrary content including non-clickable items, links, buttons, and forms.
 */
export default class extends Controller {
  static targets = ["button", "content"];

  static values = {
    show: Boolean,
    placement: { type: String, default: "bottom-end" },
    offset: { type: Number, default: 6 },
  };

  connect() {
    this.show = this.showValue;
    this.boundUpdate = this.update.bind(this);
    this.addEventListeners();
    this.startAutoUpdate();
  }

  disconnect() {
    this.removeEventListeners();
    this.stopAutoUpdate();
    this.close();
  }

  addEventListeners() {
    this.buttonTarget.addEventListener("click", this.toggle);
    this.element.addEventListener("keydown", this.handleKeydown);
    document.addEventListener("click", this.handleOutsideClick);
    document.addEventListener("turbo:load", this.handleTurboLoad);
  }

  removeEventListeners() {
    this.buttonTarget.removeEventListener("click", this.toggle);
    this.element.removeEventListener("keydown", this.handleKeydown);
    document.removeEventListener("click", this.handleOutsideClick);
    document.removeEventListener("turbo:load", this.handleTurboLoad);
  }

  handleTurboLoad = () => {
    if (!this.show) this.close();
  };

  handleOutsideClick = (event) => {
    if (this.show && !this.element.contains(event.target)) this.close();
  };

  handleKeydown = (event) => {
    if (event.key === "Escape") {
      this.close();
      this.buttonTarget.focus();
    }
  };

  toggle = () => {
    this.show = !this.show;
    this.contentTarget.classList.toggle("hidden", !this.show);
    if (this.show) {
      this.update();
      this.focusFirstElement();
    }
  };

  close() {
    this.show = false;
    this.contentTarget.classList.add("hidden");
  }

  focusFirstElement() {
    const focusableElements =
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
    const firstFocusableElement =
      this.contentTarget.querySelectorAll(focusableElements)[0];
    if (firstFocusableElement) {
      firstFocusableElement.focus();
    }
  }

  startAutoUpdate() {
    if (!this._cleanup) {
      this._cleanup = autoUpdate(
        this.buttonTarget,
        this.contentTarget,
        this.boundUpdate,
      );
    }
  }

  stopAutoUpdate() {
    if (this._cleanup) {
      this._cleanup();
      this._cleanup = null;
    }
  }

  update() {
    computePosition(this.buttonTarget, this.contentTarget, {
      placement: this.placementValue,
      middleware: [offset(this.offsetValue), flip(), shift({ padding: 5 })],
    }).then(({ x, y }) => {
      Object.assign(this.contentTarget.style, {
        position: "fixed",
        left: `${x}px`,
        top: `${y}px`,
      });
    });
  }
}


================================================
FILE: app/components/DS/menu_item.html.erb
================================================
<% if variant == :divider %>
  <%= render "shared/ruler", classes: "my-1" %>
<% else %>
  <div class="px-1">
    <%= wrapper do %>
      <% if icon %>
        <%= helpers.icon(icon, color: destructive? ? :destructive : :default) %>
      <% end %>
      <%= tag.span(text, class: text_classes) %>
    <% end %>
  </div>
<% end %>


================================================
FILE: app/components/DS/menu_item.rb
================================================
class DS::MenuItem < DesignSystemComponent
  VARIANTS = %i[link button divider].freeze

  attr_reader :variant, :text, :icon, :href, :method, :destructive, :confirm, :frame, :opts

  def initialize(variant:, text: nil, icon: nil, href: nil, method: :post, destructive: false, confirm: nil, frame: nil, **opts)
    @variant = variant.to_sym
    @text = text
    @icon = icon
    @href = href
    @method = method.to_sym
    @destructive = destructive
    @confirm = confirm
    @frame = frame
    @opts = opts
    raise ArgumentError, "Invalid variant: #{@variant}" unless VARIANTS.include?(@variant)
  end

  def wrapper(&block)
    if variant == :button
      button_to href, method: method, class: container_classes, **merged_opts, &block
    elsif variant == :link
      link_to href, class: container_classes, **merged_opts, &block
    else
      nil
    end
  end

  def text_classes
    [
      "text-sm",
      destructive? ? "text-destructive" : "text-primary"
    ].join(" ")
  end

  def destructive?
    method == :delete || destructive
  end

  private
    def container_classes
      [
        "flex items-center gap-2 p-2 rounded-md w-full",
        destructive? ? "hover:bg-red-tint-5 theme-dark:hover:bg-red-tint-10" : "hover:bg-container-hover"
      ].join(" ")
    end

    def merged_opts
      merged_opts = opts.dup || {}
      data = merged_opts.delete(:data) || {}

      if confirm.present?
        data = data.merge(turbo_confirm: confirm.to_data_attribute)
      end

      if frame.present?
        data = data.merge(turbo_frame: frame)
      end

      merged_opts.merge(data: data)
    end
end


================================================
FILE: app/components/DS/tab.rb
================================================
class DS::Tab < DesignSystemComponent
  attr_reader :id, :label

  def initialize(id:, label:)
    @id = id
    @label = label
  end

  def call
    content
  end
end


================================================
FILE: app/components/DS/tabs/nav.rb
================================================
class DS::Tabs::Nav < DesignSystemComponent
  erb_template <<~ERB
    <%= tag.nav class: classes do %>
      <% btns.each do |btn| %>
        <%= btn %>
      <% end %>
    <% end %>
  ERB

  renders_many :btns, ->(id:, label:, classes: nil, &block) do
    content_tag(
      :button, label, id: id,
      type: "button",
      class: class_names(btn_classes, id == active_tab ? active_btn_classes : inactive_btn_classes, classes),
      data: { id: id, action: "DS--tabs#show", DS__tabs_target: "navBtn" },
      &block
    )
  end

  attr_reader :active_tab, :classes, :active_btn_classes, :inactive_btn_classes, :btn_classes

  def initialize(active_tab:, classes: nil, active_btn_classes: nil, inactive_btn_classes: nil, btn_classes: nil)
    @active_tab = active_tab
    @classes = classes
    @active_btn_classes = active_btn_classes
    @inactive_btn_classes = inactive_btn_classes
    @btn_classes = btn_classes
  end
end


================================================
FILE: app/components/DS/tabs/panel.rb
================================================
class DS::Tabs::Panel < DesignSystemComponent
  attr_reader :tab_id

  def initialize(tab_id:)
    @tab_id = tab_id
  end

  def call
    content
  end
end


================================================
FILE: app/components/DS/tabs.html.erb
================================================
<%= tag.div data: {
  controller: "DS--tabs",
  testid: testid,
  DS__tabs_session_key_value: session_key,
  DS__tabs_url_param_key_value: url_param_key,
  DS__tabs_nav_btn_active_class: active_btn_classes,
  DS__tabs_nav_btn_inactive_class: inactive_btn_classes
} do %>
  <% if unstyled? %>
    <%= content %>
  <% else %>
    <%= nav %>

    <% panels.each do |panel| %>
      <%= panel %>
    <% end %>
  <% end %>
<% end %>


================================================
FILE: app/components/DS/tabs.rb
================================================
class DS::Tabs < DesignSystemComponent
  renders_one :nav, ->(classes: nil) do
    DS::Tabs::Nav.new(
      active_tab: active_tab,
      active_btn_classes: active_btn_classes,
      inactive_btn_classes: inactive_btn_classes,
      btn_classes: base_btn_classes,
      classes: unstyled? ? classes : class_names(nav_container_classes, classes)
    )
  end

  renders_many :panels, ->(tab_id:, &block) do
    content_tag(
      :div,
      class: ("hidden" unless tab_id == active_tab),
      data: { id: tab_id, DS__tabs_target: "panel" },
      &block
    )
  end

  VARIANTS = {
    default: {
      active_btn_classes: "bg-white theme-dark:bg-gray-700 text-primary shadow-sm",
      inactive_btn_classes: "text-secondary hover:bg-surface-inset-hover",
      base_btn_classes: "w-full inline-flex justify-center items-center text-sm font-medium px-2 py-1 rounded-md transition-colors duration-200",
      nav_container_classes: "flex bg-surface-inset p-1 rounded-lg mb-4"
    }
  }

  attr_reader :active_tab, :url_param_key, :session_key, :variant, :testid

  def initialize(active_tab:, url_param_key: nil, session_key: nil, variant: :default, active_btn_classes: "", inactive_btn_classes: "", testid: nil)
    @active_tab = active_tab
    @url_param_key = url_param_key
    @session_key = session_key
    @variant = variant.to_sym
    @active_btn_classes = active_btn_classes
    @inactive_btn_classes = inactive_btn_classes
    @testid = testid
  end

  def active_btn_classes
    unstyled? ? @active_btn_classes : VARIANTS.dig(variant, :active_btn_classes)
  end

  def inactive_btn_classes
    unstyled? ? @inactive_btn_classes : VARIANTS.dig(variant, :inactive_btn_classes)
  end

  private
    def unstyled?
      variant == :unstyled
    end

    def base_btn_classes
      unless unstyled?
        VARIANTS.dig(variant, :base_btn_classes)
      end
    end

    def nav_container_classes
      unless unstyled?
        VARIANTS.dig(variant, :nav_container_classes)
      end
    end
end


================================================
FILE: app/components/DS/tabs_controller.js
================================================
import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="tabs--components"
export default class extends Controller {
  static classes = ["navBtnActive", "navBtnInactive"];
  static targets = ["panel", "navBtn"];
  static values = { sessionKey: String, urlParamKey: String };

  show(e) {
    const btn = e.target.closest("button");
    const selectedTabId = btn.dataset.id;

    this.navBtnTargets.forEach((navBtn) => {
      if (navBtn.dataset.id === selectedTabId) {
        navBtn.classList.add(...this.navBtnActiveClasses);
        navBtn.classList.remove(...this.navBtnInactiveClasses);
      } else {
        navBtn.classList.add(...this.navBtnInactiveClasses);
        navBtn.classList.remove(...this.navBtnActiveClasses);
      }
    });

    this.panelTargets.forEach((panel) => {
      if (panel.dataset.id === selectedTabId) {
        panel.classList.remove("hidden");
      } else {
        panel.classList.add("hidden");
      }
    });

    if (this.urlParamKeyValue) {
      const url = new URL(window.location.href);
      url.searchParams.set(this.urlParamKeyValue, selectedTabId);
      window.history.replaceState({}, "", url);
    }

    // Update URL with the selected tab
    if (this.sessionKeyValue) {
      this.#updateSessionPreference(selectedTabId);
    }
  } 

  #updateSessionPreference(selectedTabId) {
    fetch("/current_session", {
      method: "PUT",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "X-CSRF-Token": document.querySelector('[name="csrf-token"]').content,
        Accept: "application/json",
      },
      body: new URLSearchParams({
        "current_session[tab_key]": this.sessionKeyValue,
        "current_session[tab_value]": selectedTabId,
      }).toString(),
    });
  }
}


================================================
FILE: app/components/DS/toggle.html.erb
================================================
<div class="relative inline-block select-none">
  <%= hidden_field_tag name, unchecked_value, id: nil %>
  <%= check_box_tag name, checked_value, checked, class: "sr-only peer", disabled: disabled, id: id, **opts %>
  <%= label_tag name, "&nbsp;".html_safe, class: label_classes, for: id %>
</div>


================================================
FILE: app/components/DS/toggle.rb
================================================
class DS::Toggle < DesignSystemComponent
  attr_reader :id, :name, :checked, :disabled, :checked_value, :unchecked_value, :opts

  def initialize(id:, name: nil, checked: false, disabled: false, checked_value: "1", unchecked_value: "0", **opts)
    @id = id
    @name = name
    @checked = checked
    @disabled = disabled
    @checked_value = checked_value
    @unchecked_value = unchecked_value
    @opts = opts
  end

  def label_classes
    class_names(
       "block w-9 h-5 cursor-pointer",
       "rounded-full bg-gray-100 theme-dark:bg-gray-700",
       "transition-colors duration-300",
       "after:content-[''] after:block after:bg-white after:absolute after:rounded-full",
       "after:top-0.5 after:left-0.5 after:w-4 after:h-4",
       "after:transition-transform after:duration-300 after:ease-in-out",
       "peer-checked:bg-green-600 peer-checked:after:translate-x-4",
       "peer-disabled:opacity-70 peer-disabled:cursor-not-allowed"
    )
  end
end


================================================
FILE: app/components/DS/tooltip.html.erb
================================================
<span data-controller="DS--tooltip" data-DS--tooltip-placement-value="<%= placement %>" data-DS--tooltip-offset-value="<%= offset %>" data-DS--tooltip-cross-axis-value="<%= cross_axis %>" class="inline-flex">
  <%= helpers.icon icon_name, size: size, color: color %>

  <div role="tooltip" data-DS--tooltip-target="tooltip" class="hidden absolute z-50 bg-gray-700 text-sm px-1.5 py-1 rounded-md">
    <div class="fg-inverse font-normal max-w-[200px]">
      <%= tooltip_content %>
    </div>
  </div>
</span>


================================================
FILE: app/components/DS/tooltip.rb
================================================
class DS::Tooltip < ApplicationComponent
  attr_reader :placement, :offset, :cross_axis, :icon_name, :size, :color

  def initialize(text: nil, placement: "top", offset: 10, cross_axis: 0, icon: "info", size: "sm", color: "default")
    @text = text
    @placement = placement
    @offset = offset
    @cross_axis = cross_axis
    @icon_name = icon
    @size = size
    @color = color
  end

  def tooltip_content
    content? ? content : @text
  end
end


================================================
FILE: app/components/DS/tooltip_controller.js
================================================
import {
  autoUpdate,
  computePosition,
  flip,
  offset,
  shift,
} from "@floating-ui/dom";
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["tooltip"];
  static values = {
    placement: { type: String, default: "top" },
    offset: { type: Number, default: 10 },
    crossAxis: { type: Number, default: 0 },
  };

  connect() {
    this._cleanup = null;
    this.boundUpdate = this.update.bind(this);
    this.addEventListeners();
  }

  disconnect() {
    this.removeEventListeners();
    this.stopAutoUpdate();
  }

  addEventListeners() {
    this.element.addEventListener("mouseenter", this.show);
    this.element.addEventListener("mouseleave", this.hide);
  }

  removeEventListeners() {
    this.element.removeEventListener("mouseenter", this.show);
    this.element.removeEventListener("mouseleave", this.hide);
  }

  show = () => {
    this.tooltipTarget.classList.remove("hidden");
    this.startAutoUpdate();
    this.update();
  };

  hide = () => {
    this.tooltipTarget.classList.add("hidden");
    this.stopAutoUpdate();
  };

  startAutoUpdate() {
    if (!this._cleanup) {
      const reference = this.element.querySelector("[data-icon]");
      this._cleanup = autoUpdate(
        reference || this.element,
        this.tooltipTarget,
        this.boundUpdate
      );
    }
  }

  stopAutoUpdate() {
    if (this._cleanup) {
      this._cleanup();
      this._cleanup = null;
    }
  }

  update() {
    const reference = this.element.querySelector("[data-icon]");
    computePosition(reference || this.element, this.tooltipTarget, {
      placement: this.placementValue,
      middleware: [
        offset({
          mainAxis: this.offsetValue,
          crossAxis: this.crossAxisValue,
        }),
        flip(),
        shift({ padding: 5 }),
      ],
    }).then(({ x, y }) => {
      Object.assign(this.tooltipTarget.style, {
        left: `${x}px`,
        top: `${y}px`,
      });
    });
  }
}

================================================
FILE: app/components/UI/account/activity_date.html.erb
================================================
<%= tag.div id: id, data: { bulk_select_target: "group" }, class: "bg-container-inset rounded-xl p-1 w-full" do %>
  <details class="group">
    <summary>
      <div class="py-2 px-4 flex items-center justify-between font-medium text-xs text-secondary">
        <div class="flex pl-0.5 items-center gap-4">
          <%= check_box_tag "#{date}_entries_selection",
                          class: ["checkbox checkbox--light", "hidden": entries.size == 0],
                          id: "selection_entry_#{date}",
                          data: { action: "bulk-select#toggleGroupSelection" } %>

          <p class="uppercase space-x-1.5">
            <%= tag.span I18n.l(date, format: :long) %>
            <span>&middot;</span>
            <%= tag.span entries.size %>
          </p>
        </div>

        <div class="flex items-center gap-4">
          <div class="flex items-center gap-2">
            <span class="font-medium"><%= end_balance_money.format %></span>
            <%= render DS::Tooltip.new(text: "The end of day balance, after all transactions and adjustments", placement: "left", size: "sm") %>
          </div>
          <%= helpers.icon "chevron-down", class: "group-open:rotate-180" %>
        </div>
      </div>
    </summary>

    <div class="p-4">
      <% if balance %>
        <%= render UI::Account::BalanceReconciliation.new(balance: balance, account: account) %>
      <% else %>
        <p class="text-sm text-secondary">No balance data available for this date</p>
      <% end %>
    </div>
  </details>

  <div class="bg-container shadow-border-xs rounded-lg">
    <% entries.each do |entry| %>
      <%= render entry, view_ctx: "account" %>
    <% end %>
  </div>
<% end %>


================================================
FILE: app/components/UI/account/activity_date.rb
================================================
class UI::Account::ActivityDate < ApplicationComponent
  attr_reader :account, :data

  delegate :date, :entries, :balance, :transfers, to: :data

  def initialize(account:, data:)
    @account = account
    @data = data
  end

  def id
    dom_id(account, "entries_#{date}")
  end

  def broadcast_channel
    account
  end

  def end_balance_money
    balance&.end_balance_money || Money.new(0, account.currency)
  end

  def broadcast_refresh!
    Turbo::StreamsChannel.broadcast_replace_to(
      broadcast_channel,
      target: id,
      renderable: self,
      layout: false
    )
  end
end


================================================
FILE: app/components/UI/account/activity_feed.html.erb
================================================
<%= turbo_frame_tag dom_id(account, "entries") do %>
  <div class="bg-container p-5 shadow-border-xs rounded-xl">
    <div class="flex items-center justify-between mb-4" data-testid="activity-menu">
      <%= tag.h2 "Activity", class: "font-medium text-lg" %>

      <% if account.manual? %>
        <%= render DS::Menu.new(variant: "button") do |menu| %>
          <% menu.with_button(text: "New", variant: "secondary", icon: "plus") %>

          <% menu.with_item(
              variant: "link",
              text: "New balance",
              icon: "circle-dollar-sign",
              href: new_valuation_path(account_id: account.id),
              data: { turbo_frame: :modal }) %>

          <% unless account.crypto? %>
            <% menu.with_item(
                variant: "link",
                text: "New transaction",
                icon: "credit-card",
                href: account.investment? ? new_trade_path(account_id: account.id) : new_transaction_path(account_id: account.id),
                data: { turbo_frame: :modal }) %>
          <% end %>
        <% end %>
      <% end %>
    </div>

    <div>
      <%= form_with url: account_path(account),
              id: "entries-search",
              scope: :q,
              method: :get,
              data: { controller: "auto-submit-form" } do |form| %>
        <div class="flex gap-2 mb-4">
          <div class="grow">
            <div class="flex items-center px-3 py-2 gap-2 border border-secondary rounded-lg focus-within:ring-gray-100 focus-within:border-gray-900">
              <%= helpers.icon("search") %>

              <%= hidden_field_tag :account_id, account.id %>

              <%= form.search_field :search,
                            placeholder: "Search entries by name",
                            value: search,
                            class: "form-field__input placeholder:text-sm placeholder:text-secondary",
                            "data-auto-submit-form-target": "auto" %>
            </div>
          </div>
        </div>
      <% end %>
    </div>

    <% if activity_dates.empty? %>
      <p class="text-secondary text-sm p-4">No entries yet</p>
    <% else %>
      <%= tag.div id: dom_id(account, "entries_bulk_select"),
                data: {
                  controller: "bulk-select",
                  bulk_select_singular_label_value: "entry",
                  bulk_select_plural_label_value: "entries"
                } do %>
        <div id="entry-selection-bar" data-bulk-select-target="selectionBar" class="flex justify-center hidden">
          <%= render "entries/selection_bar" %>
        </div>

        <div class="grid bg-container-inset rounded-xl grid-cols-12 items-center uppercase text-xs font-medium text-secondary px-5 py-3 mb-4">
          <div class="pl-0.5 col-span-8 flex items-center gap-4">
            <%= check_box_tag "selection_entry",
                              class: "checkbox checkbox--light",
                              data: { action: "bulk-select#togglePageSelection" } %>
            <p>Date</p>
          </div>

          <%= tag.p "Amount", class: "col-span-4 justify-self-end" %>
        </div>
Download .txt
gitextract_cwa_8u3g/

├── .cursor/
│   └── rules/
│       ├── cursor_rules.mdc
│       ├── general-rules.mdc
│       ├── project-conventions.mdc
│       ├── project-design.mdc
│       ├── self_improve.mdc
│       ├── stimulus_conventions.mdc
│       ├── testing.mdc
│       ├── ui-ux-design-guidelines.mdc
│       └── view_conventions.mdc
├── .devcontainer/
│   ├── Dockerfile
│   ├── devcontainer.json
│   └── docker-compose.yml
├── .dockerignore
├── .editorconfig
├── .env.example
├── .env.local.example
├── .env.test.example
├── .erb_lint.yml
├── .gitattributes
├── .github/
│   ├── DISCUSSION_TEMPLATE/
│   │   └── feature-requests.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── other.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       ├── pr.yml
│       └── publish.yml
├── .gitignore
├── .rubocop.yml
├── .ruby-version
├── CLAUDE.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── LICENSE
├── Procfile.dev
├── README.md
├── Rakefile
├── app/
│   ├── assets/
│   │   ├── builds/
│   │   │   └── .keep
│   │   └── tailwind/
│   │       ├── application.css
│   │       ├── geist-font.css
│   │       ├── geist-mono-font.css
│   │       ├── maybe-design-system/
│   │       │   ├── background-utils.css
│   │       │   ├── border-utils.css
│   │       │   ├── component-utils.css
│   │       │   ├── foreground-utils.css
│   │       │   └── text-utils.css
│   │       ├── maybe-design-system.css
│   │       └── simonweb_pickr.css
│   ├── channels/
│   │   └── application_cable/
│   │       ├── channel.rb
│   │       └── connection.rb
│   ├── components/
│   │   ├── DS/
│   │   │   ├── alert.html.erb
│   │   │   ├── alert.rb
│   │   │   ├── button.html.erb
│   │   │   ├── button.rb
│   │   │   ├── buttonish.rb
│   │   │   ├── dialog.html.erb
│   │   │   ├── dialog.rb
│   │   │   ├── dialog_controller.js
│   │   │   ├── disclosure.html.erb
│   │   │   ├── disclosure.rb
│   │   │   ├── filled_icon.html.erb
│   │   │   ├── filled_icon.rb
│   │   │   ├── link.html.erb
│   │   │   ├── link.rb
│   │   │   ├── menu.html.erb
│   │   │   ├── menu.rb
│   │   │   ├── menu_controller.js
│   │   │   ├── menu_item.html.erb
│   │   │   ├── menu_item.rb
│   │   │   ├── tab.rb
│   │   │   ├── tabs/
│   │   │   │   ├── nav.rb
│   │   │   │   └── panel.rb
│   │   │   ├── tabs.html.erb
│   │   │   ├── tabs.rb
│   │   │   ├── tabs_controller.js
│   │   │   ├── toggle.html.erb
│   │   │   ├── toggle.rb
│   │   │   ├── tooltip.html.erb
│   │   │   ├── tooltip.rb
│   │   │   └── tooltip_controller.js
│   │   ├── UI/
│   │   │   ├── account/
│   │   │   │   ├── activity_date.html.erb
│   │   │   │   ├── activity_date.rb
│   │   │   │   ├── activity_feed.html.erb
│   │   │   │   ├── activity_feed.rb
│   │   │   │   ├── balance_reconciliation.html.erb
│   │   │   │   ├── balance_reconciliation.rb
│   │   │   │   ├── chart.html.erb
│   │   │   │   └── chart.rb
│   │   │   ├── account_page.html.erb
│   │   │   └── account_page.rb
│   │   ├── application_component.rb
│   │   └── design_system_component.rb
│   ├── controllers/
│   │   ├── accountable_sparklines_controller.rb
│   │   ├── accounts_controller.rb
│   │   ├── api/
│   │   │   └── v1/
│   │   │       ├── accounts_controller.rb
│   │   │       ├── auth_controller.rb
│   │   │       ├── base_controller.rb
│   │   │       ├── chats_controller.rb
│   │   │       ├── messages_controller.rb
│   │   │       ├── test_controller.rb
│   │   │       ├── transactions_controller.rb
│   │   │       └── usage_controller.rb
│   │   ├── application_controller.rb
│   │   ├── budget_categories_controller.rb
│   │   ├── budgets_controller.rb
│   │   ├── categories_controller.rb
│   │   ├── category/
│   │   │   ├── deletions_controller.rb
│   │   │   └── dropdowns_controller.rb
│   │   ├── chats_controller.rb
│   │   ├── concerns/
│   │   │   ├── accountable_resource.rb
│   │   │   ├── authentication.rb
│   │   │   ├── auto_sync.rb
│   │   │   ├── breadcrumbable.rb
│   │   │   ├── entryable_resource.rb
│   │   │   ├── feature_guardable.rb
│   │   │   ├── impersonatable.rb
│   │   │   ├── invitable.rb
│   │   │   ├── localize.rb
│   │   │   ├── notifiable.rb
│   │   │   ├── onboardable.rb
│   │   │   ├── periodable.rb
│   │   │   ├── restore_layout_preferences.rb
│   │   │   ├── self_hostable.rb
│   │   │   ├── store_location.rb
│   │   │   └── stream_extensions.rb
│   │   ├── cookie_sessions_controller.rb
│   │   ├── credit_cards_controller.rb
│   │   ├── cryptos_controller.rb
│   │   ├── currencies_controller.rb
│   │   ├── current_sessions_controller.rb
│   │   ├── depositories_controller.rb
│   │   ├── email_confirmations_controller.rb
│   │   ├── family_exports_controller.rb
│   │   ├── family_merchants_controller.rb
│   │   ├── holdings_controller.rb
│   │   ├── impersonation_sessions_controller.rb
│   │   ├── import/
│   │   │   ├── cleans_controller.rb
│   │   │   ├── configurations_controller.rb
│   │   │   ├── confirms_controller.rb
│   │   │   ├── mappings_controller.rb
│   │   │   ├── rows_controller.rb
│   │   │   └── uploads_controller.rb
│   │   ├── imports_controller.rb
│   │   ├── investments_controller.rb
│   │   ├── invitations_controller.rb
│   │   ├── invite_codes_controller.rb
│   │   ├── loans_controller.rb
│   │   ├── lookbooks_controller.rb
│   │   ├── messages_controller.rb
│   │   ├── mfa_controller.rb
│   │   ├── onboardings_controller.rb
│   │   ├── other_assets_controller.rb
│   │   ├── other_liabilities_controller.rb
│   │   ├── pages_controller.rb
│   │   ├── password_resets_controller.rb
│   │   ├── passwords_controller.rb
│   │   ├── plaid_items_controller.rb
│   │   ├── properties_controller.rb
│   │   ├── registrations_controller.rb
│   │   ├── rules_controller.rb
│   │   ├── securities_controller.rb
│   │   ├── sessions_controller.rb
│   │   ├── settings/
│   │   │   ├── api_keys_controller.rb
│   │   │   ├── billings_controller.rb
│   │   │   ├── hostings_controller.rb
│   │   │   ├── preferences_controller.rb
│   │   │   ├── profiles_controller.rb
│   │   │   └── securities_controller.rb
│   │   ├── subscriptions_controller.rb
│   │   ├── tag/
│   │   │   └── deletions_controller.rb
│   │   ├── tags_controller.rb
│   │   ├── trades_controller.rb
│   │   ├── transaction_categories_controller.rb
│   │   ├── transactions/
│   │   │   ├── bulk_deletions_controller.rb
│   │   │   └── bulk_updates_controller.rb
│   │   ├── transactions_controller.rb
│   │   ├── transfer_matches_controller.rb
│   │   ├── transfers_controller.rb
│   │   ├── users_controller.rb
│   │   ├── valuations_controller.rb
│   │   ├── vehicles_controller.rb
│   │   └── webhooks_controller.rb
│   ├── data_migrations/
│   │   └── balance_component_migrator.rb
│   ├── helpers/
│   │   ├── accounts_helper.rb
│   │   ├── application_helper.rb
│   │   ├── categories_helper.rb
│   │   ├── chats_helper.rb
│   │   ├── custom_confirm.rb
│   │   ├── entries_helper.rb
│   │   ├── imports_helper.rb
│   │   ├── languages_helper.rb
│   │   ├── mfa_helper.rb
│   │   ├── settings_helper.rb
│   │   ├── styled_form_builder.rb
│   │   └── transactions_helper.rb
│   ├── javascript/
│   │   ├── application.js
│   │   ├── controllers/
│   │   │   ├── app_layout_controller.js
│   │   │   ├── application.js
│   │   │   ├── auto_submit_form_controller.js
│   │   │   ├── budget_form_controller.js
│   │   │   ├── bulk_select_controller.js
│   │   │   ├── category_controller.js
│   │   │   ├── chat_controller.js
│   │   │   ├── clipboard_controller.js
│   │   │   ├── color_avatar_controller.js
│   │   │   ├── color_select_controller.js
│   │   │   ├── confirm_dialog_controller.js
│   │   │   ├── deletion_controller.js
│   │   │   ├── donut_chart_controller.js
│   │   │   ├── element_removal_controller.js
│   │   │   ├── file_upload_controller.js
│   │   │   ├── hotkey_controller.js
│   │   │   ├── import_controller.js
│   │   │   ├── index.js
│   │   │   ├── intercom_controller.js
│   │   │   ├── list_filter_controller.js
│   │   │   ├── list_keyboard_navigation_controller.js
│   │   │   ├── mobile_cell_interaction_controller.js
│   │   │   ├── money_field_controller.js
│   │   │   ├── onboarding_controller.js
│   │   │   ├── password_validator_controller.js
│   │   │   ├── password_visibility_controller.js
│   │   │   ├── plaid_controller.js
│   │   │   ├── preserve_scroll_controller.js
│   │   │   ├── profile_image_preview_controller.js
│   │   │   ├── rule/
│   │   │   │   ├── actions_controller.js
│   │   │   │   └── conditions_controller.js
│   │   │   ├── rules_controller.js
│   │   │   ├── sankey_chart_controller.js
│   │   │   ├── scroll_on_connect_controller.js
│   │   │   ├── selectable_link_controller.js
│   │   │   ├── theme_controller.js
│   │   │   ├── time_series_chart_controller.js
│   │   │   ├── tooltip_controller.js
│   │   │   ├── trade_form_controller.js
│   │   │   ├── transfer_match_controller.js
│   │   │   └── turbo_frame_timeout_controller.js
│   │   ├── services/
│   │   │   └── currencies_service.js
│   │   └── shims/
│   │       ├── d3-array-default.js
│   │       └── d3-shape-default.js
│   ├── jobs/
│   │   ├── application_job.rb
│   │   ├── assistant_response_job.rb
│   │   ├── auto_categorize_job.rb
│   │   ├── auto_detect_merchants_job.rb
│   │   ├── data_cache_clear_job.rb
│   │   ├── destroy_job.rb
│   │   ├── family_data_export_job.rb
│   │   ├── family_reset_job.rb
│   │   ├── import_job.rb
│   │   ├── import_market_data_job.rb
│   │   ├── revert_import_job.rb
│   │   ├── rule_job.rb
│   │   ├── security_health_check_job.rb
│   │   ├── stripe_event_handler_job.rb
│   │   ├── sync_cleaner_job.rb
│   │   ├── sync_job.rb
│   │   └── user_purge_job.rb
│   ├── mailers/
│   │   ├── application_mailer.rb
│   │   ├── email_confirmation_mailer.rb
│   │   ├── invitation_mailer.rb
│   │   └── password_mailer.rb
│   ├── models/
│   │   ├── account/
│   │   │   ├── activity_feed_data.rb
│   │   │   ├── anchorable.rb
│   │   │   ├── chartable.rb
│   │   │   ├── current_balance_manager.rb
│   │   │   ├── linkable.rb
│   │   │   ├── market_data_importer.rb
│   │   │   ├── opening_balance_manager.rb
│   │   │   ├── reconcileable.rb
│   │   │   ├── reconciliation_manager.rb
│   │   │   ├── sync_complete_event.rb
│   │   │   └── syncer.rb
│   │   ├── account.rb
│   │   ├── account_import.rb
│   │   ├── address.rb
│   │   ├── api_key.rb
│   │   ├── application_record.rb
│   │   ├── assistant/
│   │   │   ├── broadcastable.rb
│   │   │   ├── configurable.rb
│   │   │   ├── function/
│   │   │   │   ├── get_accounts.rb
│   │   │   │   ├── get_balance_sheet.rb
│   │   │   │   ├── get_income_statement.rb
│   │   │   │   └── get_transactions.rb
│   │   │   ├── function.rb
│   │   │   ├── function_tool_caller.rb
│   │   │   ├── provided.rb
│   │   │   └── responder.rb
│   │   ├── assistant.rb
│   │   ├── assistant_message.rb
│   │   ├── balance/
│   │   │   ├── base_calculator.rb
│   │   │   ├── chart_series_builder.rb
│   │   │   ├── forward_calculator.rb
│   │   │   ├── materializer.rb
│   │   │   ├── reverse_calculator.rb
│   │   │   └── sync_cache.rb
│   │   ├── balance.rb
│   │   ├── balance_sheet/
│   │   │   ├── account_group.rb
│   │   │   ├── account_totals.rb
│   │   │   ├── classification_group.rb
│   │   │   ├── net_worth_series_builder.rb
│   │   │   └── sync_status_monitor.rb
│   │   ├── balance_sheet.rb
│   │   ├── budget.rb
│   │   ├── budget_category.rb
│   │   ├── category.rb
│   │   ├── chat/
│   │   │   └── debuggable.rb
│   │   ├── chat.rb
│   │   ├── concerns/
│   │   │   ├── accountable.rb
│   │   │   ├── enrichable.rb
│   │   │   ├── monetizable.rb
│   │   │   └── syncable.rb
│   │   ├── credit_card.rb
│   │   ├── crypto.rb
│   │   ├── current.rb
│   │   ├── data_enrichment.rb
│   │   ├── demo/
│   │   │   ├── data_cleaner.rb
│   │   │   └── generator.rb
│   │   ├── depository.rb
│   │   ├── developer_message.rb
│   │   ├── entry.rb
│   │   ├── entry_search.rb
│   │   ├── entryable.rb
│   │   ├── exchange_rate/
│   │   │   ├── importer.rb
│   │   │   └── provided.rb
│   │   ├── exchange_rate.rb
│   │   ├── family/
│   │   │   ├── auto_categorizer.rb
│   │   │   ├── auto_merchant_detector.rb
│   │   │   ├── auto_transfer_matchable.rb
│   │   │   ├── data_exporter.rb
│   │   │   ├── plaid_connectable.rb
│   │   │   ├── subscribeable.rb
│   │   │   ├── sync_complete_event.rb
│   │   │   └── syncer.rb
│   │   ├── family.rb
│   │   ├── family_export.rb
│   │   ├── family_merchant.rb
│   │   ├── holding/
│   │   │   ├── forward_calculator.rb
│   │   │   ├── gapfillable.rb
│   │   │   ├── materializer.rb
│   │   │   ├── portfolio_cache.rb
│   │   │   ├── portfolio_snapshot.rb
│   │   │   └── reverse_calculator.rb
│   │   ├── holding.rb
│   │   ├── impersonation_session.rb
│   │   ├── impersonation_session_log.rb
│   │   ├── import/
│   │   │   ├── account_mapping.rb
│   │   │   ├── account_type_mapping.rb
│   │   │   ├── category_mapping.rb
│   │   │   ├── mapping.rb
│   │   │   ├── row.rb
│   │   │   └── tag_mapping.rb
│   │   ├── import.rb
│   │   ├── income_statement/
│   │   │   ├── category_stats.rb
│   │   │   ├── family_stats.rb
│   │   │   └── totals.rb
│   │   ├── income_statement.rb
│   │   ├── investment.rb
│   │   ├── invitation.rb
│   │   ├── invite_code.rb
│   │   ├── loan.rb
│   │   ├── market_data_importer.rb
│   │   ├── measurement.rb
│   │   ├── merchant.rb
│   │   ├── message.rb
│   │   ├── mint_import.rb
│   │   ├── mobile_device.rb
│   │   ├── other_asset.rb
│   │   ├── other_liability.rb
│   │   ├── period.rb
│   │   ├── plaid_account/
│   │   │   ├── importer.rb
│   │   │   ├── investments/
│   │   │   │   ├── balance_calculator.rb
│   │   │   │   ├── holdings_processor.rb
│   │   │   │   ├── security_resolver.rb
│   │   │   │   └── transactions_processor.rb
│   │   │   ├── liabilities/
│   │   │   │   ├── credit_processor.rb
│   │   │   │   ├── mortgage_processor.rb
│   │   │   │   └── student_loan_processor.rb
│   │   │   ├── processor.rb
│   │   │   ├── transactions/
│   │   │   │   ├── category_matcher.rb
│   │   │   │   ├── category_taxonomy.rb
│   │   │   │   └── processor.rb
│   │   │   └── type_mappable.rb
│   │   ├── plaid_account.rb
│   │   ├── plaid_entry/
│   │   │   └── processor.rb
│   │   ├── plaid_item/
│   │   │   ├── accounts_snapshot.rb
│   │   │   ├── importer.rb
│   │   │   ├── provided.rb
│   │   │   ├── sync_complete_event.rb
│   │   │   ├── syncer.rb
│   │   │   └── webhook_processor.rb
│   │   ├── plaid_item.rb
│   │   ├── property.rb
│   │   ├── provider/
│   │   │   ├── exchange_rate_concept.rb
│   │   │   ├── github.rb
│   │   │   ├── llm_concept.rb
│   │   │   ├── openai/
│   │   │   │   ├── auto_categorizer.rb
│   │   │   │   ├── auto_merchant_detector.rb
│   │   │   │   ├── chat_config.rb
│   │   │   │   ├── chat_parser.rb
│   │   │   │   └── chat_stream_parser.rb
│   │   │   ├── openai.rb
│   │   │   ├── plaid.rb
│   │   │   ├── plaid_sandbox.rb
│   │   │   ├── registry.rb
│   │   │   ├── security_concept.rb
│   │   │   ├── stripe/
│   │   │   │   ├── event_processor.rb
│   │   │   │   └── subscription_event_processor.rb
│   │   │   ├── stripe.rb
│   │   │   └── synth.rb
│   │   ├── provider.rb
│   │   ├── provider_merchant.rb
│   │   ├── rejected_transfer.rb
│   │   ├── rule/
│   │   │   ├── action.rb
│   │   │   ├── action_executor/
│   │   │   │   ├── auto_categorize.rb
│   │   │   │   ├── auto_detect_merchants.rb
│   │   │   │   ├── set_transaction_category.rb
│   │   │   │   ├── set_transaction_merchant.rb
│   │   │   │   ├── set_transaction_name.rb
│   │   │   │   └── set_transaction_tags.rb
│   │   │   ├── action_executor.rb
│   │   │   ├── condition.rb
│   │   │   ├── condition_filter/
│   │   │   │   ├── transaction_amount.rb
│   │   │   │   ├── transaction_merchant.rb
│   │   │   │   └── transaction_name.rb
│   │   │   ├── condition_filter.rb
│   │   │   ├── registry/
│   │   │   │   └── transaction_resource.rb
│   │   │   └── registry.rb
│   │   ├── rule.rb
│   │   ├── security/
│   │   │   ├── health_checker.rb
│   │   │   ├── price/
│   │   │   │   └── importer.rb
│   │   │   ├── price.rb
│   │   │   ├── provided.rb
│   │   │   ├── resolver.rb
│   │   │   └── synth_combobox_option.rb
│   │   ├── security.rb
│   │   ├── series.rb
│   │   ├── session.rb
│   │   ├── setting.rb
│   │   ├── subscription.rb
│   │   ├── sync.rb
│   │   ├── tag.rb
│   │   ├── tagging.rb
│   │   ├── tool_call/
│   │   │   └── function.rb
│   │   ├── tool_call.rb
│   │   ├── trade/
│   │   │   └── create_form.rb
│   │   ├── trade.rb
│   │   ├── trade_import.rb
│   │   ├── transaction/
│   │   │   ├── ruleable.rb
│   │   │   ├── search.rb
│   │   │   └── transferable.rb
│   │   ├── transaction.rb
│   │   ├── transaction_import.rb
│   │   ├── transfer/
│   │   │   └── creator.rb
│   │   ├── transfer.rb
│   │   ├── trend.rb
│   │   ├── user.rb
│   │   ├── user_message.rb
│   │   ├── valuation/
│   │   │   └── name.rb
│   │   ├── valuation.rb
│   │   └── vehicle.rb
│   ├── services/
│   │   ├── api_rate_limiter.rb
│   │   └── noop_api_rate_limiter.rb
│   └── views/
│       ├── accountable_sparklines/
│       │   └── show.html.erb
│       ├── accounts/
│       │   ├── _account.html.erb
│       │   ├── _account_sidebar_tabs.html.erb
│       │   ├── _account_type.html.erb
│       │   ├── _accountable_group.html.erb
│       │   ├── _empty.html.erb
│       │   ├── _form.html.erb
│       │   ├── _logo.html.erb
│       │   ├── _summary_card.html.erb
│       │   ├── index/
│       │   │   ├── _account_groups.erb
│       │   │   └── _manual_accounts.html.erb
│       │   ├── index.html.erb
│       │   ├── new/
│       │   │   ├── _container.html.erb
│       │   │   └── _method_selector.html.erb
│       │   ├── new.html.erb
│       │   ├── show/
│       │   │   ├── _activity.html.erb
│       │   │   ├── _header.html.erb
│       │   │   └── _menu.html.erb
│       │   ├── show.html.erb
│       │   └── sparkline.html.erb
│       ├── api/
│       │   └── v1/
│       │       ├── accounts/
│       │       │   └── index.json.jbuilder
│       │       ├── chats/
│       │       │   ├── _chat.json.jbuilder
│       │       │   ├── index.json.jbuilder
│       │       │   └── show.json.jbuilder
│       │       ├── messages/
│       │       │   └── show.json.jbuilder
│       │       └── transactions/
│       │           ├── _transaction.json.jbuilder
│       │           ├── index.json.jbuilder
│       │           └── show.json.jbuilder
│       ├── assistant_messages/
│       │   ├── _assistant_message.html.erb
│       │   └── _tool_calls.html.erb
│       ├── budget_categories/
│       │   ├── _allocation_progress.erb
│       │   ├── _budget_category.html.erb
│       │   ├── _budget_category_donut.html.erb
│       │   ├── _budget_category_form.html.erb
│       │   ├── _confirm_button.html.erb
│       │   ├── _no_categories.html.erb
│       │   ├── _uncategorized_budget_category_form.html.erb
│       │   ├── index.html.erb
│       │   ├── show.html.erb
│       │   └── update.turbo_stream.erb
│       ├── budgets/
│       │   ├── _actuals_summary.html.erb
│       │   ├── _budget_categories.html.erb
│       │   ├── _budget_donut.html.erb
│       │   ├── _budget_header.html.erb
│       │   ├── _budget_nav.html.erb
│       │   ├── _budgeted_summary.html.erb
│       │   ├── _over_allocation_warning.html.erb
│       │   ├── _picker.html.erb
│       │   ├── edit.html.erb
│       │   └── show.html.erb
│       ├── categories/
│       │   ├── _badge.html.erb
│       │   ├── _category.html.erb
│       │   ├── _category_list_group.html.erb
│       │   ├── _color_avatar.html.erb
│       │   ├── _form.html.erb
│       │   ├── _menu.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── category/
│       │   ├── deletions/
│       │   │   └── new.html.erb
│       │   └── dropdowns/
│       │       ├── _row.html.erb
│       │       └── show.html.erb
│       ├── chats/
│       │   ├── _ai_avatar.html.erb
│       │   ├── _ai_consent.html.erb
│       │   ├── _ai_greeting.html.erb
│       │   ├── _chat.html.erb
│       │   ├── _chat_nav.html.erb
│       │   ├── _chat_title.html.erb
│       │   ├── _error.html.erb
│       │   ├── _thinking_indicator.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── credit_cards/
│       │   ├── _form.html.erb
│       │   ├── _overview.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── cryptos/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── depositories/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── developer_messages/
│       │   └── _developer_message.html.erb
│       ├── doorkeeper/
│       │   ├── applications/
│       │   │   ├── _delete_form.html.erb
│       │   │   ├── _form.html.erb
│       │   │   ├── edit.html.erb
│       │   │   ├── index.html.erb
│       │   │   ├── new.html.erb
│       │   │   └── show.html.erb
│       │   ├── authorizations/
│       │   │   ├── error.html.erb
│       │   │   ├── form_post.html.erb
│       │   │   ├── new.html.erb
│       │   │   └── show.html.erb
│       │   └── authorized_applications/
│       │       ├── _delete_form.html.erb
│       │       └── index.html.erb
│       ├── email_confirmation_mailer/
│       │   ├── confirmation_email.html.erb
│       │   └── confirmation_email.text.erb
│       ├── entries/
│       │   ├── _empty.html.erb
│       │   ├── _entry.html.erb
│       │   ├── _entry_group.html.erb
│       │   ├── _loading.html.erb
│       │   └── _selection_bar.html.erb
│       ├── family_exports/
│       │   ├── _list.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── family_merchants/
│       │   ├── _family_merchant.html.erb
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── holdings/
│       │   ├── _cash.html.erb
│       │   ├── _holding.html.erb
│       │   ├── _missing_price_tooltip.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── impersonation_sessions/
│       │   ├── _approval_bar.html.erb
│       │   └── _super_admin_bar.html.erb
│       ├── import/
│       │   ├── cleans/
│       │   │   └── show.html.erb
│       │   ├── configurations/
│       │   │   ├── _account_import.html.erb
│       │   │   ├── _mint_import.html.erb
│       │   │   ├── _trade_import.html.erb
│       │   │   ├── _transaction_import.html.erb
│       │   │   └── show.html.erb
│       │   ├── confirms/
│       │   │   ├── _mappings.html.erb
│       │   │   └── show.html.erb
│       │   ├── mappings/
│       │   │   └── _form.html.erb
│       │   ├── rows/
│       │   │   ├── _form.html.erb
│       │   │   └── show.html.erb
│       │   └── uploads/
│       │       └── show.html.erb
│       ├── imports/
│       │   ├── _empty.html.erb
│       │   ├── _failure.html.erb
│       │   ├── _import.html.erb
│       │   ├── _importing.html.erb
│       │   ├── _nav.html.erb
│       │   ├── _ready.html.erb
│       │   ├── _revert_failure.html.erb
│       │   ├── _success.html.erb
│       │   ├── _table.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── investments/
│       │   ├── _form.html.erb
│       │   ├── _value_tooltip.html.erb
│       │   ├── edit.html.erb
│       │   ├── new.html.erb
│       │   └── tabs/
│       │       └── _holdings.html.erb
│       ├── invitation_mailer/
│       │   └── invite_email.html.erb
│       ├── invitations/
│       │   └── new.html.erb
│       ├── invite_codes/
│       │   ├── _invite_code.html.erb
│       │   └── index.html.erb
│       ├── layouts/
│       │   ├── application.html.erb
│       │   ├── auth.html.erb
│       │   ├── blank.html.erb
│       │   ├── doorkeeper/
│       │   │   ├── admin.html.erb
│       │   │   └── application.html.erb
│       │   ├── imports.html.erb
│       │   ├── lookbooks.html.erb
│       │   ├── mailer.html.erb
│       │   ├── mailer.text.erb
│       │   ├── onboardings.html.erb
│       │   ├── settings.html.erb
│       │   ├── shared/
│       │   │   ├── _breadcrumbs.html.erb
│       │   │   ├── _confirm_dialog.html.erb
│       │   │   ├── _footer.html.erb
│       │   │   ├── _head.html.erb
│       │   │   ├── _htmldoc.html.erb
│       │   │   ├── _nav_item.html.erb
│       │   │   └── _page_header.html.erb
│       │   └── wizard.html.erb
│       ├── loans/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   ├── new.html.erb
│       │   └── tabs/
│       │       └── _overview.html.erb
│       ├── messages/
│       │   └── _chat_form.html.erb
│       ├── mfa/
│       │   ├── backup_codes.html.erb
│       │   ├── new.html.erb
│       │   └── verify.html.erb
│       ├── onboardings/
│       │   ├── _logout.html.erb
│       │   ├── _onboarding_nav.html.erb
│       │   ├── goals.html.erb
│       │   ├── preferences.html.erb
│       │   ├── show.html.erb
│       │   └── trial.html.erb
│       ├── other_assets/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── other_liabilities/
│       │   ├── _form.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── pages/
│       │   ├── changelog.html.erb
│       │   ├── dashboard/
│       │   │   ├── _balance_sheet.html.erb
│       │   │   ├── _cashflow_sankey.html.erb
│       │   │   ├── _group_weight.html.erb
│       │   │   ├── _net_worth_chart.html.erb
│       │   │   └── _no_accounts_graph_placeholder.html.erb
│       │   ├── dashboard.html.erb
│       │   ├── feedback.html.erb
│       │   └── redis_configuration_error.html.erb
│       ├── password_mailer/
│       │   └── password_reset.html.erb
│       ├── password_resets/
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── passwords/
│       │   └── edit.html.erb
│       ├── plaid_items/
│       │   ├── _auto_link_opener.html.erb
│       │   ├── _plaid_item.html.erb
│       │   ├── edit.html.erb
│       │   └── new.html.erb
│       ├── properties/
│       │   ├── _form.html.erb
│       │   ├── _form_alert.html.erb
│       │   ├── _form_tab.html.erb
│       │   ├── _form_tabs.html.erb
│       │   ├── _overview_fields.html.erb
│       │   ├── address.html.erb
│       │   ├── balances.html.erb
│       │   ├── edit.html.erb
│       │   ├── new.html.erb
│       │   └── tabs/
│       │       └── _overview.html.erb
│       ├── pwa/
│       │   ├── manifest.json.erb
│       │   └── service-worker.js
│       ├── registrations/
│       │   └── new.html.erb
│       ├── rule/
│       │   ├── actions/
│       │   │   └── _action.html.erb
│       │   └── conditions/
│       │       ├── _condition.html.erb
│       │       └── _condition_group.html.erb
│       ├── rules/
│       │   ├── _category_rule_cta.html.erb
│       │   ├── _form.html.erb
│       │   ├── _rule.html.erb
│       │   ├── confirm.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── securities/
│       │   ├── _combobox_security.turbo_stream.erb
│       │   └── index.turbo_stream.erb
│       ├── sessions/
│       │   └── new.html.erb
│       ├── settings/
│       │   ├── _section.html.erb
│       │   ├── _settings_nav.html.erb
│       │   ├── _settings_nav_item.html.erb
│       │   ├── _settings_nav_link_large.html.erb
│       │   ├── _user_avatar.html.erb
│       │   ├── _user_avatar_field.html.erb
│       │   ├── api_keys/
│       │   │   ├── created.html.erb
│       │   │   ├── created.turbo_stream.erb
│       │   │   ├── new.html.erb
│       │   │   └── show.html.erb
│       │   ├── billings/
│       │   │   └── show.html.erb
│       │   ├── hostings/
│       │   │   ├── _danger_zone_settings.html.erb
│       │   │   ├── _invite_code_settings.html.erb
│       │   │   ├── _synth_settings.html.erb
│       │   │   └── show.html.erb
│       │   ├── preferences/
│       │   │   └── show.html.erb
│       │   ├── profiles/
│       │   │   └── show.html.erb
│       │   └── securities/
│       │       └── show.html.erb
│       ├── shared/
│       │   ├── _app_version.html.erb
│       │   ├── _color_avatar.html.erb
│       │   ├── _form_errors.html.erb
│       │   ├── _logo.html.erb
│       │   ├── _money_field.html.erb
│       │   ├── _pagination.html.erb
│       │   ├── _progress_circle.html.erb
│       │   ├── _ruler.html.erb
│       │   ├── _sparkline.html.erb
│       │   ├── _text_tooltip.erb
│       │   ├── _transaction_type_tabs.html.erb
│       │   ├── _trend_change.html.erb
│       │   └── notifications/
│       │       ├── _alert.html.erb
│       │       ├── _cta.html.erb
│       │       └── _notice.html.erb
│       ├── subscriptions/
│       │   ├── _plan_choice.html.erb
│       │   └── upgrade.html.erb
│       ├── tag/
│       │   └── deletions/
│       │       └── new.html.erb
│       ├── tags/
│       │   ├── _badge.html.erb
│       │   ├── _form.html.erb
│       │   ├── _tag.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   └── new.html.erb
│       ├── trades/
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _trade.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── transactions/
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _selection_bar.html.erb
│       │   ├── _summary.html.erb
│       │   ├── _transaction.html.erb
│       │   ├── _transaction_category.html.erb
│       │   ├── _transfer_match.html.erb
│       │   ├── bulk_updates/
│       │   │   └── new.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   ├── searches/
│       │   │   ├── _form.html.erb
│       │   │   ├── _menu.html.erb
│       │   │   ├── _search.html.erb
│       │   │   └── filters/
│       │   │       ├── _account_filter.html.erb
│       │   │       ├── _amount_filter.html.erb
│       │   │       ├── _badge.html.erb
│       │   │       ├── _category_filter.html.erb
│       │   │       ├── _date_filter.html.erb
│       │   │       ├── _merchant_filter.html.erb
│       │   │       ├── _tag_filter.html.erb
│       │   │       └── _type_filter.html.erb
│       │   └── show.html.erb
│       ├── transfer_matches/
│       │   ├── _matching_fields.html.erb
│       │   └── new.html.erb
│       ├── transfers/
│       │   ├── _account_links.html.erb
│       │   ├── _form.html.erb
│       │   ├── new.html.erb
│       │   ├── show.html.erb
│       │   └── update.turbo_stream.erb
│       ├── user_messages/
│       │   └── _user_message.html.erb
│       ├── users/
│       │   └── _user_menu.html.erb
│       ├── valuations/
│       │   ├── _confirmation_contents.html.erb
│       │   ├── _header.html.erb
│       │   ├── _valuation.html.erb
│       │   ├── confirm_create.html.erb
│       │   ├── confirm_update.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       └── vehicles/
│           ├── _form.html.erb
│           ├── edit.html.erb
│           ├── new.html.erb
│           └── tabs/
│               └── _overview.html.erb
├── bin/
│   ├── brakeman
│   ├── bundle
│   ├── dev
│   ├── docker-entrypoint
│   ├── importmap
│   ├── rails
│   ├── rake
│   ├── render-build.sh
│   ├── rubocop
│   ├── setup
│   └── update_structure.sh
├── biome.json
├── compose.example.yml
├── config/
│   ├── application.rb
│   ├── boot.rb
│   ├── brakeman.ignore
│   ├── cable.yml
│   ├── credentials.yml.enc
│   ├── currencies.yml
│   ├── database.yml
│   ├── environment.rb
│   ├── environments/
│   │   ├── development.rb
│   │   ├── production.rb
│   │   └── test.rb
│   ├── i18n-tasks.yml
│   ├── importmap.rb
│   ├── initializers/
│   │   ├── active_record_encryption.rb
│   │   ├── assets.rb
│   │   ├── content_security_policy.rb
│   │   ├── doorkeeper.rb
│   │   ├── doorkeeper_csrf_protection.rb
│   │   ├── doorkeeper_layout.rb
│   │   ├── enable_yjit.rb
│   │   ├── filter_parameter_logging.rb
│   │   ├── generator.rb
│   │   ├── inflections.rb
│   │   ├── intercom.rb
│   │   ├── mini_profiler.rb
│   │   ├── pagy.rb
│   │   ├── permissions_policy.rb
│   │   ├── plaid.rb
│   │   ├── rack_attack.rb
│   │   ├── sentry.rb
│   │   ├── sidekiq.rb
│   │   └── version.rb
│   ├── locales/
│   │   ├── defaults/
│   │   │   ├── af.yml
│   │   │   ├── ar.yml
│   │   │   ├── az.yml
│   │   │   ├── be.yml
│   │   │   ├── bg.yml
│   │   │   ├── bn.yml
│   │   │   ├── bs.yml
│   │   │   ├── ca.yml
│   │   │   ├── cs.yml
│   │   │   ├── cy.yml
│   │   │   ├── da.yml
│   │   │   ├── de-AT.yml
│   │   │   ├── de-CH.yml
│   │   │   ├── de-DE.yml
│   │   │   ├── de.yml
│   │   │   ├── dz.yml
│   │   │   ├── el-CY.yml
│   │   │   ├── el.yml
│   │   │   ├── en-AU.yml
│   │   │   ├── en-CA.yml
│   │   │   ├── en-CY.yml
│   │   │   ├── en-GB.yml
│   │   │   ├── en-IE.yml
│   │   │   ├── en-IN.yml
│   │   │   ├── en-NZ.yml
│   │   │   ├── en-TT.yml
│   │   │   ├── en-US.yml
│   │   │   ├── en-ZA.yml
│   │   │   ├── en.yml
│   │   │   ├── eo.yml
│   │   │   ├── es-419.yml
│   │   │   ├── es-AR.yml
│   │   │   ├── es-CL.yml
│   │   │   ├── es-CO.yml
│   │   │   ├── es-CR.yml
│   │   │   ├── es-EC.yml
│   │   │   ├── es-ES.yml
│   │   │   ├── es-MX.yml
│   │   │   ├── es-NI.yml
│   │   │   ├── es-PA.yml
│   │   │   ├── es-PE.yml
│   │   │   ├── es-US.yml
│   │   │   ├── es-VE.yml
│   │   │   ├── es.yml
│   │   │   ├── et.yml
│   │   │   ├── eu.yml
│   │   │   ├── fa.yml
│   │   │   ├── fi.yml
│   │   │   ├── fr-CA.yml
│   │   │   ├── fr-CH.yml
│   │   │   ├── fr-FR.yml
│   │   │   ├── fr.yml
│   │   │   ├── fy.yml
│   │   │   ├── gd.yml
│   │   │   ├── gl.yml
│   │   │   ├── he.yml
│   │   │   ├── hi-IN.yml
│   │   │   ├── hi.yml
│   │   │   ├── hr.yml
│   │   │   ├── hu.yml
│   │   │   ├── id.yml
│   │   │   ├── is.yml
│   │   │   ├── it-CH.yml
│   │   │   ├── it.yml
│   │   │   ├── ja.yml
│   │   │   ├── ka.yml
│   │   │   ├── kk.yml
│   │   │   ├── km.yml
│   │   │   ├── kn.yml
│   │   │   ├── ko.yml
│   │   │   ├── lb.yml
│   │   │   ├── lo.yml
│   │   │   ├── lt.yml
│   │   │   ├── lv.yml
│   │   │   ├── mg.yml
│   │   │   ├── mk.yml
│   │   │   ├── ml.yml
│   │   │   ├── mn.yml
│   │   │   ├── mr-IN.yml
│   │   │   ├── ms.yml
│   │   │   ├── nb.yml
│   │   │   ├── ne.yml
│   │   │   ├── nl.yml
│   │   │   ├── nn.yml
│   │   │   ├── oc.yml
│   │   │   ├── or.yml
│   │   │   ├── pa.yml
│   │   │   ├── pl.yml
│   │   │   ├── pt-BR.yml
│   │   │   ├── pt.yml
│   │   │   ├── rm.yml
│   │   │   ├── ro.yml
│   │   │   ├── ru.yml
│   │   │   ├── sc.yml
│   │   │   ├── sk.yml
│   │   │   ├── sl.yml
│   │   │   ├── sq.yml
│   │   │   ├── sr.yml
│   │   │   ├── st.yml
│   │   │   ├── sv-FI.yml
│   │   │   ├── sv-SE.yml
│   │   │   ├── sv.yml
│   │   │   ├── sw.yml
│   │   │   ├── ta.yml
│   │   │   ├── te.yml
│   │   │   ├── th.yml
│   │   │   ├── tl.yml
│   │   │   ├── tr.yml
│   │   │   ├── tt.yml
│   │   │   ├── ug.yml
│   │   │   ├── uk.yml
│   │   │   ├── ur.yml
│   │   │   ├── uz.yml
│   │   │   ├── vi.yml
│   │   │   ├── wo.yml
│   │   │   ├── zh-CN.yml
│   │   │   └── zh-TW.yml
│   │   ├── doorkeeper.en.yml
│   │   ├── mailers/
│   │   │   └── invitation_mailer/
│   │   │       └── en.yml
│   │   ├── models/
│   │   │   ├── account/
│   │   │   │   └── en.yml
│   │   │   ├── address/
│   │   │   │   └── en.yml
│   │   │   ├── entry/
│   │   │   │   └── en.yml
│   │   │   ├── import/
│   │   │   │   └── en.yml
│   │   │   ├── time_series/
│   │   │   │   └── value/
│   │   │   │       └── en.yml
│   │   │   ├── transfer/
│   │   │   │   └── en.yml
│   │   │   ├── trend/
│   │   │   │   └── en.yml
│   │   │   └── user/
│   │   │       └── en.yml
│   │   └── views/
│   │       ├── accounts/
│   │       │   └── en.yml
│   │       ├── application/
│   │       │   └── en.yml
│   │       ├── categories/
│   │       │   └── en.yml
│   │       ├── category/
│   │       │   ├── deletions/
│   │       │   │   └── en.yml
│   │       │   └── dropdowns/
│   │       │       └── en.yml
│   │       ├── credit_cards/
│   │       │   └── en.yml
│   │       ├── cryptos/
│   │       │   └── en.yml
│   │       ├── depositories/
│   │       │   └── en.yml
│   │       ├── email_confirmation_mailer/
│   │       │   └── en.yml
│   │       ├── entries/
│   │       │   └── en.yml
│   │       ├── holdings/
│   │       │   └── en.yml
│   │       ├── impersonation_sessions/
│   │       │   └── en.yml
│   │       ├── imports/
│   │       │   └── en.yml
│   │       ├── investments/
│   │       │   └── en.yml
│   │       ├── invitation_mailer/
│   │       │   └── en.yml
│   │       ├── invitations/
│   │       │   └── en.yml
│   │       ├── invite_codes/
│   │       │   └── en.yml
│   │       ├── layout/
│   │       │   └── en.yml
│   │       ├── loans/
│   │       │   └── en.yml
│   │       ├── merchants/
│   │       │   └── en.yml
│   │       ├── mfa/
│   │       │   └── en.yml
│   │       ├── onboardings/
│   │       │   └── en.yml
│   │       ├── other_assets/
│   │       │   └── en.yml
│   │       ├── other_liabilities/
│   │       │   └── en.yml
│   │       ├── pages/
│   │       │   └── en.yml
│   │       ├── password_mailer/
│   │       │   └── en.yml
│   │       ├── password_resets/
│   │       │   └── en.yml
│   │       ├── passwords/
│   │       │   └── en.yml
│   │       ├── plaid_items/
│   │       │   └── en.yml
│   │       ├── properties/
│   │       │   └── en.yml
│   │       ├── registrations/
│   │       │   └── en.yml
│   │       ├── sessions/
│   │       │   └── en.yml
│   │       ├── settings/
│   │       │   ├── api_keys/
│   │       │   │   └── en.yml
│   │       │   ├── en.yml
│   │       │   ├── hostings/
│   │       │   │   └── en.yml
│   │       │   └── securities/
│   │       │       └── en.yml
│   │       ├── shared/
│   │       │   └── en.yml
│   │       ├── subscriptions/
│   │       │   └── en.yml
│   │       ├── tag/
│   │       │   └── deletions/
│   │       │       └── en.yml
│   │       ├── tags/
│   │       │   └── en.yml
│   │       ├── trades/
│   │       │   └── en.yml
│   │       ├── transactions/
│   │       │   └── en.yml
│   │       ├── transfers/
│   │       │   └── en.yml
│   │       ├── users/
│   │       │   └── en.yml
│   │       ├── valuations/
│   │       │   └── en.yml
│   │       └── vehicles/
│   │           └── en.yml
│   ├── puma.rb
│   ├── routes.rb
│   ├── schedule.yml
│   ├── sidekiq.yml
│   └── storage.yml
├── config.ru
├── db/
│   ├── migrate/
│   │   ├── 20240201183314_enable_uuid.rb
│   │   ├── 20240201184038_create_families.rb
│   │   ├── 20240201184212_create_users.rb
│   │   ├── 20240202015428_create_accounts.rb
│   │   ├── 20240202191425_create_account_loans.rb
│   │   ├── 20240202191746_add_accountable_to_account.rb
│   │   ├── 20240202192214_create_account_depositories.rb
│   │   ├── 20240202192231_create_account_credits.rb
│   │   ├── 20240202192238_create_account_investments.rb
│   │   ├── 20240202192312_create_account_properties.rb
│   │   ├── 20240202192319_create_account_vehicles.rb
│   │   ├── 20240202192327_create_account_other_assets.rb
│   │   ├── 20240202192333_create_account_other_liabilities.rb
│   │   ├── 20240202230325_create_invite_codes.rb
│   │   ├── 20240203030754_remove_type_from_accounts.rb
│   │   ├── 20240203050018_add_token_index_to_invite_codes.rb
│   │   ├── 20240206031739_replace_money_field.rb
│   │   ├── 20240209153232_add_currency_to_families.rb
│   │   ├── 20240209174912_redo_money_storage.rb
│   │   ├── 20240209200519_create_currencies.rb
│   │   ├── 20240209200924_create_exchange_rates.rb
│   │   ├── 20240210155058_create_good_jobs.rb
│   │   ├── 20240212150110_create_account_balances.rb
│   │   ├── 20240215201527_create_valuations.rb
│   │   ├── 20240221004818_remove_valuation_type.rb
│   │   ├── 20240222144849_add_status_to_account.rb
│   │   ├── 20240223162105_create_transactions.rb
│   │   ├── 20240227142457_rename_account_balance.rb
│   │   ├── 20240302145715_add_classification_to_accounts.rb
│   │   ├── 20240306193345_add_is_active_to_account.rb
│   │   ├── 20240307082827_create_transaction_categories.rb
│   │   ├── 20240308121431_remove_currency_table.rb
│   │   ├── 20240308214956_add_notes_and_excluded_to_transaction.rb
│   │   ├── 20240309180636_add_sync_status_fields_to_account.rb
│   │   ├── 20240313141813_update_unique_indexes_for_account_balance_and_exchange_rate.rb
│   │   ├── 20240313203622_remove_converted_balance_from_account.rb
│   │   ├── 20240319154732_create_account_cryptos.rb
│   │   ├── 20240325064211_add_uniq_index_to_users_email.rb
│   │   ├── 20240401213443_add_last_sync_date_to_accounts.rb
│   │   ├── 20240403192649_add_last_login_at_to_users.rb
│   │   ├── 20240404112829_change_transaction_category_delete_behavior.rb
│   │   ├── 20240410183531_create_settings.rb
│   │   ├── 20240411102931_add_last_seen_upgrade_to_user.rb
│   │   ├── 20240425000110_add_role_to_users.rb
│   │   ├── 20240426162500_create_active_storage_tables.active_storage.rb
│   │   ├── 20240426191312_add_transaction_merchants.rb
│   │   ├── 20240430111641_add_active_to_users.rb
│   │   ├── 20240502205006_create_imports.rb
│   │   ├── 20240520074309_add_admin_role_to_current_users.rb
│   │   ├── 20240522133147_create_tags.rb
│   │   ├── 20240522151453_create_taggings.rb
│   │   ├── 20240524203959_change_account_error_columns_default.rb
│   │   ├── 20240612164751_create_institutions.rb
│   │   ├── 20240612164944_add_institution_to_accounts.rb
│   │   ├── 20240614120946_create_transfers.rb
│   │   ├── 20240614121110_add_transfer_fields_to_transaction.rb
│   │   ├── 20240619125949_rename_accountable_tables.rb
│   │   ├── 20240620114307_rename_categories_table.rb
│   │   ├── 20240620122201_rename_merchants_table.rb
│   │   ├── 20240620125026_rename_transfer_table.rb
│   │   ├── 20240620221801_rename_valuation_table.rb
│   │   ├── 20240621212528_rename_transactions_table.rb
│   │   ├── 20240624160611_create_account_entries.rb
│   │   ├── 20240624161153_migrate_entryables.rb
│   │   ├── 20240624164119_remove_old_columns_from_entryables.rb
│   │   ├── 20240628104551_move_transfers_association_from_transactions_to_entries.rb
│   │   ├── 20240706151026_rename_rate_fields.rb
│   │   ├── 20240707130331_create_account_syncs.rb
│   │   ├── 20240709113713_create_good_job_execution_error_backtrace.rb
│   │   ├── 20240709113714_create_good_job_process_lock_ids.rb
│   │   ├── 20240709113715_create_good_job_process_lock_indexes.rb
│   │   ├── 20240709152243_create_good_job_execution_duration.rb
│   │   ├── 20240710182529_create_securities.rb
│   │   ├── 20240710182728_create_security_prices.rb
│   │   ├── 20240710184048_create_account_trades.rb
│   │   ├── 20240710184249_create_account_holdings.rb
│   │   ├── 20240717113535_remove_default_from_account_balance.rb
│   │   ├── 20240725163339_add_last_synced_at_to_family.rb
│   │   ├── 20240731191344_change_primary_identifier_for_security.rb
│   │   ├── 20240807153618_add_currency_field_to_trade.rb
│   │   ├── 20240813170608_fix_invalid_accountable_data.rb
│   │   ├── 20240815125404_create_issues.rb
│   │   ├── 20240815190722_remove_warnings_from_sync.rb
│   │   ├── 20240816071555_add_col_sep_to_imports.rb
│   │   ├── 20240817144454_rename_import_raw_csv_str_to_raw_file_str.rb
│   │   ├── 20240822174006_create_addresses.rb
│   │   ├── 20240822180845_add_property_attributes.rb
│   │   ├── 20240823125526_add_details_to_vehicle.rb
│   │   ├── 20240911143158_add_last_synced_at_institution.rb
│   │   ├── 20240921170426_change_import_owner.rb
│   │   ├── 20240925112218_add_import_types.rb
│   │   ├── 20241001181256_add_locale_preference.rb
│   │   ├── 20241003163448_create_sessions.rb
│   │   ├── 20241007211438_add_billing_to_families.rb
│   │   ├── 20241008122449_add_debt_account_views.rb
│   │   ├── 20241009132959_add_notes_to_entry.rb
│   │   ├── 20241009214601_add_super_admin_to_users.rb
│   │   ├── 20241017162347_create_impersonation_sessions.rb
│   │   ├── 20241017162536_create_impersonation_session_logs.rb
│   │   ├── 20241017204250_add_accounts_indexes.rb
│   │   ├── 20241018201653_add_account_mode.rb
│   │   ├── 20241022170439_create_stock_exchanges.rb
│   │   ├── 20241022192319_fix_user_role_column_type.rb
│   │   ├── 20241022221544_add_onboarding_fields.rb
│   │   ├── 20241023195438_add_stock_exchange_reference.rb
│   │   ├── 20241024142537_add_subscription_timestamp_to_session.rb
│   │   ├── 20241025174650_add_mic_to_securities.rb
│   │   ├── 20241025182612_add_search_vector_to_securities.rb
│   │   ├── 20241029125406_add_reference_to_security_prices.rb
│   │   ├── 20241029184115_remove_prices_missing_issue.rb
│   │   ├── 20241029234028_remove_search_vector.rb
│   │   ├── 20241030121302_fix_not_null_stock_exchange_data.rb
│   │   ├── 20241030151105_remove_account_mode.rb
│   │   ├── 20241030222235_create_invitations.rb
│   │   ├── 20241106193743_add_plaid_domain.rb
│   │   ├── 20241108150422_add_unique_email_index_to_invitations.rb
│   │   ├── 20241114164118_add_products_to_plaid_item.rb
│   │   ├── 20241122183828_change_loan_interest_rate_precision.rb.rb
│   │   ├── 20241126211249_add_logo_url_to_security.rb
│   │   ├── 20241204235400_add_balance_components.rb
│   │   ├── 20241207002408_add_family_timezone.rb
│   │   ├── 20241212141453_add_merchant_logo.rb
│   │   ├── 20241217141716_add_enrichment_setting.rb
│   │   ├── 20241218132503_add_enriched_name_field.rb
│   │   ├── 20241219151540_add_region_to_plaid_item.rb
│   │   ├── 20241219174803_add_parent_category.rb
│   │   ├── 20241227142333_add_error_trace_to_syncs.rb
│   │   ├── 20241231140709_reverse_transfer_relations.rb
│   │   ├── 20250108182147_create_budgets.rb
│   │   ├── 20250108200055_create_budget_categories.rb
│   │   ├── 20250110012347_category_classification.rb
│   │   ├── 20250120210449_align_transfer_cascade_behavior.rb
│   │   ├── 20250124224316_create_rejected_transfers.rb
│   │   ├── 20250128203303_store_transaction_filters_in_session.rb
│   │   ├── 20250130191533_add_email_confirmation_to_users.rb
│   │   ├── 20250130214500_remove_email_confirmation_sent_at_from_users.rb
│   │   ├── 20250131171943_remove_email_confirmation_token_from_users.rb
│   │   ├── 20250206003115_remove_import_status_enum.rb
│   │   ├── 20250206141452_add_institution_details_to_plaid_items.rb
│   │   ├── 20250206151825_add_mfa_fields_to_users.rb
│   │   ├── 20250206204404_add_constraints_to_account_holdings.rb
│   │   ├── 20250207011850_add_exchange_operating_mic_to_securities.rb
│   │   ├── 20250207014022_add_number_format_to_imports.rb
│   │   ├── 20250207194638_adjust_securities_indexes.rb
│   │   ├── 20250211161238_make_ticker_not_null.rb
│   │   ├── 20250212163624_add_status_to_plaid_items.rb
│   │   ├── 20250212213301_add_user_sidebar_preference.rb
│   │   ├── 20250220153958_update_imports_for_operating_mic_v2.rb
│   │   ├── 20250220200735_add_default_lucide_icon_to_categories.rb
│   │   ├── 20250303141007_add_optional_account_for_import.rb
│   │   ├── 20250304140435_add_default_period_to_users.rb
│   │   ├── 20250304200956_add_signage_type_to_imports.rb
│   │   ├── 20250315191233_remove_ticker_from_security_prices.rb
│   │   ├── 20250316103753_remove_issues.rb
│   │   ├── 20250316122019_security_price_unique_index.rb
│   │   ├── 20250318212559_remove_good_job.rb
│   │   ├── 20250319145426_remove_self_host_upgrades.rb
│   │   ├── 20250319212839_create_ai_chats.rb
│   │   ├── 20250405210514_add_initial_balance_field.rb
│   │   ├── 20250410144939_add_theme_to_users.rb
│   │   ├── 20250411140604_add_parent_syncs.rb
│   │   ├── 20250413141446_table_renames.rb
│   │   ├── 20250416235317_add_rules_engine.rb
│   │   ├── 20250416235420_add_data_enrichments.rb
│   │   ├── 20250416235758_merchant_and_category_enrichment.rb
│   │   ├── 20250429021255_add_name_to_rules.rb
│   │   ├── 20250501172430_add_user_goals.rb
│   │   ├── 20250502164951_create_subscriptions.rb
│   │   ├── 20250509182903_dynamic_last_synced.rb
│   │   ├── 20250512171654_update_sync_timestamps.rb
│   │   ├── 20250513122703_add_uniqueness_to_subscriptions.rb
│   │   ├── 20250514214242_add_metadata_to_session.rb
│   │   ├── 20250516180846_remove_stock_exchanges.rb
│   │   ├── 20250518181619_add_auto_sync_preference_to_family.rb
│   │   ├── 20250521112347_add_security_resolver_fields.rb
│   │   ├── 20250522201031_stronger_unique_index_on_security.rb
│   │   ├── 20250523131455_add_raw_payloads_to_plaid_accounts.rb
│   │   ├── 20250605031616_add_index_to_sync_status.rb
│   │   ├── 20250610181219_add_sync_timestamps_to_family.rb
│   │   ├── 20250612150749_create_doorkeeper_tables.rb
│   │   ├── 20250612154522_fix_doorkeeper_resource_owner_id_for_uuid.rb
│   │   ├── 20250613002027_create_api_keys.rb
│   │   ├── 20250613100842_add_display_key_to_api_keys.rb
│   │   ├── 20250613101036_remove_key_from_api_keys.rb
│   │   ├── 20250613101051_remove_key_index_from_api_keys.rb
│   │   ├── 20250613152743_fix_doorkeeper_access_grants_resource_owner_id_for_uuid.rb
│   │   ├── 20250616183654_add_kind_to_transactions.rb
│   │   ├── 20250618104425_add_source_to_api_keys.rb
│   │   ├── 20250618110104_create_mobile_devices.rb
│   │   ├── 20250618110736_add_owner_to_oauth_applications.rb
│   │   ├── 20250618120703_add_oauth_application_to_mobile_devices.rb
│   │   ├── 20250620204550_update_excluded_transactions_to_one_time.rb
│   │   ├── 20250623162207_update_outdated_timezones.rb
│   │   ├── 20250701161640_add_account_status.rb
│   │   ├── 20250702173231_fix_mobile_devices_unique_constraint.rb
│   │   ├── 20250710225721_add_valuation_kind.rb
│   │   ├── 20250718120146_add_indexes_to_core_models.rb
│   │   ├── 20250719121103_add_start_end_columns_to_balances.rb
│   │   └── 20250724115507_create_family_exports.rb
│   ├── schema.rb
│   ├── seeds/
│   │   ├── .keep
│   │   └── oauth_applications.rb
│   └── seeds.rb
├── docs/
│   ├── api/
│   │   └── chats.md
│   └── hosting/
│       └── docker.md
├── lib/
│   ├── assets/
│   │   └── .keep
│   ├── money/
│   │   ├── arithmetic.rb
│   │   ├── currency.rb
│   │   └── formatting.rb
│   ├── money.rb
│   ├── semver.rb
│   └── tasks/
│       ├── benchmarking.rake
│       ├── data_migration.rake
│       ├── demo_data.rake
│       ├── invites.rake
│       ├── securities.rake
│       └── stripe.rake
├── log/
│   └── .keep
├── package.json
├── perf.rake
├── public/
│   ├── 404.html
│   ├── 406-unsupported-browser.html
│   ├── 422.html
│   ├── 426.html
│   ├── 500.html
│   ├── browserconfig.xml
│   ├── robots.txt
│   └── site.webmanifest
├── storage/
│   └── .keep
├── test/
│   ├── application_system_test_case.rb
│   ├── channels/
│   │   └── application_cable/
│   │       └── connection_test.rb
│   ├── components/
│   │   └── previews/
│   │       ├── alert_component_preview.rb
│   │       ├── button_component_preview.rb
│   │       ├── dialog_component_preview.rb
│   │       ├── disclosure_component_preview.rb
│   │       ├── filled_icon_component_preview.rb
│   │       ├── link_component_preview.rb
│   │       ├── menu_component_preview.rb
│   │       ├── tabs_component_preview/
│   │       │   ├── custom.html.erb
│   │       │   └── default.html.erb
│   │       ├── tabs_component_preview.rb
│   │       ├── toggle_component_preview.rb
│   │       └── tooltip_component_preview.rb
│   ├── controllers/
│   │   ├── accountable_sparklines_controller_test.rb
│   │   ├── accounts_controller_test.rb
│   │   ├── api/
│   │   │   └── v1/
│   │   │       ├── accounts_controller_test.rb
│   │   │       ├── auth_controller_test.rb
│   │   │       ├── base_controller_test.rb
│   │   │       ├── chats_controller_test.rb
│   │   │       ├── messages_controller_test.rb
│   │   │       ├── transactions_controller_test.rb
│   │   │       └── usage_controller_test.rb
│   │   ├── categories_controller_test.rb
│   │   ├── category/
│   │   │   └── deletions_controller_test.rb
│   │   ├── chats_controller_test.rb
│   │   ├── concerns/
│   │   │   ├── auto_sync_test.rb
│   │   │   └── onboardable_test.rb
│   │   ├── credit_cards_controller_test.rb
│   │   ├── cryptos_controller_test.rb
│   │   ├── currencies_controller_test.rb
│   │   ├── current_sessions_controller_test.rb
│   │   ├── depositories_controller_test.rb
│   │   ├── email_confirmations_controller_test.rb
│   │   ├── family_exports_controller_test.rb
│   │   ├── family_merchants_controller_test.rb
│   │   ├── holdings_controller_test.rb
│   │   ├── impersonation_sessions_controller_test.rb
│   │   ├── import/
│   │   │   ├── cleans_controller_test.rb
│   │   │   ├── configurations_controller_test.rb
│   │   │   ├── confirms_controller_test.rb
│   │   │   ├── mappings_controller_test.rb
│   │   │   ├── rows_controller_test.rb
│   │   │   └── uploads_controller_test.rb
│   │   ├── imports_controller_test.rb
│   │   ├── investments_controller_test.rb
│   │   ├── invitations_controller_test.rb
│   │   ├── invite_codes_controller_test.rb
│   │   ├── loans_controller_test.rb
│   │   ├── messages_controller_test.rb
│   │   ├── mfa_controller_test.rb
│   │   ├── onboardings_controller_test.rb
│   │   ├── other_assets_controller_test.rb
│   │   ├── other_liabilities_controller_test.rb
│   │   ├── pages_controller_test.rb
│   │   ├── password_resets_controller_test.rb
│   │   ├── plaid_items_controller_test.rb
│   │   ├── properties_controller_test.rb
│   │   ├── registrations_controller_test.rb
│   │   ├── rules_controller_test.rb
│   │   ├── sessions_controller_test.rb
│   │   ├── settings/
│   │   │   ├── api_keys_controller_test.rb
│   │   │   ├── billings_controller_test.rb
│   │   │   ├── hostings_controller_test.rb
│   │   │   ├── preferences_controller_test.rb
│   │   │   └── profiles_controller_test.rb
│   │   ├── subscriptions_controller_test.rb
│   │   ├── tag/
│   │   │   └── deletions_controller_test.rb
│   │   ├── tags_controller_test.rb
│   │   ├── trades_controller_test.rb
│   │   ├── transactions/
│   │   │   ├── bulk_deletions_controller_test.rb
│   │   │   └── bulk_updates_controller_test.rb
│   │   ├── transactions_controller_test.rb
│   │   ├── transfer_matches_controller_test.rb
│   │   ├── transfers_controller_test.rb
│   │   ├── users_controller_test.rb
│   │   ├── valuations_controller_test.rb
│   │   ├── vehicles_controller_test.rb
│   │   └── webhooks_controller_test.rb
│   ├── data_migrations/
│   │   └── balance_component_migrator_test.rb
│   ├── fixtures/
│   │   ├── accounts.yml
│   │   ├── active_storage/
│   │   │   ├── attachments.yml
│   │   │   └── blobs.yml
│   │   ├── addresses.yml
│   │   ├── api_keys.yml
│   │   ├── balances.yml
│   │   ├── budgets.yml
│   │   ├── categories.yml
│   │   ├── chats.yml
│   │   ├── credit_cards.yml
│   │   ├── cryptos.yml
│   │   ├── depositories.yml
│   │   ├── entries.yml
│   │   ├── exchange_rates.yml
│   │   ├── families.yml
│   │   ├── family_exports.yml
│   │   ├── files/
│   │   │   └── imports/
│   │   │       ├── accounts.csv
│   │   │       ├── invalid.csv
│   │   │       ├── mint.csv
│   │   │       ├── trades.csv
│   │   │       ├── transactions.csv
│   │   │       └── valid.csv
│   │   ├── holdings.yml
│   │   ├── impersonation_session_logs.yml
│   │   ├── impersonation_sessions.yml
│   │   ├── import/
│   │   │   ├── mappings.yml
│   │   │   └── rows.yml
│   │   ├── imports.yml
│   │   ├── investments.yml
│   │   ├── invitations.yml
│   │   ├── loans.yml
│   │   ├── merchants.yml
│   │   ├── messages.yml
│   │   ├── mobile_devices.yml
│   │   ├── other_assets.yml
│   │   ├── other_liabilities.yml
│   │   ├── plaid_accounts.yml
│   │   ├── plaid_items.yml
│   │   ├── properties.yml
│   │   ├── rule/
│   │   │   ├── actions.yml
│   │   │   └── conditions.yml
│   │   ├── rules.yml
│   │   ├── securities.yml
│   │   ├── security/
│   │   │   └── prices.yml
│   │   ├── sessions.yml
│   │   ├── subscriptions.yml
│   │   ├── syncs.yml
│   │   ├── taggings.yml
│   │   ├── tags.yml
│   │   ├── tool_calls.yml
│   │   ├── trades.yml
│   │   ├── transactions.yml
│   │   ├── transfers.yml
│   │   ├── users.yml
│   │   ├── valuations.yml
│   │   └── vehicles.yml
│   ├── helpers/
│   │   ├── .keep
│   │   └── application_helper_test.rb
│   ├── i18n_test.rb
│   ├── integration/
│   │   ├── oauth_basic_test.rb
│   │   ├── oauth_mobile_test.rb
│   │   └── rack_attack_test.rb
│   ├── interfaces/
│   │   ├── accountable_resource_interface_test.rb
│   │   ├── entryable_resource_interface_test.rb
│   │   ├── exchange_rate_provider_interface_test.rb
│   │   ├── import_interface_test.rb
│   │   ├── llm_interface_test.rb
│   │   ├── security_provider_interface_test.rb
│   │   └── syncable_interface_test.rb
│   ├── jobs/
│   │   ├── family_data_export_job_test.rb
│   │   ├── import_job_test.rb
│   │   ├── stripe_event_handler_job_test.rb
│   │   └── sync_job_test.rb
│   ├── lib/
│   │   ├── money/
│   │   │   └── currency_test.rb
│   │   └── money_test.rb
│   ├── mailers/
│   │   ├── email_confirmation_mailer_test.rb
│   │   ├── password_mailer_test.rb
│   │   └── previews/
│   │       ├── email_confirmation_mailer_preview.rb
│   │       └── password_mailer_preview.rb
│   ├── models/
│   │   ├── account/
│   │   │   ├── activity_feed_data_test.rb
│   │   │   ├── chartable_test.rb
│   │   │   ├── current_balance_manager_test.rb
│   │   │   ├── entry_test.rb
│   │   │   ├── market_data_importer_test.rb
│   │   │   ├── opening_balance_manager_test.rb
│   │   │   ├── reconciliation_manager_test.rb
│   │   │   └── transaction_test.rb
│   │   ├── account_import_test.rb
│   │   ├── account_test.rb
│   │   ├── address_test.rb
│   │   ├── api_key_test.rb
│   │   ├── assistant_message_test.rb
│   │   ├── assistant_test.rb
│   │   ├── balance/
│   │   │   ├── chart_series_builder_test.rb
│   │   │   ├── forward_calculator_test.rb
│   │   │   ├── materializer_test.rb
│   │   │   └── reverse_calculator_test.rb
│   │   ├── balance_sheet_test.rb
│   │   ├── budget_test.rb
│   │   ├── category_test.rb
│   │   ├── chat_test.rb
│   │   ├── concerns/
│   │   │   └── enrichable_test.rb
│   │   ├── current_test.rb
│   │   ├── developer_message_test.rb
│   │   ├── exchange_rate/
│   │   │   └── importer_test.rb
│   │   ├── exchange_rate_test.rb
│   │   ├── family/
│   │   │   ├── auto_categorizer_test.rb
│   │   │   ├── auto_merchant_detector_test.rb
│   │   │   ├── auto_transfer_matchable_test.rb
│   │   │   ├── data_exporter_test.rb
│   │   │   ├── subscribeable_test.rb
│   │   │   └── syncer_test.rb
│   │   ├── family_export_test.rb
│   │   ├── family_test.rb
│   │   ├── holding/
│   │   │   ├── forward_calculator_test.rb
│   │   │   ├── materializer_test.rb
│   │   │   ├── portfolio_cache_test.rb
│   │   │   ├── portfolio_snapshot_test.rb
│   │   │   └── reverse_calculator_test.rb
│   │   ├── holding_test.rb
│   │   ├── impersonation_session_test.rb
│   │   ├── income_statement_test.rb
│   │   ├── invite_code_test.rb
│   │   ├── loan_test.rb
│   │   ├── market_data_importer_test.rb
│   │   ├── mobile_device_test.rb
│   │   ├── period_test.rb
│   │   ├── plaid_account/
│   │   │   ├── importer_test.rb
│   │   │   ├── investments/
│   │   │   │   ├── balance_calculator_test.rb
│   │   │   │   ├── holdings_processor_test.rb
│   │   │   │   ├── security_resolver_test.rb
│   │   │   │   └── transactions_processor_test.rb
│   │   │   ├── liabilities/
│   │   │   │   ├── credit_processor_test.rb
│   │   │   │   ├── mortgage_processor_test.rb
│   │   │   │   └── student_loan_processor_test.rb
│   │   │   ├── processor_test.rb
│   │   │   ├── transactions/
│   │   │   │   ├── category_matcher_test.rb
│   │   │   │   └── processor_test.rb
│   │   │   └── type_mappable_test.rb
│   │   ├── plaid_entry/
│   │   │   └── processor_test.rb
│   │   ├── plaid_item/
│   │   │   ├── accounts_snapshot_test.rb
│   │   │   └── importer_test.rb
│   │   ├── plaid_item_test.rb
│   │   ├── provider/
│   │   │   ├── openai_test.rb
│   │   │   ├── plaid_test.rb
│   │   │   ├── registry_test.rb
│   │   │   ├── stripe/
│   │   │   │   └── subscription_event_processor_test.rb
│   │   │   ├── stripe_test.rb
│   │   │   └── synth_test.rb
│   │   ├── provider_test.rb
│   │   ├── rule/
│   │   │   ├── action_test.rb
│   │   │   └── condition_test.rb
│   │   ├── rule_test.rb
│   │   ├── security/
│   │   │   ├── health_checker_test.rb
│   │   │   ├── price/
│   │   │   │   └── importer_test.rb
│   │   │   ├── price_test.rb
│   │   │   └── resolver_test.rb
│   │   ├── security_test.rb
│   │   ├── subscription_test.rb
│   │   ├── sync_test.rb
│   │   ├── tag_test.rb
│   │   ├── trade_import_test.rb
│   │   ├── trade_test.rb
│   │   ├── transaction/
│   │   │   └── search_test.rb
│   │   ├── transaction_import_test.rb
│   │   ├── transfer/
│   │   │   └── creator_test.rb
│   │   ├── transfer_test.rb
│   │   ├── trend_test.rb
│   │   ├── user_message_test.rb
│   │   ├── user_test.rb
│   │   └── valuation/
│   │       └── name_test.rb
│   ├── services/
│   │   ├── api_rate_limiter_test.rb
│   │   └── noop_api_rate_limiter_test.rb
│   ├── support/
│   │   ├── balance_test_helper.rb
│   │   ├── entries_test_helper.rb
│   │   ├── ledger_testing_helper.rb
│   │   ├── provider_test_helper.rb
│   │   └── securities_test_helper.rb
│   ├── system/
│   │   ├── accounts_test.rb
│   │   ├── categories_test.rb
│   │   ├── chats_test.rb
│   │   ├── imports_test.rb
│   │   ├── onboardings_test.rb
│   │   ├── settings/
│   │   │   └── api_keys_test.rb
│   │   ├── settings_test.rb
│   │   ├── trades_test.rb
│   │   ├── transactions_test.rb
│   │   └── transfers_test.rb
│   ├── test_helper.rb
│   └── vcr_cassettes/
│       ├── git_repository_provider/
│       │   └── fetch_latest_release_notes.yml
│       ├── openai/
│       │   ├── auto_categorize.yml
│       │   ├── auto_detect_merchants.yml
│       │   └── chat/
│       │       ├── basic_response.yml
│       │       ├── basic_streaming_response.yml
│       │       ├── error.yml
│       │       ├── function_calls.yml
│       │       └── streaming_function_calls.yml
│       ├── plaid/
│       │   ├── access_token.yml
│       │   ├── exchange_public_token.yml
│       │   ├── get_item.yml
│       │   ├── get_item_accounts.yml
│       │   ├── get_item_investments.yml
│       │   ├── get_item_liabilities.yml
│       │   └── link_token.yml
│       ├── stripe/
│       │   ├── checkout_session.yml
│       │   └── create_checkout_session.yml
│       └── synth/
│           ├── exchange_rate.yml
│           ├── exchange_rates.yml
│           ├── health.yml
│           ├── security_info.yml
│           ├── security_price.yml
│           ├── security_prices.yml
│           ├── security_search.yml
│           └── usage.yml
├── tmp/
│   └── .keep
└── vendor/
    ├── .keep
    └── javascript/
        ├── .keep
        ├── @floating-ui--core.js
        ├── @floating-ui--dom.js
        ├── @floating-ui--utils--dom.js
        ├── @floating-ui--utils.js
        ├── @github--hotkey.js
        ├── @simonwep--pickr.js
        ├── d3-array.js
        ├── d3-axis.js
        ├── d3-brush.js
        ├── d3-chord.js
        ├── d3-color.js
        ├── d3-contour.js
        ├── d3-delaunay.js
        ├── d3-dispatch.js
        ├── d3-drag.js
        ├── d3-dsv.js
        ├── d3-ease.js
        ├── d3-fetch.js
        ├── d3-force.js
        ├── d3-format.js
        ├── d3-geo.js
        ├── d3-hierarchy.js
        ├── d3-interpolate.js
        ├── d3-path.js
        ├── d3-polygon.js
        ├── d3-quadtree.js
        ├── d3-random.js
        ├── d3-sankey.js
        ├── d3-scale-chromatic.js
        ├── d3-scale.js
        ├── d3-selection.js
        ├── d3-shape.js
        ├── d3-time-format.js
        ├── d3-time.js
        ├── d3-timer.js
        ├── d3-transition.js
        ├── d3-zoom.js
        ├── d3.js
        ├── delaunator.js
        ├── internmap.js
        └── robust-predicates.js
Download .txt
Showing preview only (407K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4709 symbols across 853 files)

FILE: app/channels/application_cable/channel.rb
  type ApplicationCable (line 1) | module ApplicationCable
    class Channel (line 2) | class Channel < ActionCable::Channel::Base

FILE: app/channels/application_cable/connection.rb
  type ApplicationCable (line 1) | module ApplicationCable
    class Connection (line 2) | class Connection < ActionCable::Connection::Base
      method report_error (line 6) | def report_error(e)

FILE: app/components/DS/alert.rb
  class DS::Alert (line 1) | class DS::Alert < DesignSystemComponent
    method initialize (line 2) | def initialize(message:, variant: :info)
    method container_classes (line 10) | def container_classes
    method icon_name (line 27) | def icon_name
    method icon_color (line 40) | def icon_color

FILE: app/components/DS/button.rb
  class DS::Button (line 5) | class DS::Button < DS::Buttonish
    method initialize (line 8) | def initialize(confirm: nil, **opts)
    method container (line 13) | def container(&block)
    method merged_opts (line 22) | def merged_opts

FILE: app/components/DS/buttonish.rb
  class DS::Buttonish (line 1) | class DS::Buttonish < DesignSystemComponent
    method initialize (line 60) | def initialize(variant: :primary, size: :md, href: nil, text: nil, ico...
    method call (line 73) | def call
    method container_classes (line 77) | def container_classes(override_classes = nil)
    method container_size_classes (line 88) | def container_size_classes
    method icon_color (line 92) | def icon_color
    method icon_classes (line 104) | def icon_classes
    method icon_only? (line 110) | def icon_only?
    method variant_data (line 115) | def variant_data
    method size_data (line 119) | def size_data
    method merged_base_classes (line 124) | def merged_base_classes
    method permitted_radius_override_classes (line 149) | def permitted_radius_override_classes
    method permitted_display_override_classes (line 153) | def permitted_display_override_classes

FILE: app/components/DS/dialog.rb
  class DS::Dialog (line 1) | class DS::Dialog < DesignSystemComponent
    method initialize (line 46) | def initialize(variant: "modal", auto_open: true, reload_on_close: fal...
    method frame (line 56) | def frame
    method wrapper_element (line 61) | def wrapper_element(&block)
    method dialog_outer_classes (line 69) | def dialog_outer_classes
    method dialog_inner_classes (line 82) | def dialog_inner_classes
    method merged_opts (line 98) | def merged_opts
    method drawer? (line 112) | def drawer?

FILE: app/components/DS/dialog_controller.js
  method connect (line 12) | connect() {
  method clickOutside (line 20) | clickOutside(e) {
  method close (line 26) | close() {

FILE: app/components/DS/disclosure.rb
  class DS::Disclosure (line 1) | class DS::Disclosure < DesignSystemComponent
    method initialize (line 6) | def initialize(title: nil, align: "right", open: false, **opts)

FILE: app/components/DS/filled_icon.rb
  class DS::FilledIcon (line 1) | class DS::FilledIcon < DesignSystemComponent
    method initialize (line 27) | def initialize(variant: :default, icon: nil, text: nil, hex_color: nil...
    method container_classes (line 36) | def container_classes
    method icon_size (line 45) | def icon_size
    method text_classes (line 49) | def text_classes
    method container_styles (line 56) | def container_styles
    method transparent? (line 64) | def transparent?
    method solid_bg_class (line 69) | def solid_bg_class
    method size_classes (line 80) | def size_classes
    method radius_classes (line 84) | def radius_classes
    method custom_fg_color (line 88) | def custom_fg_color
    method transparent_bg_color (line 92) | def transparent_bg_color
    method transparent_border_color (line 96) | def transparent_border_color

FILE: app/components/DS/link.rb
  class DS::Link (line 3) | class DS::Link < DS::Buttonish
    method merged_opts (line 13) | def merged_opts
    method container_size_classes (line 28) | def container_size_classes

FILE: app/components/DS/menu.rb
  class DS::Menu (line 3) | class DS::Menu < DesignSystemComponent
    method initialize (line 26) | def initialize(variant: "icon", avatar_url: nil, initials: nil, placem...

FILE: app/components/DS/menu_controller.js
  method connect (line 22) | connect() {
  method disconnect (line 29) | disconnect() {
  method addEventListeners (line 35) | addEventListeners() {
  method removeEventListeners (line 42) | removeEventListeners() {
  method close (line 73) | close() {
  method focusFirstElement (line 78) | focusFirstElement() {
  method startAutoUpdate (line 88) | startAutoUpdate() {
  method stopAutoUpdate (line 98) | stopAutoUpdate() {
  method update (line 105) | update() {

FILE: app/components/DS/menu_item.rb
  class DS::MenuItem (line 1) | class DS::MenuItem < DesignSystemComponent
    method initialize (line 6) | def initialize(variant:, text: nil, icon: nil, href: nil, method: :pos...
    method wrapper (line 19) | def wrapper(&block)
    method text_classes (line 29) | def text_classes
    method destructive? (line 36) | def destructive?
    method container_classes (line 41) | def container_classes
    method merged_opts (line 48) | def merged_opts

FILE: app/components/DS/tab.rb
  class DS::Tab (line 1) | class DS::Tab < DesignSystemComponent
    method initialize (line 4) | def initialize(id:, label:)
    method call (line 9) | def call

FILE: app/components/DS/tabs.rb
  class DS::Tabs (line 1) | class DS::Tabs < DesignSystemComponent
    method initialize (line 32) | def initialize(active_tab:, url_param_key: nil, session_key: nil, vari...
    method active_btn_classes (line 42) | def active_btn_classes
    method inactive_btn_classes (line 46) | def inactive_btn_classes
    method unstyled? (line 51) | def unstyled?
    method base_btn_classes (line 55) | def base_btn_classes
    method nav_container_classes (line 61) | def nav_container_classes

FILE: app/components/DS/tabs/nav.rb
  class DS::Tabs::Nav (line 1) | class DS::Tabs::Nav < DesignSystemComponent
    method initialize (line 22) | def initialize(active_tab:, classes: nil, active_btn_classes: nil, ina...

FILE: app/components/DS/tabs/panel.rb
  class DS::Tabs::Panel (line 1) | class DS::Tabs::Panel < DesignSystemComponent
    method initialize (line 4) | def initialize(tab_id:)
    method call (line 8) | def call

FILE: app/components/DS/tabs_controller.js
  method show (line 9) | show(e) {
  method #updateSessionPreference (line 43) | #updateSessionPreference(selectedTabId) {

FILE: app/components/DS/toggle.rb
  class DS::Toggle (line 1) | class DS::Toggle < DesignSystemComponent
    method initialize (line 4) | def initialize(id:, name: nil, checked: false, disabled: false, checke...
    method label_classes (line 14) | def label_classes

FILE: app/components/DS/tooltip.rb
  class DS::Tooltip (line 1) | class DS::Tooltip < ApplicationComponent
    method initialize (line 4) | def initialize(text: nil, placement: "top", offset: 10, cross_axis: 0,...
    method tooltip_content (line 14) | def tooltip_content

FILE: app/components/DS/tooltip_controller.js
  method connect (line 18) | connect() {
  method disconnect (line 24) | disconnect() {
  method addEventListeners (line 29) | addEventListeners() {
  method removeEventListeners (line 34) | removeEventListeners() {
  method startAutoUpdate (line 50) | startAutoUpdate() {
  method stopAutoUpdate (line 61) | stopAutoUpdate() {
  method update (line 68) | update() {

FILE: app/components/UI/account/activity_date.rb
  class UI::Account::ActivityDate (line 1) | class UI::Account::ActivityDate < ApplicationComponent
    method initialize (line 6) | def initialize(account:, data:)
    method id (line 11) | def id
    method broadcast_channel (line 15) | def broadcast_channel
    method end_balance_money (line 19) | def end_balance_money
    method broadcast_refresh! (line 23) | def broadcast_refresh!

FILE: app/components/UI/account/activity_feed.rb
  class UI::Account::ActivityFeed (line 1) | class UI::Account::ActivityFeed < ApplicationComponent
    method initialize (line 4) | def initialize(feed_data:, pagy:, search: nil)
    method id (line 10) | def id
    method broadcast_channel (line 14) | def broadcast_channel
    method broadcast_refresh! (line 18) | def broadcast_refresh!
    method activity_dates (line 27) | def activity_dates
    method account (line 32) | def account

FILE: app/components/UI/account/balance_reconciliation.rb
  class UI::Account::BalanceReconciliation (line 1) | class UI::Account::BalanceReconciliation < ApplicationComponent
    method initialize (line 4) | def initialize(balance:, account:)
    method reconciliation_items (line 9) | def reconciliation_items
    method default_items (line 30) | def default_items
    method credit_card_items (line 45) | def credit_card_items
    method investment_items (line 61) | def investment_items
    method loan_items (line 84) | def loan_items
    method asset_items (line 99) | def asset_items # Property/Vehicle
    method crypto_items (line 114) | def crypto_items
    method net_cash_flow (line 132) | def net_cash_flow
    method net_non_cash_flow (line 136) | def net_non_cash_flow
    method net_total_flow (line 140) | def net_total_flow
    method total_adjustments (line 144) | def total_adjustments
    method has_adjustments? (line 148) | def has_adjustments?
    method end_balance_before_adjustments (line 152) | def end_balance_before_adjustments

FILE: app/components/UI/account/chart.rb
  class UI::Account::Chart (line 1) | class UI::Account::Chart < ApplicationComponent
    method initialize (line 4) | def initialize(account:, period: nil, view: nil)
    method period (line 10) | def period
    method holdings_value_money (line 14) | def holdings_value_money
    method view_balance_money (line 18) | def view_balance_money
    method title (line 29) | def title
    method foreign_currency? (line 51) | def foreign_currency?
    method converted_balance_money (line 55) | def converted_balance_money
    method view (line 61) | def view
    method series (line 65) | def series
    method trend (line 69) | def trend

FILE: app/components/UI/account_page.rb
  class UI::AccountPage (line 1) | class UI::AccountPage < ApplicationComponent
    method initialize (line 6) | def initialize(account:, chart_view: nil, chart_period: nil, active_ta...
    method id (line 13) | def id
    method broadcast_channel (line 17) | def broadcast_channel
    method broadcast_refresh! (line 21) | def broadcast_refresh!
    method title (line 25) | def title
    method subtitle (line 29) | def subtitle
    method active_tab (line 35) | def active_tab
    method tabs (line 39) | def tabs
    method tab_content_for (line 50) | def tab_content_for(tab)

FILE: app/components/application_component.rb
  class ApplicationComponent (line 1) | class ApplicationComponent < ViewComponent::Base

FILE: app/components/design_system_component.rb
  class DesignSystemComponent (line 1) | class DesignSystemComponent < ViewComponent::Base

FILE: app/controllers/accountable_sparklines_controller.rb
  class AccountableSparklinesController (line 1) | class AccountableSparklinesController < ApplicationController
    method show (line 2) | def show
    method family (line 26) | def family
    method accountable (line 30) | def accountable
    method account_ids (line 34) | def account_ids
    method cache_key (line 38) | def cache_key

FILE: app/controllers/accounts_controller.rb
  class AccountsController (line 1) | class AccountsController < ApplicationController
    method index (line 5) | def index
    method sync_all (line 12) | def sync_all
    method show (line 17) | def show
    method sync (line 28) | def sync
    method sparkline (line 36) | def sparkline
    method toggle_active (line 47) | def toggle_active
    method destroy (line 56) | def destroy
    method family (line 66) | def family
    method set_account (line 70) | def set_account

FILE: app/controllers/api/v1/accounts_controller.rb
  class Api::V1::AccountsController (line 3) | class Api::V1::AccountsController < Api::V1::BaseController
    method index (line 9) | def index
    method ensure_read_scope (line 37) | def ensure_read_scope
    method safe_page_param (line 43) | def safe_page_param
    method safe_per_page_param (line 48) | def safe_per_page_param

FILE: app/controllers/api/v1/auth_controller.rb
  type Api (line 1) | module Api
    type V1 (line 2) | module V1
      class AuthController (line 3) | class AuthController < BaseController
        method signup (line 10) | def signup
        method login (line 64) | def login
        method refresh (line 102) | def refresh
        method user_signup_params (line 147) | def user_signup_params
        method validate_password (line 151) | def validate_password(password)
        method valid_device_info? (line 167) | def valid_device_info?
        method create_or_update_device (line 175) | def create_or_update_device(user)
        method create_oauth_token_for_device (line 184) | def create_oauth_token_for_device(user, device)

FILE: app/controllers/api/v1/base_controller.rb
  class Api::V1::BaseController (line 3) | class Api::V1::BaseController < ApplicationController
    method doorkeeper_unauthorized_render_options (line 25) | def doorkeeper_unauthorized_render_options(error: nil)
    method force_json_format (line 37) | def force_json_format
    method authenticate_request! (line 42) | def authenticate_request!
    method authenticate_oauth (line 49) | def authenticate_oauth
    method authenticate_api_key (line 91) | def authenticate_api_key
    method check_api_key_rate_limit (line 107) | def check_api_key_rate_limit
    method render_rate_limit_exceeded (line 124) | def render_rate_limit_exceeded(usage_info)
    method add_rate_limit_headers (line 144) | def add_rate_limit_headers(usage_info)
    method render_unauthorized (line 151) | def render_unauthorized
    method current_resource_owner (line 156) | def current_resource_owner
    method current_scopes (line 161) | def current_scopes
    method authorize_scope! (line 174) | def authorize_scope!(required_scope)
    method render_json (line 198) | def render_json(data, status: :ok)
    method handle_not_found (line 203) | def handle_not_found(exception)
    method handle_unauthorized (line 208) | def handle_unauthorized(exception)
    method handle_bad_request (line 213) | def handle_bad_request(exception)
    method log_api_access (line 219) | def log_api_access
    method ensure_current_family_access (line 235) | def ensure_current_family_access(resource)
    method doorkeeper_token (line 248) | def doorkeeper_token
    method setup_current_context_for_api (line 253) | def setup_current_context_for_api
    method require_ai_enabled (line 274) | def require_ai_enabled

FILE: app/controllers/api/v1/chats_controller.rb
  class Api::V1::ChatsController (line 3) | class Api::V1::ChatsController < Api::V1::BaseController
    method index (line 10) | def index
    method show (line 14) | def show
    method create (line 19) | def create
    method update (line 45) | def update
    method destroy (line 55) | def destroy
    method ensure_read_scope (line 63) | def ensure_read_scope
    method ensure_write_scope (line 67) | def ensure_write_scope
    method set_chat (line 71) | def set_chat
    method chat_params (line 77) | def chat_params
    method update_chat_params (line 81) | def update_chat_params

FILE: app/controllers/api/v1/messages_controller.rb
  class Api::V1::MessagesController (line 3) | class Api::V1::MessagesController < Api::V1::BaseController
    method create (line 8) | def create
    method retry (line 23) | def retry
    method ensure_write_scope (line 42) | def ensure_write_scope
    method set_chat (line 46) | def set_chat
    method message_params (line 52) | def message_params

FILE: app/controllers/api/v1/test_controller.rb
  class Api::V1::TestController (line 5) | class Api::V1::TestController < Api::V1::BaseController
    method index (line 6) | def index
    method not_found (line 10) | def not_found
    method family_access (line 15) | def family_access
    method scope_required (line 27) | def scope_required
    method multiple_scopes_required (line 38) | def multiple_scopes_required

FILE: app/controllers/api/v1/transactions_controller.rb
  class Api::V1::TransactionsController (line 3) | class Api::V1::TransactionsController < Api::V1::BaseController
    method index (line 11) | def index
    method show (line 52) | def show
    method create (line 66) | def create
    method update (line 107) | def update
    method destroy (line 133) | def destroy
    method set_transaction (line 153) | def set_transaction
    method ensure_read_scope (line 164) | def ensure_read_scope
    method ensure_write_scope (line 168) | def ensure_write_scope
    method apply_filters (line 172) | def apply_filters(query)
    method apply_search (line 242) | def apply_search(query)
    method transaction_params (line 253) | def transaction_params
    method entry_params_for_create (line 260) | def entry_params_for_create
    method entry_params_for_update (line 278) | def entry_params_for_update
    method calculate_signed_amount (line 299) | def calculate_signed_amount
    method safe_page_param (line 313) | def safe_page_param
    method safe_per_page_param (line 318) | def safe_per_page_param

FILE: app/controllers/api/v1/usage_controller.rb
  class Api::V1::UsageController (line 1) | class Api::V1::UsageController < Api::V1::BaseController
    method show (line 3) | def show

FILE: app/controllers/application_controller.rb
  class ApplicationController (line 1) | class ApplicationController < ActionController::Base
    method detect_os (line 13) | def detect_os
    method set_default_chat (line 26) | def set_default_chat
    method set_active_storage_url_options (line 31) | def set_active_storage_url_options

FILE: app/controllers/budget_categories_controller.rb
  class BudgetCategoriesController (line 1) | class BudgetCategoriesController < ApplicationController
    method index (line 4) | def index
    method show (line 9) | def show
    method update (line 24) | def update
    method budget_category_params (line 38) | def budget_category_params
    method set_budget (line 44) | def set_budget

FILE: app/controllers/budgets_controller.rb
  class BudgetsController (line 1) | class BudgetsController < ApplicationController
    method index (line 4) | def index
    method show (line 8) | def show
    method edit (line 11) | def edit
    method update (line 15) | def update
    method picker (line 20) | def picker
    method budget_create_params (line 29) | def budget_create_params
    method budget_params (line 33) | def budget_params
    method set_budget (line 37) | def set_budget
    method redirect_to_current_month_budget (line 43) | def redirect_to_current_month_budget

FILE: app/controllers/categories_controller.rb
  class CategoriesController (line 1) | class CategoriesController < ApplicationController
    method index (line 6) | def index
    method new (line 12) | def new
    method create (line 17) | def create
    method edit (line 36) | def edit
    method update (line 39) | def update
    method destroy (line 53) | def destroy
    method destroy_all (line 59) | def destroy_all
    method bootstrap (line 64) | def bootstrap
    method set_category (line 71) | def set_category
    method set_categories (line 75) | def set_categories
    method set_transaction (line 83) | def set_transaction
    method category_params (line 89) | def category_params

FILE: app/controllers/category/deletions_controller.rb
  class Category::DeletionsController (line 1) | class Category::DeletionsController < ApplicationController
    method new (line 5) | def new
    method create (line 8) | def create
    method set_category (line 15) | def set_category
    method set_replacement_category (line 19) | def set_replacement_category

FILE: app/controllers/category/dropdowns_controller.rb
  class Category::DropdownsController (line 1) | class Category::DropdownsController < ApplicationController
    method show (line 4) | def show
    method set_from_params (line 9) | def set_from_params
    method categories_scope (line 19) | def categories_scope

FILE: app/controllers/chats_controller.rb
  class ChatsController (line 1) | class ChatsController < ApplicationController
    method index (line 6) | def index
    method show (line 11) | def show
    method new (line 15) | def new
    method create (line 19) | def create
    method edit (line 25) | def edit
    method update (line 28) | def update
    method destroy (line 37) | def destroy
    method retry (line 44) | def retry
    method set_chat (line 50) | def set_chat
    method set_last_viewed_chat (line 54) | def set_last_viewed_chat(chat)
    method clear_last_viewed_chat (line 58) | def clear_last_viewed_chat
    method chat_params (line 62) | def chat_params

FILE: app/controllers/concerns/accountable_resource.rb
  type AccountableResource (line 1) | module AccountableResource
    function permitted_accountable_attributes (line 12) | def permitted_accountable_attributes(*attrs)
    function new (line 18) | def new
    function show (line 25) | def show
    function edit (line 33) | def edit
    function create (line 36) | def create
    function update (line 43) | def update
    function set_link_options (line 68) | def set_link_options
    function accountable_type (line 73) | def accountable_type
    function set_account (line 77) | def set_account
    function account_params (line 81) | def account_params

FILE: app/controllers/concerns/authentication.rb
  type Authentication (line 1) | module Authentication
    function skip_authentication (line 11) | def skip_authentication(**options)
    function authenticate_user! (line 18) | def authenticate_user!
    function find_session_by_cookie (line 30) | def find_session_by_cookie
    function create_session_for (line 40) | def create_session_for(user)
    function self_hosted_first_login? (line 46) | def self_hosted_first_login?
    function set_request_details (line 50) | def set_request_details
    function set_sentry_user (line 55) | def set_sentry_user

FILE: app/controllers/concerns/auto_sync.rb
  type AutoSync (line 1) | module AutoSync
    function sync_family (line 9) | def sync_family
    function family_needs_auto_sync? (line 13) | def family_needs_auto_sync?

FILE: app/controllers/concerns/breadcrumbable.rb
  type Breadcrumbable (line 1) | module Breadcrumbable
    function set_breadcrumbs (line 10) | def set_breadcrumbs

FILE: app/controllers/concerns/entryable_resource.rb
  type EntryableResource (line 1) | module EntryableResource
    function show (line 10) | def show
    function new (line 13) | def new
    function create (line 23) | def create
    function update (line 27) | def update
    function destroy (line 31) | def destroy
    function entryable (line 40) | def entryable
    function set_entry (line 44) | def set_entry

FILE: app/controllers/concerns/feature_guardable.rb
  type FeatureGuardable (line 10) | module FeatureGuardable
    function guard_feature (line 14) | def guard_feature(**options)
    function guard_feature (line 20) | def guard_feature

FILE: app/controllers/concerns/impersonatable.rb
  type Impersonatable (line 1) | module Impersonatable
    function create_impersonation_session_log (line 9) | def create_impersonation_session_log

FILE: app/controllers/concerns/invitable.rb
  type Invitable (line 1) | module Invitable
    function invite_code_required? (line 9) | def invite_code_required?
    function self_hosted? (line 14) | def self_hosted?

FILE: app/controllers/concerns/localize.rb
  type Localize (line 1) | module Localize
    function switch_locale (line 10) | def switch_locale(&action)
    function switch_timezone (line 15) | def switch_timezone(&action)

FILE: app/controllers/concerns/notifiable.rb
  type Notifiable (line 1) | module Notifiable
    function render_flash_notifications (line 10) | def render_flash_notifications
    function flash_notification_stream_items (line 18) | def flash_notification_stream_items
    function resolve_cta (line 36) | def resolve_cta(cta)
    function resolve_notifications (line 43) | def resolve_notifications(type, data)

FILE: app/controllers/concerns/onboardable.rb
  type Onboardable (line 1) | module Onboardable
    function require_onboarding_and_upgrade (line 10) | def require_onboarding_and_upgrade
    function redirectable_path? (line 23) | def redirectable_path?(path)

FILE: app/controllers/concerns/periodable.rb
  type Periodable (line 1) | module Periodable
    function set_period (line 9) | def set_period

FILE: app/controllers/concerns/restore_layout_preferences.rb
  type RestoreLayoutPreferences (line 1) | module RestoreLayoutPreferences
    function restore_active_tabs (line 9) | def restore_active_tabs
    function valid_account_group_tabs (line 15) | def valid_account_group_tabs
    function account_group_tab_param (line 19) | def account_group_tab_param

FILE: app/controllers/concerns/self_hostable.rb
  type SelfHostable (line 1) | module SelfHostable
    function self_hosted? (line 11) | def self_hosted?
    function self_hosted_first_login? (line 15) | def self_hosted_first_login?
    function verify_self_host_config (line 19) | def verify_self_host_config
    function redis_connected? (line 37) | def redis_connected?

FILE: app/controllers/concerns/store_location.rb
  type StoreLocation (line 1) | module StoreLocation
    function previous_path (line 12) | def previous_path
    function handle_not_found (line 17) | def handle_not_found
    function store_return_to (line 26) | def store_return_to
    function clear_previous_path (line 32) | def clear_previous_path
    function fallback_path (line 38) | def fallback_path

FILE: app/controllers/concerns/stream_extensions.rb
  type StreamExtensions (line 1) | module StreamExtensions
    function stream_redirect_to (line 4) | def stream_redirect_to(path, notice: nil, alert: nil)
    function stream_redirect_back_or_to (line 8) | def stream_redirect_back_or_to(path, notice: nil, alert: nil)
    function custom_stream_redirect (line 13) | def custom_stream_redirect(path, redirect_back: false, notice: nil, al...

FILE: app/controllers/cookie_sessions_controller.rb
  class CookieSessionsController (line 1) | class CookieSessionsController < ApplicationController
    method update (line 2) | def update
    method cookie_session_params (line 12) | def cookie_session_params
    method save_kv_to_session (line 16) | def save_kv_to_session(key, value)

FILE: app/controllers/credit_cards_controller.rb
  class CreditCardsController (line 1) | class CreditCardsController < ApplicationController

FILE: app/controllers/cryptos_controller.rb
  class CryptosController (line 1) | class CryptosController < ApplicationController

FILE: app/controllers/currencies_controller.rb
  class CurrenciesController (line 1) | class CurrenciesController < ApplicationController
    method show (line 2) | def show

FILE: app/controllers/current_sessions_controller.rb
  class CurrentSessionsController (line 1) | class CurrentSessionsController < ApplicationController
    method update (line 2) | def update
    method session_params (line 11) | def session_params

FILE: app/controllers/depositories_controller.rb
  class DepositoriesController (line 1) | class DepositoriesController <  ApplicationController

FILE: app/controllers/email_confirmations_controller.rb
  class EmailConfirmationsController (line 1) | class EmailConfirmationsController < ApplicationController
    method new (line 5) | def new

FILE: app/controllers/family_exports_controller.rb
  class FamilyExportsController (line 1) | class FamilyExportsController < ApplicationController
    method new (line 7) | def new
    method create (line 11) | def create
    method index (line 23) | def index
    method download (line 28) | def download
    method set_export (line 38) | def set_export
    method require_admin (line 42) | def require_admin

FILE: app/controllers/family_merchants_controller.rb
  class FamilyMerchantsController (line 1) | class FamilyMerchantsController < ApplicationController
    method index (line 4) | def index
    method new (line 12) | def new
    method create (line 16) | def create
    method edit (line 29) | def edit
    method update (line 32) | def update
    method destroy (line 40) | def destroy
    method set_merchant (line 46) | def set_merchant
    method merchant_params (line 50) | def merchant_params

FILE: app/controllers/holdings_controller.rb
  class HoldingsController (line 1) | class HoldingsController < ApplicationController
    method index (line 4) | def index
    method show (line 8) | def show
    method destroy (line 11) | def destroy
    method set_holding (line 26) | def set_holding

FILE: app/controllers/impersonation_sessions_controller.rb
  class ImpersonationSessionsController (line 1) | class ImpersonationSessionsController < ApplicationController
    method create (line 5) | def create
    method join (line 10) | def join
    method leave (line 16) | def leave
    method approve (line 21) | def approve
    method reject (line 28) | def reject
    method complete (line 35) | def complete
    method session_params (line 41) | def session_params
    method set_impersonation_session (line 45) | def set_impersonation_session
    method require_super_admin! (line 51) | def require_super_admin!
    method raise_unauthorized! (line 55) | def raise_unauthorized!

FILE: app/controllers/import/cleans_controller.rb
  class Import::CleansController (line 1) | class Import::CleansController < ApplicationController
    method show (line 6) | def show
    method set_import (line 19) | def set_import

FILE: app/controllers/import/configurations_controller.rb
  class Import::ConfigurationsController (line 1) | class Import::ConfigurationsController < ApplicationController
    method show (line 6) | def show
    method update (line 9) | def update
    method set_import (line 18) | def set_import
    method import_params (line 22) | def import_params

FILE: app/controllers/import/confirms_controller.rb
  class Import::ConfirmsController (line 1) | class Import::ConfirmsController < ApplicationController
    method show (line 6) | def show
    method set_import (line 15) | def set_import

FILE: app/controllers/import/mappings_controller.rb
  class Import::MappingsController (line 1) | class Import::MappingsController < ApplicationController
    method update (line 4) | def update
    method mapping_params (line 16) | def mapping_params
    method set_import (line 20) | def set_import
    method mappable (line 24) | def mappable
    method create_when_empty (line 30) | def create_when_empty
    method mappable_class (line 36) | def mappable_class
    method mapping_class (line 40) | def mapping_class

FILE: app/controllers/import/rows_controller.rb
  class Import::RowsController (line 1) | class Import::RowsController < ApplicationController
    method update (line 4) | def update
    method show (line 10) | def show
    method row_params (line 14) | def row_params
    method set_import_row (line 18) | def set_import_row

FILE: app/controllers/import/uploads_controller.rb
  class Import::UploadsController (line 1) | class Import::UploadsController < ApplicationController
    method show (line 6) | def show
    method sample_csv (line 9) | def sample_csv
    method update (line 16) | def update
    method set_import (line 31) | def set_import
    method csv_str (line 35) | def csv_str
    method csv_valid? (line 39) | def csv_valid?(str)
    method upload_params (line 50) | def upload_params

FILE: app/controllers/imports_controller.rb
  class ImportsController (line 1) | class ImportsController < ApplicationController
    method publish (line 4) | def publish
    method index (line 12) | def index
    method new (line 18) | def new
    method create (line 22) | def create
    method show (line 33) | def show
    method revert (line 41) | def revert
    method apply_template (line 46) | def apply_template
    method destroy (line 55) | def destroy
    method set_import (line 62) | def set_import
    method import_params (line 66) | def import_params

FILE: app/controllers/investments_controller.rb
  class InvestmentsController (line 1) | class InvestmentsController < ApplicationController

FILE: app/controllers/invitations_controller.rb
  class InvitationsController (line 1) | class InvitationsController < ApplicationController
    method new (line 3) | def new
    method create (line 7) | def create
    method accept (line 27) | def accept
    method destroy (line 37) | def destroy
    method invitation_params (line 57) | def invitation_params

FILE: app/controllers/invite_codes_controller.rb
  class InviteCodesController (line 1) | class InviteCodesController < ApplicationController
    method index (line 4) | def index
    method create (line 8) | def create
    method ensure_self_hosted (line 16) | def ensure_self_hosted

FILE: app/controllers/loans_controller.rb
  class LoansController (line 1) | class LoansController < ApplicationController

FILE: app/controllers/lookbooks_controller.rb
  class LookbooksController (line 1) | class LookbooksController < Lookbook::PreviewController

FILE: app/controllers/messages_controller.rb
  class MessagesController (line 1) | class MessagesController < ApplicationController
    method create (line 6) | def create
    method set_chat (line 17) | def set_chat
    method message_params (line 21) | def message_params

FILE: app/controllers/mfa_controller.rb
  class MfaController (line 1) | class MfaController < ApplicationController
    method new (line 5) | def new
    method create (line 10) | def create
    method verify (line 21) | def verify
    method verify_code (line 29) | def verify_code
    method disable (line 42) | def disable
    method determine_layout (line 49) | def determine_layout

FILE: app/controllers/onboardings_controller.rb
  class OnboardingsController (line 1) | class OnboardingsController < ApplicationController
    method show (line 7) | def show
    method preferences (line 10) | def preferences
    method trial (line 13) | def trial
    method set_user (line 17) | def set_user
    method load_invitation (line 21) | def load_invitation

FILE: app/controllers/other_assets_controller.rb
  class OtherAssetsController (line 1) | class OtherAssetsController < ApplicationController

FILE: app/controllers/other_liabilities_controller.rb
  class OtherLiabilitiesController (line 1) | class OtherLiabilitiesController < ApplicationController

FILE: app/controllers/pages_controller.rb
  class PagesController (line 1) | class PagesController < ApplicationController
    method dashboard (line 6) | def dashboard
    method changelog (line 30) | def changelog
    method feedback (line 47) | def feedback
    method redis_configuration_error (line 51) | def redis_configuration_error
    method github_provider (line 56) | def github_provider
    method build_cashflow_sankey_data (line 60) | def build_cashflow_sankey_data(income_totals, expense_totals, currency...

FILE: app/controllers/password_resets_controller.rb
  class PasswordResetsController (line 1) | class PasswordResetsController < ApplicationController
    method new (line 8) | def new
    method create (line 11) | def create
    method edit (line 22) | def edit
    method update (line 26) | def update
    method set_user_by_token (line 36) | def set_user_by_token
    method password_params (line 41) | def password_params

FILE: app/controllers/passwords_controller.rb
  class PasswordsController (line 1) | class PasswordsController < ApplicationController
    method edit (line 2) | def edit
    method update (line 5) | def update
    method password_params (line 15) | def password_params

FILE: app/controllers/plaid_items_controller.rb
  class PlaidItemsController (line 1) | class PlaidItemsController < ApplicationController
    method new (line 4) | def new
    method edit (line 16) | def edit
    method create (line 25) | def create
    method destroy (line 35) | def destroy
    method sync (line 40) | def sync
    method set_plaid_item (line 52) | def set_plaid_item
    method plaid_item_params (line 56) | def plaid_item_params
    method item_name (line 60) | def item_name
    method plaid_us_webhooks_url (line 64) | def plaid_us_webhooks_url
    method plaid_eu_webhooks_url (line 70) | def plaid_eu_webhooks_url

FILE: app/controllers/properties_controller.rb
  class PropertiesController (line 1) | class PropertiesController < ApplicationController
    method new (line 6) | def new
    method create (line 10) | def create
    method update (line 18) | def update
    method edit (line 33) | def edit
    method balances (line 36) | def balances
    method update_balances (line 39) | def update_balances
    method address (line 56) | def address
    method update_address (line 61) | def update_address
    method balance_params (line 81) | def balance_params
    method address_params (line 85) | def address_params
    method property_params (line 90) | def property_params
    method set_property (line 95) | def set_property

FILE: app/controllers/registrations_controller.rb
  class RegistrationsController (line 1) | class RegistrationsController < ApplicationController
    method new (line 11) | def new
    method create (line 15) | def create
    method set_invitation (line 37) | def set_invitation
    method set_user (line 43) | def set_user
    method user_params (line 47) | def user_params(specific_param = nil)
    method claim_invite_code (line 52) | def claim_invite_code
    method validate_password_requirements (line 58) | def validate_password_requirements

FILE: app/controllers/rules_controller.rb
  class RulesController (line 1) | class RulesController < ApplicationController
    method index (line 6) | def index
    method new (line 18) | def new
    method create (line 24) | def create
    method apply (line 34) | def apply
    method confirm (line 40) | def confirm
    method edit (line 43) | def edit
    method update (line 46) | def update
    method destroy (line 57) | def destroy
    method destroy_all (line 62) | def destroy_all
    method set_rule (line 68) | def set_rule
    method rule_params (line 72) | def rule_params

FILE: app/controllers/securities_controller.rb
  class SecuritiesController (line 1) | class SecuritiesController < ApplicationController
    method index (line 2) | def index

FILE: app/controllers/sessions_controller.rb
  class SessionsController (line 1) | class SessionsController < ApplicationController
    method new (line 7) | def new
    method create (line 10) | def create
    method destroy (line 25) | def destroy
    method set_session (line 31) | def set_session

FILE: app/controllers/settings/api_keys_controller.rb
  class Settings::ApiKeysController (line 3) | class Settings::ApiKeysController < ApplicationController
    method show (line 8) | def show
    method new (line 12) | def new
    method create (line 19) | def create
    method destroy (line 38) | def destroy
    method set_api_key (line 49) | def set_api_key
    method api_key_params (line 53) | def api_key_params

FILE: app/controllers/settings/billings_controller.rb
  class Settings::BillingsController (line 1) | class Settings::BillingsController < ApplicationController
    method show (line 4) | def show

FILE: app/controllers/settings/hostings_controller.rb
  class Settings::HostingsController (line 1) | class Settings::HostingsController < ApplicationController
    method show (line 8) | def show
    method update (line 13) | def update
    method clear_cache (line 32) | def clear_cache
    method hosting_params (line 38) | def hosting_params
    method ensure_admin (line 42) | def ensure_admin

FILE: app/controllers/settings/preferences_controller.rb
  class Settings::PreferencesController (line 1) | class Settings::PreferencesController < ApplicationController
    method show (line 4) | def show

FILE: app/controllers/settings/profiles_controller.rb
  class Settings::ProfilesController (line 1) | class Settings::ProfilesController < ApplicationController
    method show (line 4) | def show
    method destroy (line 10) | def destroy

FILE: app/controllers/settings/securities_controller.rb
  class Settings::SecuritiesController (line 1) | class Settings::SecuritiesController < ApplicationController
    method show (line 4) | def show

FILE: app/controllers/subscriptions_controller.rb
  class SubscriptionsController (line 1) | class SubscriptionsController < ApplicationController
    method upgrade (line 6) | def upgrade
    method new (line 15) | def new
    method create (line 30) | def create
    method show (line 39) | def show
    method success (line 49) | def success
    method stripe (line 61) | def stripe

FILE: app/controllers/tag/deletions_controller.rb
  class Tag::DeletionsController (line 1) | class Tag::DeletionsController < ApplicationController
    method new (line 5) | def new
    method create (line 8) | def create
    method set_tag (line 15) | def set_tag
    method set_replacement_tag (line 19) | def set_replacement_tag

FILE: app/controllers/tags_controller.rb
  class TagsController (line 1) | class TagsController < ApplicationController
    method index (line 4) | def index
    method new (line 10) | def new
    method create (line 14) | def create
    method edit (line 24) | def edit
    method update (line 27) | def update
    method destroy (line 32) | def destroy
    method destroy_all (line 37) | def destroy_all
    method set_tag (line 44) | def set_tag
    method tag_params (line 48) | def tag_params

FILE: app/controllers/trades_controller.rb
  class TradesController (line 1) | class TradesController < ApplicationController
    method new (line 5) | def new
    method create (line 15) | def create
    method update (line 31) | def update
    method entry_params (line 54) | def entry_params
    method create_params (line 61) | def create_params
    method update_entry_params (line 67) | def update_entry_params

FILE: app/controllers/transaction_categories_controller.rb
  class TransactionCategoriesController (line 1) | class TransactionCategoriesController < ApplicationController
    method update (line 4) | def update
    method entry_params (line 37) | def entry_params
    method needs_rule_notification? (line 41) | def needs_rule_notification?(transaction)

FILE: app/controllers/transactions/bulk_deletions_controller.rb
  class Transactions::BulkDeletionsController (line 1) | class Transactions::BulkDeletionsController < ApplicationController
    method create (line 2) | def create
    method bulk_delete_params (line 9) | def bulk_delete_params

FILE: app/controllers/transactions/bulk_updates_controller.rb
  class Transactions::BulkUpdatesController (line 1) | class Transactions::BulkUpdatesController < ApplicationController
    method new (line 2) | def new
    method create (line 5) | def create
    method bulk_update_params (line 15) | def bulk_update_params

FILE: app/controllers/transactions_controller.rb
  class TransactionsController (line 1) | class TransactionsController < ApplicationController
    method new (line 6) | def new
    method index (line 12) | def index
    method clear_filter (line 27) | def clear_filter
    method create (line 56) | def create
    method update (line 76) | def update
    method per_page (line 112) | def per_page
    method needs_rule_notification? (line 116) | def needs_rule_notification?(transaction)
    method entry_params (line 128) | def entry_params
    method search_params (line 144) | def search_params
    method store_params! (line 161) | def store_params!
    method should_restore_params? (line 181) | def should_restore_params?
    method stored_params (line 185) | def stored_params

FILE: app/controllers/transfer_matches_controller.rb
  class TransferMatchesController (line 1) | class TransferMatchesController < ApplicationController
    method new (line 4) | def new
    method create (line 9) | def create
    method set_entry (line 23) | def set_entry
    method transfer_match_params (line 27) | def transfer_match_params
    method build_transfer (line 31) | def build_transfer

FILE: app/controllers/transfers_controller.rb
  class TransfersController (line 1) | class TransfersController < ApplicationController
    method new (line 6) | def new
    method show (line 10) | def show
    method create (line 14) | def create
    method update (line 34) | def update
    method destroy (line 46) | def destroy
    method set_transfer (line 52) | def set_transfer
    method transfer_params (line 60) | def transfer_params
    method transfer_update_params (line 64) | def transfer_update_params
    method update_transfer_status (line 68) | def update_transfer_status
    method update_transfer_details (line 76) | def update_transfer_details

FILE: app/controllers/users_controller.rb
  class UsersController (line 1) | class UsersController < ApplicationController
    method update (line 5) | def update
    method reset (line 38) | def reset
    method destroy (line 43) | def destroy
    method rule_prompt_settings (line 52) | def rule_prompt_settings
    method handle_redirect (line 58) | def handle_redirect(notice)
    method should_purge_profile_image? (line 75) | def should_purge_profile_image?
    method email_changed? (line 80) | def email_changed?
    method rule_prompt_settings_params (line 84) | def rule_prompt_settings_params
    method user_params (line 88) | def user_params
    method set_user (line 97) | def set_user
    method ensure_admin (line 101) | def ensure_admin

FILE: app/controllers/valuations_controller.rb
  class ValuationsController (line 1) | class ValuationsController < ApplicationController
    method confirm_create (line 4) | def confirm_create
    method confirm_update (line 17) | def confirm_update
    method create (line 32) | def create
    method update (line 51) | def update
    method entry_params (line 86) | def entry_params

FILE: app/controllers/vehicles_controller.rb
  class VehiclesController (line 1) | class VehiclesController < ApplicationController

FILE: app/controllers/webhooks_controller.rb
  class WebhooksController (line 1) | class WebhooksController < ApplicationController
    method plaid (line 5) | def plaid
    method plaid_eu (line 21) | def plaid_eu
    method stripe (line 37) | def stripe

FILE: app/data_migrations/balance_component_migrator.rb
  class BalanceComponentMigrator (line 1) | class BalanceComponentMigrator
    method run (line 2) | def self.run

FILE: app/helpers/accounts_helper.rb
  type AccountsHelper (line 1) | module AccountsHelper
    function summary_card (line 2) | def summary_card(title:, &block)

FILE: app/helpers/application_helper.rb
  type ApplicationHelper (line 1) | module ApplicationHelper
    function styled_form_with (line 4) | def styled_form_with(**options, &block)
    function icon (line 9) | def icon(key, size: "md", color: "default", custom: false, as_button: ...
    function hex_with_alpha (line 31) | def hex_with_alpha(hex, alpha)
    function title (line 36) | def title(page_title)
    function header_title (line 40) | def header_title(page_title)
    function header_description (line 44) | def header_description(page_description)
    function page_active? (line 48) | def page_active?(path)
    function format_date (line 53) | def format_date(object, format = :default, options = {})
    function format_money (line 65) | def format_money(number_or_money, options = {})
    function totals_by_currency (line 71) | def totals_by_currency(collection:, money_method:, separator: " | ", n...
    function show_super_admin_bar? (line 78) | def show_super_admin_bar?
    function markdown (line 87) | def markdown(text)
    function calculate_total (line 112) | def calculate_total(item, money_method, negate)

FILE: app/helpers/categories_helper.rb
  type CategoriesHelper (line 1) | module CategoriesHelper
    function transfer_category (line 2) | def transfer_category
    function payment_category (line 9) | def payment_category
    function trade_category (line 16) | def trade_category
    function family_categories (line 22) | def family_categories

FILE: app/helpers/chats_helper.rb
  type ChatsHelper (line 1) | module ChatsHelper
    function chat_frame (line 2) | def chat_frame
    function chat_view_path (line 6) | def chat_view_path(chat)

FILE: app/helpers/custom_confirm.rb
  class CustomConfirm (line 3) | class CustomConfirm
    method for_resource_deletion (line 5) | def for_resource_deletion(resource_name, high_severity: false)
    method initialize (line 16) | def initialize(title: default_title, body: default_body, btn_text: def...
    method to_data_attribute (line 23) | def to_data_attribute
    method derive_btn_variant (line 35) | def derive_btn_variant(destructive, high_severity)
    method default_title (line 40) | def default_title
    method default_body (line 44) | def default_body
    method default_btn_text (line 48) | def default_btn_text

FILE: app/helpers/entries_helper.rb
  type EntriesHelper (line 1) | module EntriesHelper
    function entries_by_date (line 2) | def entries_by_date(entries, totals: false)
    function entry_name_detailed (line 32) | def entry_name_detailed(entry)

FILE: app/helpers/imports_helper.rb
  type ImportsHelper (line 1) | module ImportsHelper
    function mapping_label (line 2) | def mapping_label(mapping_class)
    function import_col_label (line 11) | def import_col_label(key)
    function dry_run_resource (line 29) | def dry_run_resource(key)
    function permitted_import_configuration_path (line 40) | def permitted_import_configuration_path(import)
    function cell_class (line 48) | def cell_class(row, field)
    function cell_is_valid? (line 58) | def cell_is_valid?(row, field)
    function permitted_import_types (line 64) | def permitted_import_types

FILE: app/helpers/languages_helper.rb
  type LanguagesHelper (line 1) | module LanguagesHelper
    function country_options (line 353) | def country_options
    function language_options (line 357) | def language_options
    function timezone_options (line 367) | def timezone_options

FILE: app/helpers/mfa_helper.rb
  type MfaHelper (line 1) | module MfaHelper
    function generate_mfa_qr_code (line 2) | def generate_mfa_qr_code(provisioning_uri)

FILE: app/helpers/settings_helper.rb
  type SettingsHelper (line 1) | module SettingsHelper
    function adjacent_setting (line 19) | def adjacent_setting(current_path, offset)
    function settings_section (line 36) | def settings_section(title:, subtitle: nil, &block)
    function settings_nav_footer (line 41) | def settings_nav_footer
    function settings_nav_footer_mobile (line 51) | def settings_nav_footer_mobile
    function not_self_hosted? (line 62) | def not_self_hosted?

FILE: app/helpers/styled_form_builder.rb
  class StyledFormBuilder (line 1) | class StyledFormBuilder < ActionView::Helpers::FormBuilder
    method radio_button (line 17) | def radio_button(method, tag_value, options = {})
    method select (line 22) | def select(method, choices, options = {}, html_options = {})
    method collection_select (line 30) | def collection_select(method, collection, value_method, text_method, o...
    method money_field (line 38) | def money_field(amount_method, options = {})
    method toggle (line 47) | def toggle(method, options = {}, checked_value = "1", unchecked_value ...
    method submit (line 65) | def submit(value = nil, options = {})
    method build_field (line 79) | def build_field(method, options = {}, html_options = {}, &block)
    method normalize_options (line 108) | def normalize_options(options, html_options)
    method build_label (line 112) | def build_label(method, options)
    method build_tooltip (line 128) | def build_tooltip(tooltip_text)

FILE: app/helpers/transactions_helper.rb
  type TransactionsHelper (line 1) | module TransactionsHelper
    function transaction_search_filters (line 2) | def transaction_search_filters
    function get_transaction_search_filter_partial_path (line 14) | def get_transaction_search_filter_partial_path(filter)
    function get_default_transaction_search_filter (line 18) | def get_default_transaction_search_filter

FILE: app/javascript/controllers/app_layout_controller.js
  method openMobileSidebar (line 13) | openMobileSidebar() {
  method closeMobileSidebar (line 17) | closeMobileSidebar() {
  method toggleLeftSidebar (line 21) | toggleLeftSidebar() {
  method toggleRightSidebar (line 27) | toggleRightSidebar() {
  method #toggleSidebarWidth (line 33) | #toggleSidebarWidth(el, isCurrentlyOpen) {
  method #updateUserPreference (line 43) | #updateUserPreference(field, value) {

FILE: app/javascript/controllers/auto_submit_form_controller.js
  method connect (line 11) | connect() {
  method disconnect (line 18) | disconnect() {
  method #getTriggerEvent (line 34) | #getTriggerEvent(element) {
  method #debounceTimeout (line 78) | #debounceTimeout(element) {

FILE: app/javascript/controllers/budget_form_controller.js
  method toggleAutoFill (line 5) | toggleAutoFill(e) {
  method #fillField (line 18) | #fillField(id, value) {
  method #clearField (line 22) | #clearField(id) {

FILE: app/javascript/controllers/bulk_select_controller.js
  method connect (line 18) | connect() {
  method disconnect (line 24) | disconnect() {
  method bulkEditDrawerHeaderTargetConnected (line 28) | bulkEditDrawerHeaderTargetConnected(element) {
  method submitBulkRequest (line 35) | submitBulkRequest(e) {
  method togglePageSelection (line 46) | togglePageSelection(e) {
  method toggleGroupSelection (line 54) | toggleGroupSelection(e) {
  method toggleRowSelection (line 66) | toggleRowSelection(e) {
  method deselectAll (line 74) | deselectAll() {
  method selectedIdsValueChanged (line 81) | selectedIdsValueChanged() {
  method _addHiddenFormInputsForSelectedIds (line 85) | _addHiddenFormInputsForSelectedIds(form, paramName, transactionIds) {
  method _resetFormInputs (line 97) | _resetFormInputs(form, paramName) {
  method _rowsForGroup (line 102) | _rowsForGroup(group) {
  method _addToSelection (line 108) | _addToSelection(idToAdd) {
  method _removeFromSelection (line 114) | _removeFromSelection(idToRemove) {
  method _selectAll (line 120) | _selectAll() {
  method _updateSelectionBar (line 132) | _updateSelectionBar() {
  method _pluralizedResourceName (line 140) | _pluralizedResourceName() {
  method _updateGroups (line 148) | _updateGroups() {
  method _updateRows (line 160) | _updateRows() {

FILE: app/javascript/controllers/category_controller.js
  method initialize (line 25) | initialize() {
  method initPicker (line 52) | initPicker() {
  method updateAvatarColors (line 87) | updateAvatarColors(color) {
  method handleIconColorChange (line 92) | handleIconColorChange(e) {
  method handleIconChange (line 107) | handleIconChange(e) {
  method updateSelectedIconColor (line 118) | updateSelectedIconColor(color) {
  method handleColorChange (line 126) | handleColorChange(e) {
  method handleContrastValidation (line 134) | handleContrastValidation(contrastRatio) {
  method autoAdjust (line 147) | autoAdjust(e) {
  method handleParentChange (line 153) | handleParentChange(e) {
  method backgroundColor (line 160) | backgroundColor([r, g, b, a], percentage) {
  method luminance (line 173) | luminance([r, g, b]) {
  method contrast (line 183) | contrast(foregroundColor, backgroundColor) {
  method darkenColor (line 190) | darkenColor(color) {
  method showPaletteSection (line 211) | showPaletteSection() {
  method showColorsSection (line 220) | showColorsSection() {
  method toggleSections (line 230) | toggleSections() {
  method updatePopupPosition (line 244) | updatePopupPosition() {
  method #backgroundColor (line 259) | #backgroundColor(color) {

FILE: app/javascript/controllers/chat_controller.js
  method connect (line 6) | connect() {
  method disconnect (line 10) | disconnect() {
  method autoResize (line 16) | autoResize() {
  method submitSampleQuestion (line 27) | submitSampleQuestion(e) {
  method handleInputKeyDown (line 36) | handleInputKeyDown(e) {
  method #configureAutoScroll (line 43) | #configureAutoScroll() {

FILE: app/javascript/controllers/clipboard_controller.js
  method copy (line 6) | copy(event) {
  method showSuccess (line 20) | showSuccess() {

FILE: app/javascript/controllers/color_avatar_controller.js
  method connect (line 8) | connect() {
  method disconnect (line 12) | disconnect() {
  method handleColorChange (line 22) | handleColorChange(e) {

FILE: app/javascript/controllers/color_select_controller.js
  method connect (line 7) | connect() {
  method select (line 11) | select({ target }) {
  method selectionValueChanged (line 15) | selectionValueChanged() {
  method #renderOptions (line 26) | #renderOptions() {
  method #check (line 32) | #check(option) {
  method #uncheck (line 41) | #uncheck(option) {
  method #options (line 46) | get #options() {
  function hexToRGBA (line 51) | function hexToRGBA(hex, alpha = 1) {

FILE: app/javascript/controllers/confirm_dialog_controller.js
  method handleConfirm (line 8) | handleConfirm(rawData) {
  method #prepareDialog (line 27) | #prepareDialog(data) {
  method #normalizeRawData (line 46) | #normalizeRawData(rawData) {

FILE: app/javascript/controllers/deletion_controller.js
  method chooseSubmitButton (line 15) | chooseSubmitButton() {

FILE: app/javascript/controllers/donut_chart_controller.js
  method connect (line 18) | connect() {
  method disconnect (line 24) | disconnect() {
  method #data (line 30) | get #data() {
  method #teardown (line 60) | #teardown() {
  method #draw (line 64) | #draw() {
  method #handleSegmentHover (line 127) | #handleSegmentHover(event) {

FILE: app/javascript/controllers/element_removal_controller.js
  method remove (line 5) | remove() {

FILE: app/javascript/controllers/file_upload_controller.js
  method connect (line 6) | connect() {
  method disconnect (line 18) | disconnect() {
  method triggerFileInput (line 28) | triggerFileInput() {
  method fileSelected (line 34) | fileSelected() {
  method formSubmitting (line 56) | formSubmitting() {

FILE: app/javascript/controllers/hotkey_controller.js
  method connect (line 6) | connect() {
  method disconnect (line 10) | disconnect() {
  method navigateBack (line 14) | navigateBack(event) {

FILE: app/javascript/controllers/import_controller.js
  method connect (line 17) | connect() {
  method handleAmountTypeStrategyChange (line 26) | handleAmountTypeStrategyChange(event) {
  method handleAmountTypeChange (line 42) | handleAmountTypeChange(event) {
  method #showAmountTypeValueTargets (line 48) | #showAmountTypeValueTargets(amountTypeColumnKey) {
  method #uniqueValuesForColumn (line 75) | #uniqueValuesForColumn(column) {
  method #enableCustomColumnFieldset (line 81) | #enableCustomColumnFieldset() {
  method #enableSignedAmountFieldset (line 100) | #enableSignedAmountFieldset() {

FILE: app/javascript/controllers/intercom_controller.js
  method show (line 5) | show() {

FILE: app/javascript/controllers/list_filter_controller.js
  method connect (line 7) | connect() {
  method filter (line 11) | filter() {

FILE: app/javascript/controllers/list_keyboard_navigation_controller.js
  method focusPrevious (line 5) | focusPrevious() {
  method focusNext (line 9) | focusNext() {
  method focusLinkTargetInDirection (line 13) | focusLinkTargetInDirection(direction) {
  method getLinkTargetInDirection (line 18) | getLinkTargetInDirection(direction) {
  method indexOfLastFocus (line 26) | indexOfLastFocus(targets = this.focusableLinks) {
  method focusableLinks (line 37) | get focusableLinks() {

FILE: app/javascript/controllers/mobile_cell_interaction_controller.js
  method connect (line 12) | connect() {
  method disconnect (line 17) | disconnect() {
  method handleDocumentClick (line 23) | handleDocumentClick(event) {
  method highlightCell (line 32) | highlightCell(event) {
  method unhighlightCell (line 40) | unhighlightCell(event) {
  method handleCellTouch (line 50) | handleCellTouch(event) {
  method toggleErrorMessage (line 73) | toggleErrorMessage(event) {
  method showErrorTooltip (line 104) | showErrorTooltip() {
  method hideAllErrorTooltips (line 119) | hideAllErrorTooltips() {
  method hideAllTooltipsExcept (line 126) | hideAllTooltipsExcept(tooltipToKeep) {
  method selectCell (line 134) | selectCell(event) {
  method findHighlightForField (line 145) | findHighlightForField(field) {

FILE: app/javascript/controllers/money_field_controller.js
  method handleCurrencyChange (line 9) | handleCurrencyChange(e) {
  method updateAmount (line 14) | updateAmount(currency) {

FILE: app/javascript/controllers/onboarding_controller.js
  method setLocale (line 5) | setLocale(event) {
  method setDateFormat (line 9) | setDateFormat(event) {
  method setCurrency (line 13) | setCurrency(event) {
  method setTheme (line 17) | setTheme(event) {
  method refreshWithParam (line 21) | refreshWithParam(key, value) {

FILE: app/javascript/controllers/password_validator_controller.js
  method connect (line 7) | connect() {
  method validate (line 11) | validate() {
  method validateRequirementText (line 37) | validateRequirementText(type, isValid) {
  method updateBlockLines (line 51) | updateBlockLines(requirementsMet) {

FILE: app/javascript/controllers/password_visibility_controller.js
  method connect (line 7) | connect() {
  method toggle (line 11) | toggle() {

FILE: app/javascript/controllers/plaid_controller.js
  method connect (line 12) | connect() {
  method open (line 16) | open() {

FILE: app/javascript/controllers/preserve_scroll_controller.js
  method connect (line 12) | connect() {
  method disconnect (line 21) | disconnect() {
  method preserveScroll (line 27) | preserveScroll() {
  method restoreScroll (line 36) | restoreScroll(event) {

FILE: app/javascript/controllers/profile_image_preview_controller.js
  method clearFileInput (line 16) | clearFileInput() {
  method showFileInputPreview (line 31) | showFileInputPreview(event) {

FILE: app/javascript/controllers/rule/actions_controller.js
  method remove (line 13) | remove(e) {
  method handleActionTypeChange (line 22) | handleActionTypeChange(e) {
  method #hideActionValue (line 40) | #hideActionValue() {
  method #clearFormFields (line 44) | #clearFormFields() {
  method #buildSelectFor (line 49) | #buildSelectFor(actionExecutor) {
  method #buildTextInputFor (line 78) | #buildTextInputFor() {

FILE: app/javascript/controllers/rule/conditions_controller.js
  method addSubCondition (line 14) | addSubCondition() {
  method remove (line 23) | remove(e) {
  method handleConditionTypeChange (line 43) | handleConditionTypeChange(e) {
  method valueInputEl (line 57) | get valueInputEl() {
  method #updateOperatorsField (line 64) | #updateOperatorsField(conditionFilter) {
  method #buildSelectFor (line 75) | #buildSelectFor(conditionFilter) {
  method #buildTextInputFor (line 88) | #buildTextInputFor(conditionFilter) {
  method #convertFormFieldTo (line 99) | #convertFormFieldTo(type, el) {
  method #uniqueKey (line 112) | #uniqueKey() {

FILE: app/javascript/controllers/rules_controller.js
  method connect (line 14) | connect() {
  method addConditionGroup (line 19) | addConditionGroup() {
  method addCondition (line 27) | addCondition() {
  method addAction (line 35) | addAction() {
  method clearEffectiveDate (line 39) | clearEffectiveDate() {
  method #appendTemplate (line 43) | #appendTemplate(templateEl, listEl) {
  method #uniqueKey (line 52) | #uniqueKey() {
  method updateConditionPrefixes (line 58) | updateConditionPrefixes() {

FILE: app/javascript/controllers/sankey_chart_controller.js
  method connect (line 14) | connect() {
  method disconnect (line 20) | disconnect() {
  method #draw (line 24) | #draw() {

FILE: app/javascript/controllers/scroll_on_connect_controller.js
  method connect (line 9) | connect() {
  method scrollToActiveItem (line 15) | scrollToActiveItem() {

FILE: app/javascript/controllers/selectable_link_controller.js
  method connect (line 5) | connect() {
  method disconnect (line 9) | disconnect() {
  method handleChange (line 13) | handleChange(event) {

FILE: app/javascript/controllers/theme_controller.js
  method connect (line 6) | connect() {
  method disconnect (line 10) | disconnect() {
  method userPreferenceValueChanged (line 15) | userPreferenceValueChanged() {
  method updateTheme (line 20) | updateTheme(event) {
  method applyTheme (line 32) | applyTheme() {
  method setTheme (line 43) | setTheme(isDark) {
  method systemPrefersDark (line 51) | systemPrefersDark() {
  method toggle (line 62) | toggle() {
  method startSystemThemeListener (line 71) | startSystemThemeListener() {
  method stopSystemThemeListener (line 79) | stopSystemThemeListener() {

FILE: app/javascript/controllers/time_series_chart_controller.js
  method connect (line 22) | connect() {
  method disconnect (line 28) | disconnect() {
  method _teardown (line 39) | _teardown() {
  method _install (line 48) | _install() {
  method _normalizeDataPoints (line 54) | _normalizeDataPoints() {
  method _rememberInitialContainerSize (line 63) | _rememberInitialContainerSize() {
  method _draw (line 68) | _draw() {
  method _drawEmpty (line 76) | _drawEmpty() {
  method _drawDashedLineEmptyState (line 84) | _drawDashedLineEmptyState() {
  method _drawCenteredCircleEmptyState (line 95) | _drawCenteredCircleEmptyState() {
  method _drawChart (line 105) | _drawChart() {
  method _drawTrendline (line 119) | _drawTrendline() {
  method _installTrendlineSplit (line 133) | _installTrendlineSplit() {
  method _setTrendlineSplitAt (line 171) | _setTrendlineSplitAt(percent) {
  method _drawXAxisLabels (line 190) | _drawXAxisLabels() {
  method _drawGradientBelowTrendline (line 222) | _drawGradientBelowTrendline() {
  method _drawTooltip (line 274) | _drawTooltip() {
  method _trackMouseForShowingTooltip (line 284) | _trackMouseForShowingTooltip() {
  method _tooltipTemplate (line 375) | _tooltipTemplate(datum) {
  method _getTrendIcon (line 401) | _getTrendIcon(datum) {
  method _createMainSvg (line 436) | _createMainSvg() {
  method _createMainGroup (line 449) | _createMainGroup() {
  method _d3Svg (line 455) | get _d3Svg() {
  method _d3Group (line 462) | get _d3Group() {
  method _margin (line 469) | get _margin() {
  method _d3ContainerWidth (line 476) | get _d3ContainerWidth() {
  method _d3ContainerHeight (line 482) | get _d3ContainerHeight() {
  method _d3Container (line 488) | get _d3Container() {
  method _trendColor (line 492) | get _trendColor() {
  method _d3Line (line 496) | get _d3Line() {
  method _d3XScale (line 503) | get _d3XScale() {
  method _d3YScale (line 510) | get _d3YScale() {
  method _setupResizeObserver (line 564) | _setupResizeObserver() {

FILE: app/javascript/controllers/tooltip_controller.js
  method connect (line 19) | connect() {
  method disconnect (line 26) | disconnect() {
  method addEventListeners (line 31) | addEventListeners() {
  method removeEventListeners (line 36) | removeEventListeners() {
  method startAutoUpdate (line 50) | startAutoUpdate() {
  method stopAutoUpdate (line 60) | stopAutoUpdate() {
  method update (line 67) | update() {

FILE: app/javascript/controllers/trade_form_controller.js
  method changeType (line 6) | async changeType(event) {

FILE: app/javascript/controllers/transfer_match_controller.js
  method update (line 7) | update(event) {

FILE: app/javascript/controllers/turbo_frame_timeout_controller.js
  method connect (line 7) | connect() {
  method disconnect (line 16) | disconnect() {
  method clearTimeout (line 20) | clearTimeout() {
  method handleTimeout (line 27) | handleTimeout() {

FILE: app/javascript/services/currencies_service.js
  class CurrenciesService (line 1) | class CurrenciesService {
    method get (line 2) | get(id) {

FILE: app/jobs/application_job.rb
  class ApplicationJob (line 1) | class ApplicationJob < ActiveJob::Base

FILE: app/jobs/assistant_response_job.rb
  class AssistantResponseJob (line 1) | class AssistantResponseJob < ApplicationJob
    method perform (line 4) | def perform(message)

FILE: app/jobs/auto_categorize_job.rb
  class AutoCategorizeJob (line 1) | class AutoCategorizeJob < ApplicationJob
    method perform (line 4) | def perform(family, transaction_ids: [])

FILE: app/jobs/auto_detect_merchants_job.rb
  class AutoDetectMerchantsJob (line 1) | class AutoDetectMerchantsJob < ApplicationJob
    method perform (line 4) | def perform(family, transaction_ids: [])

FILE: app/jobs/data_cache_clear_job.rb
  class DataCacheClearJob (line 1) | class DataCacheClearJob < ApplicationJob
    method perform (line 4) | def perform(family)

FILE: app/jobs/destroy_job.rb
  class DestroyJob (line 1) | class DestroyJob < ApplicationJob
    method perform (line 4) | def perform(model)

FILE: app/jobs/family_data_export_job.rb
  class FamilyDataExportJob (line 1) | class FamilyDataExportJob < ApplicationJob
    method perform (line 4) | def perform(family_export)

FILE: app/jobs/family_reset_job.rb
  class FamilyResetJob (line 1) | class FamilyResetJob < ApplicationJob
    method perform (line 4) | def perform(family)

FILE: app/jobs/import_job.rb
  class ImportJob (line 1) | class ImportJob < ApplicationJob
    method perform (line 4) | def perform(import)

FILE: app/jobs/import_market_data_job.rb
  class ImportMarketDataJob (line 10) | class ImportMarketDataJob < ApplicationJob
    method perform (line 13) | def perform(opts)

FILE: app/jobs/revert_import_job.rb
  class RevertImportJob (line 1) | class RevertImportJob < ApplicationJob
    method perform (line 4) | def perform(import)

FILE: app/jobs/rule_job.rb
  class RuleJob (line 1) | class RuleJob < ApplicationJob
    method perform (line 4) | def perform(rule, ignore_attribute_locks: false)

FILE: app/jobs/security_health_check_job.rb
  class SecurityHealthCheckJob (line 1) | class SecurityHealthCheckJob < ApplicationJob
    method perform (line 4) | def perform

FILE: app/jobs/stripe_event_handler_job.rb
  class StripeEventHandlerJob (line 1) | class StripeEventHandlerJob < ApplicationJob
    method perform (line 4) | def perform(event_id)

FILE: app/jobs/sync_cleaner_job.rb
  class SyncCleanerJob (line 1) | class SyncCleanerJob < ApplicationJob
    method perform (line 4) | def perform

FILE: app/jobs/sync_job.rb
  class SyncJob (line 1) | class SyncJob < ApplicationJob
    method perform (line 4) | def perform(sync)

FILE: app/jobs/user_purge_job.rb
  class UserPurgeJob (line 1) | class UserPurgeJob < ApplicationJob
    method perform (line 4) | def perform(user)

FILE: app/mailers/application_mailer.rb
  class ApplicationMailer (line 1) | class ApplicationMailer < ActionMailer::Base

FILE: app/mailers/email_confirmation_mailer.rb
  class EmailConfirmationMailer (line 1) | class EmailConfirmationMailer < ApplicationMailer
    method confirmation_email (line 7) | def confirmation_email

FILE: app/mailers/invitation_mailer.rb
  class InvitationMailer (line 1) | class InvitationMailer < ApplicationMailer
    method invite_email (line 2) | def invite_email(invitation)

FILE: app/mailers/password_mailer.rb
  class PasswordMailer (line 1) | class PasswordMailer < ApplicationMailer
    method password_reset (line 2) | def password_reset

FILE: app/models/account.rb
  class Account (line 1) | class Account < ApplicationRecord
    method create_and_sync (line 58) | def create_and_sync(attributes)
    method institution_domain (line 76) | def institution_domain
    method destroy_later (line 91) | def destroy_later
    method destroy (line 97) | def destroy
    method current_holdings (line 106) | def current_holdings
    method start_date (line 117) | def start_date
    method lock_saved_attributes! (line 122) | def lock_saved_attributes!
    method first_valuation (line 127) | def first_valuation
    method first_valuation_amount (line 131) | def first_valuation_amount
    method short_subtype_label (line 136) | def short_subtype_label
    method long_subtype_label (line 141) | def long_subtype_label
    method balance_type (line 151) | def balance_type

FILE: app/models/account/activity_feed_data.rb
  class Account::ActivityFeedData (line 4) | class Account::ActivityFeedData
    method initialize (line 9) | def initialize(account, entries)
    method entries_by_date (line 14) | def entries_by_date
    method balance_for_date (line 28) | def balance_for_date(date)
    method transfers_for_date (line 32) | def transfers_for_date(date)
    method grouped_entries (line 36) | def grouped_entries
    method balances_by_date (line 40) | def balances_by_date
    method transfers_by_date (line 51) | def transfers_by_date
    method transaction_ids (line 79) | def transaction_ids

FILE: app/models/account/anchorable.rb
  type Account::Anchorable (line 3) | module Account::Anchorable
    function set_opening_anchor_balance (line 12) | def set_opening_anchor_balance(**opts)
    function opening_anchor_date (line 18) | def opening_anchor_date
    function opening_anchor_balance (line 22) | def opening_anchor_balance
    function has_opening_anchor? (line 26) | def has_opening_anchor?
    function set_current_balance (line 30) | def set_current_balance(balance)
    function current_anchor_balance (line 36) | def current_anchor_balance
    function current_anchor_date (line 40) | def current_anchor_date
    function has_current_anchor? (line 44) | def has_current_anchor?
    function opening_balance_manager (line 49) | def opening_balance_manager
    function current_balance_manager (line 53) | def current_balance_manager

FILE: app/models/account/chartable.rb
  type Account::Chartable (line 1) | module Account::Chartable
    function favorable_direction (line 4) | def favorable_direction
    function balance_series (line 8) | def balance_series(period: Period.last_30_days, view: :balance, interv...
    function sparkline_series (line 26) | def sparkline_series

FILE: app/models/account/current_balance_manager.rb
  class Account::CurrentBalanceManager (line 1) | class Account::CurrentBalanceManager
    method initialize (line 6) | def initialize(account)
    method has_current_anchor? (line 10) | def has_current_anchor?
    method current_balance (line 16) | def current_balance
    method current_date (line 25) | def current_date
    method set_current_balance (line 33) | def set_current_balance(balance)
    method opening_balance_manager (line 51) | def opening_balance_manager
    method reconciliation_manager (line 55) | def reconciliation_manager
    method set_current_balance_for_manual_account (line 69) | def set_current_balance_for_manual_account(balance)
    method adjust_opening_balance_with_delta (line 83) | def adjust_opening_balance_with_delta(new_balance:, old_balance:)
    method set_current_balance_for_linked_account (line 95) | def set_current_balance_for_linked_account(balance)
    method current_anchor_valuation (line 105) | def current_anchor_valuation
    method create_current_anchor (line 109) | def create_current_anchor(balance)
    method update_current_anchor (line 119) | def update_current_anchor(balance)

FILE: app/models/account/linkable.rb
  type Account::Linkable (line 1) | module Account::Linkable
    function linked? (line 9) | def linked?
    function unlinked? (line 15) | def unlinked?

FILE: app/models/account/market_data_importer.rb
  class Account::MarketDataImporter (line 1) | class Account::MarketDataImporter
    method initialize (line 4) | def initialize(account)
    method import_all (line 8) | def import_all
    method import_exchange_rates (line 13) | def import_exchange_rates
    method import_security_prices (line 45) | def import_security_prices
    method first_required_price_date (line 64) | def first_required_price_date(security)
    method needs_exchange_rates? (line 71) | def needs_exchange_rates?
    method has_multi_currency_entries? (line 75) | def has_multi_currency_entries?
    method foreign_account? (line 79) | def foreign_account?

FILE: app/models/account/opening_balance_manager.rb
  class Account::OpeningBalanceManager (line 1) | class Account::OpeningBalanceManager
    method initialize (line 4) | def initialize(account)
    method has_opening_anchor? (line 8) | def has_opening_anchor?
    method opening_date (line 13) | def opening_date
    method opening_balance (line 22) | def opening_balance
    method set_opening_balance (line 26) | def set_opening_balance(balance:, date: nil)
    method opening_anchor_valuation (line 49) | def opening_anchor_valuation
    method oldest_entry_date (line 53) | def oldest_entry_date
    method default_date (line 57) | def default_date
    method create_opening_anchor (line 65) | def create_opening_anchor(balance:, date:)
    method update_opening_anchor (line 77) | def update_opening_anchor(balance:, date: nil)

FILE: app/models/account/reconcileable.rb
  type Account::Reconcileable (line 1) | module Account::Reconcileable
    function create_reconciliation (line 4) | def create_reconciliation(balance:, date:, dry_run: false)
    function update_reconciliation (line 10) | def update_reconciliation(existing_valuation_entry, balance:, date:, d...
    function reconciliation_manager (line 17) | def reconciliation_manager

FILE: app/models/account/reconciliation_manager.rb
  class Account::ReconciliationManager (line 1) | class Account::ReconciliationManager
    method initialize (line 4) | def initialize(account)
    method reconcile_balance (line 9) | def reconcile_balance(balance:, date: Date.current, dry_run: false, ex...
    method prepare_reconciliation (line 44) | def prepare_reconciliation(balance, date, existing_valuation)
    method derived_cash_balance (line 61) | def derived_cash_balance(date:, total_balance:)
    method old_balance_components (line 73) | def old_balance_components(reconciliation_date:, existing_valuation_en...
    method get_balance_components_for_date (line 81) | def get_balance_components_for_date(date)

FILE: app/models/account/sync_complete_event.rb
  class Account::SyncCompleteEvent (line 1) | class Account::SyncCompleteEvent
    method initialize (line 6) | def initialize(account)
    method broadcast (line 10) | def broadcast
    method sidebar_targets (line 43) | def sidebar_targets
    method account_group (line 54) | def account_group
    method family_balance_sheet (line 60) | def family_balance_sheet

FILE: app/models/account/syncer.rb
  class Account::Syncer (line 1) | class Account::Syncer
    method initialize (line 4) | def initialize(account)
    method perform_sync (line 8) | def perform_sync(sync)
    method perform_post_sync (line 14) | def perform_post_sync
    method materialize_balances (line 19) | def materialize_balances
    method import_market_data (line 31) | def import_market_data

FILE: app/models/account_import.rb
  class AccountImport (line 1) | class AccountImport < Import
    method import! (line 4) | def import!
    method mapping_steps (line 31) | def mapping_steps
    method required_column_keys (line 35) | def required_column_keys
    method column_keys (line 39) | def column_keys
    method dry_run (line 43) | def dry_run
    method csv_template (line 49) | def csv_template
    method max_row_count (line 60) | def max_row_count

FILE: app/models/address.rb
  class Address (line 1) | class Address < ApplicationRecord
    method to_s (line 4) | def to_s

FILE: app/models/api_key.rb
  class ApiKey (line 1) | class ApiKey < ApplicationRecord
    method find_by_value (line 25) | def self.find_by_value(plain_key)
    method generate_secure_key (line 34) | def self.generate_secure_key
    method active? (line 39) | def active?
    method revoked? (line 43) | def revoked?
    method expired? (line 47) | def expired?
    method key_matches? (line 51) | def key_matches?(plain_key)
    method revoke! (line 55) | def revoke!
    method update_last_used! (line 59) | def update_last_used!
    method plain_key (line 64) | def plain_key
    method set_display_key (line 73) | def set_display_key
    method scopes_not_empty (line 79) | def scopes_not_empty
    method one_active_key_per_user_per_source (line 89) | def one_active_key_per_user_per_source

FILE: app/models/application_record.rb
  class ApplicationRecord (line 1) | class ApplicationRecord < ActiveRecord::Base

FILE: app/models/assistant.rb
  class Assistant (line 1) | class Assistant
    method for_chat (line 7) | def for_chat(chat)
    method initialize (line 13) | def initialize(chat, instructions: nil, functions: [])
    method respond_to (line 19) | def respond_to(message)
    method function_tool_caller (line 68) | def function_tool_caller

FILE: app/models/assistant/broadcastable.rb
  type Assistant::Broadcastable (line 1) | module Assistant::Broadcastable
    function update_thinking (line 5) | def update_thinking(thought)
    function stop_thinking (line 9) | def stop_thinking

FILE: app/models/assistant/configurable.rb
  type Assistant::Configurable (line 1) | module Assistant::Configurable
    function config_for (line 5) | def config_for(chat)
    function default_functions (line 16) | def default_functions
    function default_instructions (line 25) | def default_instructions(preferred_currency, preferred_date_format)

FILE: app/models/assistant/function.rb
  class Assistant::Function (line 1) | class Assistant::Function
    method name (line 3) | def name
    method description (line 7) | def description
    method initialize (line 12) | def initialize(user)
    method call (line 16) | def call(params = {})
    method name (line 20) | def name
    method description (line 24) | def description
    method params_schema (line 28) | def params_schema
    method strict_mode? (line 33) | def strict_mode?
    method to_definition (line 37) | def to_definition
    method build_schema (line 49) | def build_schema(properties: {}, required: [])
    method family_account_names (line 58) | def family_account_names
    method family_category_names (line 62) | def family_category_names
    method family_merchant_names (line 70) | def family_merchant_names
    method family_tag_names (line 74) | def family_tag_names
    method family (line 78) | def family
    method to_ai_time_series (line 84) | def to_ai_time_series(series)

FILE: app/models/assistant/function/get_accounts.rb
  class Assistant::Function::GetAccounts (line 1) | class Assistant::Function::GetAccounts < Assistant::Function
    method name (line 3) | def name
    method description (line 7) | def description
    method call (line 12) | def call(params = {})
    method historical_balances (line 33) | def historical_balances(account)

FILE: app/models/assistant/function/get_balance_sheet.rb
  class Assistant::Function::GetBalanceSheet (line 1) | class Assistant::Function::GetBalanceSheet < Assistant::Function
    method name (line 5) | def name
    method description (line 9) | def description
    method call (line 20) | def call(params = {})
    method historical_data (line 46) | def historical_data(period, classification: nil)
    method insights_data (line 67) | def insights_data

FILE: app/models/assistant/function/get_income_statement.rb
  class Assistant::Function::GetIncomeStatement (line 1) | class Assistant::Function::GetIncomeStatement < Assistant::Function
    method name (line 5) | def name
    method description (line 9) | def description
    method call (line 30) | def call(params = {})
    method params_schema (line 53) | def params_schema
    method format_money (line 70) | def format_money(value)
    method calculate_savings_rate (line 74) | def calculate_savings_rate(total_income, total_expenses)
    method to_ai_category_totals (line 81) | def to_ai_category_totals(category_totals)
    method get_insights (line 110) | def get_insights(income_data, expense_data)

FILE: app/models/assistant/function/get_transactions.rb
  class Assistant::Function::GetTransactions (line 1) | class Assistant::Function::GetTransactions < Assistant::Function
    method default_page_size (line 5) | def default_page_size
    method name (line 9) | def name
    method description (line 13) | def description
    method strict_mode? (line 65) | def strict_mode?
    method params_schema (line 69) | def params_schema
    method call (line 134) | def call(params = {})
    method default_page_size (line 183) | def default_page_size

FILE: app/models/assistant/function_tool_caller.rb
  class Assistant::FunctionToolCaller (line 1) | class Assistant::FunctionToolCaller
    method initialize (line 7) | def initialize(functions = [])
    method fulfill_requests (line 11) | def fulfill_requests(function_requests)
    method function_definitions (line 19) | def function_definitions
    method execute (line 24) | def execute(function_request)
    method find_function (line 34) | def find_function(function_request)

FILE: app/models/assistant/provided.rb
  type Assistant::Provided (line 1) | module Assistant::Provided
    function get_model_provider (line 4) | def get_model_provider(ai_model)
    function registry (line 9) | def registry

FILE: app/models/assistant/responder.rb
  class Assistant::Responder (line 1) | class Assistant::Responder
    method initialize (line 2) | def initialize(message:, instructions:, function_tool_caller:, llm:)
    method on (line 9) | def on(event_name, &block)
    method respond (line 13) | def respond(previous_response_id: nil)
    method handle_follow_up_response (line 36) | def handle_follow_up_response(response)
    method get_llm_response (line 62) | def get_llm_response(streamer:, function_results: [], previous_respons...
    method emit (line 80) | def emit(event_name, payload = nil)
    method listeners (line 84) | def listeners

FILE: app/models/assistant_message.rb
  class AssistantMessage (line 1) | class AssistantMessage < Message
    method role (line 4) | def role
    method append_text! (line 8) | def append_text!(text)

FILE: app/models/balance.rb
  class Balance (line 1) | class Balance < ApplicationRecord
    method balance_trend (line 18) | def balance_trend
    method favorable_direction (line 28) | def favorable_direction

FILE: app/models/balance/base_calculator.rb
  class Balance::BaseCalculator (line 1) | class Balance::BaseCalculator
    method initialize (line 4) | def initialize(account)
    method calculate (line 8) | def calculate
    method sync_cache (line 13) | def sync_cache
    method holdings_value_for_date (line 17) | def holdings_value_for_date(date)
    method derive_cash_balance_on_date_from_total (line 22) | def derive_cash_balance_on_date_from_total(total_balance:, date:)
    method cash_adjustments_for_date (line 32) | def cash_adjustments_for_date(start_cash, end_cash, net_cash_flows)
    method non_cash_adjustments_for_date (line 38) | def non_cash_adjustments_for_date(start_non_cash, end_non_cash, non_ca...
    method market_value_change_on_date (line 47) | def market_value_change_on_date(date, flows)
    method flows_for_date (line 59) | def flows_for_date(date)
    method derive_cash_balance (line 93) | def derive_cash_balance(cash_balance, date)
    method derive_non_cash_balance (line 103) | def derive_non_cash_balance(non_cash_balance, date, direction: :forward)
    method signed_entry_flows (line 117) | def signed_entry_flows(entries)
    method build_balance (line 121) | def build_balance(date:, **args)

FILE: app/models/balance/chart_series_builder.rb
  class Balance::ChartSeriesBuilder (line 1) | class Balance::ChartSeriesBuilder
    method initialize (line 2) | def initialize(account_ids:, currency:, period: Period.last_30_days, i...
    method balance_series (line 10) | def balance_series
    method cash_balance_series (line 17) | def cash_balance_series
    method holdings_balance_series (line 24) | def holdings_balance_series
    method interval (line 34) | def interval
    method build_series_for (line 38) | def build_series_for(column)
    method query_data (line 68) | def query_data
    method sign_multiplier (line 89) | def sign_multiplier
    method query (line 93) | def query

FILE: app/models/balance/forward_calculator.rb
  class Balance::ForwardCalculator (line 1) | class Balance::ForwardCalculator < Balance::BaseCalculator
    method calculate (line 2) | def calculate
    method calc_start_date (line 55) | def calc_start_date
    method calc_end_date (line 59) | def calc_end_date
    method signed_entry_flows (line 67) | def signed_entry_flows(entries)
    method derive_end_cash_balance (line 73) | def derive_end_cash_balance(start_cash_balance:, date:)
    method derive_end_non_cash_balance (line 78) | def derive_end_non_cash_balance(start_non_cash_balance:, date:)
    method flows_factor (line 82) | def flows_factor

FILE: app/models/balance/materializer.rb
  class Balance::Materializer (line 1) | class Balance::Materializer
    method initialize (line 4) | def initialize(account, strategy:)
    method materialize_balances (line 9) | def materialize_balances
    method materialize_holdings (line 26) | def materialize_holdings
    method update_account_info (line 30) | def update_account_info
    method calculate_balances (line 54) | def calculate_balances
    method persist_balances (line 58) | def persist_balances
    method purge_stale_balances (line 74) | def purge_stale_balances
    method calculator (line 82) | def calculator

FILE: app/models/balance/reverse_calculator.rb
  class Balance::ReverseCalculator (line 1) | class Balance::ReverseCalculator < Balance::BaseCalculator
    method calculate (line 2) | def calculate
    method signed_entry_flows (line 59) | def signed_entry_flows(entries)
    method derive_start_cash_balance (line 66) | def derive_start_cash_balance(end_cash_balance:, date:)
    method derive_start_non_cash_balance (line 72) | def derive_start_non_cash_balance(end_non_cash_balance:, date:)
    method use_opening_anchor_for_date? (line 79) | def use_opening_anchor_for_date?(date)

FILE: app/models/balance/sync_cache.rb
  class Balance::SyncCache (line 1) | class Balance::SyncCache
    method initialize (line 2) | def initialize(account)
    method get_valuation (line 6) | def get_valuation(date)
    method get_holdings (line 10) | def get_holdings(date)
    method get_entries (line 14) | def get_entries(date)
    method converted_entries (line 21) | def converted_entries
    method converted_holdings (line 34) | def converted_holdings

FILE: app/models/balance_sheet.rb
  class BalanceSheet (line 1) | class BalanceSheet
    method initialize (line 8) | def initialize(family)
    method assets (line 12) | def assets
    method liabilities (line 20) | def liabilities
    method classification_groups (line 28) | def classification_groups
    method account_groups (line 32) | def account_groups
    method net_worth (line 36) | def net_worth
    method net_worth_series (line 40) | def net_worth_series(period: Period.last_30_days)
    method currency (line 44) | def currency
    method syncing? (line 48) | def syncing?
    method sync_status_monitor (line 53) | def sync_status_monitor
    method account_totals (line 57) | def account_totals
    method net_worth_series_builder (line 61) | def net_worth_series_builder

FILE: app/models/balance_sheet/account_group.rb
  class BalanceSheet::AccountGroup (line 1) | class BalanceSheet::AccountGroup
    method initialize (line 8) | def initialize(name:, color:, accountable_type:, accounts:, classifica...
    method dom_id (line 24) | def dom_id(tab: nil, mobile: false)
    method key (line 32) | def key
    method total (line 36) | def total
    method weight (line 40) | def weight
    method syncing? (line 46) | def syncing?
    method classification (line 51) | def classification
    method currency (line 55) | def currency

FILE: app/models/balance_sheet/account_totals.rb
  class BalanceSheet::AccountTotals (line 1) | class BalanceSheet::AccountTotals
    method initialize (line 2) | def initialize(family, sync_status_monitor:)
    method asset_accounts (line 7) | def asset_accounts
    method liability_accounts (line 11) | def liability_accounts
    method syncing? (line 19) | def syncing? = is_syncing
    method to_param (line 22) | def to_param = account.to_param
    method visible_accounts (line 26) | def visible_accounts
    method account_rows (line 30) | def account_rows
    method cache_key (line 40) | def cache_key
    method query (line 47) | def query

FILE: app/models/balance_sheet/classification_group.rb
  class BalanceSheet::ClassificationGroup (line 1) | class BalanceSheet::ClassificationGroup
    method initialize (line 8) | def initialize(classification:, currency:, accounts:)
    method name (line 15) | def name
    method icon (line 19) | def icon
    method total (line 23) | def total
    method syncing? (line 27) | def syncing?
    method account_groups (line 32) | def account_groups
    method normalize_classification! (line 57) | def normalize_classification!(classification)

FILE: app/models/balance_sheet/net_worth_series_builder.rb
  class BalanceSheet::NetWorthSeriesBuilder (line 1) | class BalanceSheet::NetWorthSeriesBuilder
    method initialize (line 2) | def initialize(family)
    method net_worth_series (line 6) | def net_worth_series(period: Period.last_30_days)
    method visible_account_ids (line 22) | def visible_account_ids
    method cache_key (line 26) | def cache_key(period)

FILE: app/models/balance_sheet/sync_status_monitor.rb
  class BalanceSheet::SyncStatusMonitor (line 1) | class BalanceSheet::SyncStatusMonitor
    method initialize (line 2) | def initialize(family)
    method syncing? (line 6) | def syncing?
    method account_syncing? (line 10) | def account_syncing?(account)
    method syncing_account_ids (line 17) | def syncing_account_ids
    method cache_key (line 28) | def cache_key

FILE: app/models/budget.rb
  class Budget (line 1) | class Budget < ApplicationRecord
    method date_to_param (line 18) | def date_to_param(date)
    method param_to_date (line 22) | def param_to_date(param)
    method budget_date_valid? (line 26) | def budget_date_valid?(date, family:)
    method find_or_bootstrap (line 32) | def find_or_bootstrap(family, start_date:)
    method oldest_valid_budget_date (line 51) | def oldest_valid_budget_date(family)
    method period (line 59) | def period
    method to_param (line 63) | def to_param
    method sync_budget_categories (line 67) | def sync_budget_categories
    method uncategorized_budget_category (line 86) | def uncategorized_budget_category
    method transactions (line 93) | def transactions
    method name (line 97) | def name
    method initialized? (line 101) | def initialized?
    method income_category_totals (line 105) | def income_category_totals
    method expense_category_totals (line 109) | def expense_category_totals
    method current? (line 113) | def current?
    method previous_budget_param (line 117) | def previous_budget_param
    method next_budget_param (line 124) | def next_budget_param
    method to_donut_segments_json (line 133) | def to_donut_segments_json
    method estimated_spending (line 153) | def estimated_spending
    method actual_spending (line 157) | def actual_spending
    method budget_category_actual_spending (line 161) | def budget_category_actual_spending(budget_category)
    method category_median_monthly_expense (line 165) | def category_median_monthly_expense(category)
    method category_avg_monthly_expense (line 169) | def category_avg_monthly_expense(category)
    method available_to_spend (line 173) | def available_to_spend
    method percent_of_budget_spent (line 177) | def percent_of_budget_spent
    method overage_percent (line 183) | def overage_percent
    method allocated_spending (line 192) | def allocated_spending
    method allocated_percent (line 196) | def allocated_percent
    method available_to_allocate (line 202) | def available_to_allocate
    method allocations_valid? (line 206) | def allocations_valid?
    method estimated_income (line 213) | def estimated_income
    method actual_income (line 217) | def actual_income
    method actual_income_percent (line 221) | def actual_income_percent
    method remaining_expected_income (line 227) | def remaining_expected_income
    method surplus_percent (line 231) | def surplus_percent
    method income_statement (line 238) | def income_statement
    method expense_totals (line 242) | def expense_totals
    method income_totals (line 246) | def income_totals

FILE: app/models/budget_category.rb
  class BudgetCategory (line 1) | class BudgetCategory < ApplicationRecord
    class Group (line 11) | class Group
      method for (line 17) | def self.for(budget_categories)
      method initialize (line 25) | def initialize(budget_category, budget_subcategories = [])
    method uncategorized (line 32) | def uncategorized
    method initialized? (line 40) | def initialized?
    method category (line 44) | def category
    method name (line 48) | def name
    method actual_spending (line 52) | def actual_spending
    method avg_monthly_expense (line 56) | def avg_monthly_expense
    method median_monthly_expense (line 60) | def median_monthly_expense
    method subcategory? (line 64) | def subcategory?
    method available_to_spend (line 68) | def available_to_spend
    method percent_of_budget_spent (line 72) | def percent_of_budget_spent
    method to_donut_segments_json (line 78) | def to_donut_segments_json
    method siblings (line 95) | def siblings
    method max_allocation (line 99) | def max_allocation
    method subcategories (line 108) | def subcategories
    method subcategory? (line 116) | def subcategory?

FILE: app/models/category.rb
  class Category (line 1) | class Category < ApplicationRecord
    class Group (line 31) | class Group
      method for (line 36) | def self.for(categories)
      method initialize (line 42) | def initialize(category, subcategories = nil)
    method icon_codes (line 49) | def icon_codes
    method bootstrap! (line 53) | def bootstrap!
    method uncategorized (line 63) | def uncategorized
    method default_categories (line 72) | def default_categories
    method inherit_color_from_parent (line 92) | def inherit_color_from_parent
    method replace_and_destroy! (line 98) | def replace_and_destroy!(replacement)
    method parent? (line 105) | def parent?
    method subcategory? (line 109) | def subcategory?
    method category_level_limit (line 114) | def category_level_limit
    method nested_category_matches_parent_classification (line 120) | def nested_category_matches_parent_classification
    method monetizable_currency (line 126) | def monetizable_currency

FILE: app/models/chat.rb
  class Chat (line 1) | class Chat < ApplicationRecord
    method start! (line 14) | def start!(prompt, model:)
    method generate_title (line 21) | def generate_title(prompt)
    method needs_assistant_response? (line 26) | def needs_assistant_response?
    method retry_last_message! (line 30) | def retry_last_message!
    method update_latest_response! (line 41) | def update_latest_response!(provider_response_id)
    method add_error (line 45) | def add_error(e)
    method clear_error (line 50) | def clear_error
    method assistant (line 55) | def assistant
    method ask_assistant_later (line 59) | def ask_assistant_later(message)
    method ask_assistant (line 64) | def ask_assistant(message)
    method conversation_messages (line 68) | def conversation_messages

FILE: app/models/chat/debuggable.rb
  type Chat::Debuggable (line 1) | module Chat::Debuggable
    function debug_mode? (line 4) | def debug_mode?

FILE: app/models/concerns/accountable.rb
  type Accountable (line 1) | module Accountable
    function from_type (line 9) | def self.from_type(type)
    function classification (line 21) | def classification
    function icon (line 25) | def icon
    function color (line 29) | def color
    function subtype_label_for (line 34) | def subtype_label_for(subtype, format: :short)
    function short_subtype_label_for (line 42) | def short_subtype_label_for(subtype)
    function long_subtype_label_for (line 47) | def long_subtype_label_for(subtype)
    function favorable_direction (line 51) | def favorable_direction
    function display_name (line 55) | def display_name
    function balance_money (line 59) | def balance_money(family)
    function display_name (line 71) | def display_name
    function balance_display_name (line 75) | def balance_display_name
    function opening_balance_display_name (line 79) | def opening_balance_display_name
    function icon (line 83) | def icon
    function color (line 87) | def color
    function classification (line 91) | def classification

FILE: app/models/concerns/enrichable.rb
  type Enrichable (line 12) | module Enrichable
    function enrich_attribute (line 26) | def enrich_attribute(attr, value, source:, metadata: {})
    function enrich_attributes (line 34) | def enrich_attributes(attrs, source:, metadata: {})
    function locked? (line 53) | def locked?(attr)
    function enrichable? (line 57) | def enrichable?(attr)
    function lock_attr! (line 61) | def lock_attr!(attr)
    function unlock_attr! (line 65) | def unlock_attr!(attr)
    function lock_saved_attributes! (line 69) | def lock_saved_attributes!
    function log_enrichment (line 76) | def log_enrichment(attribute_name:, attribute_value:, source:, metadat...
    function ignored_enrichable_attributes (line 88) | def ignored_enrichable_attributes

FILE: app/models/concerns/monetizable.rb
  type Monetizable (line 1) | module Monetizable
    function monetize (line 5) | def monetize(*fields)
    function monetizable_currency (line 19) | def monetizable_currency

FILE: app/models/concerns/syncable.rb
  type Syncable (line 1) | module Syncable
    function syncing? (line 8) | def syncing?
    function sync_later (line 14) | def sync_later(parent_sync: nil, window_start_date: nil, window_end_da...
    function perform_sync (line 37) | def perform_sync(sync)
    function perform_post_sync (line 41) | def perform_post_sync
    function broadcast_sync_complete (line 45) | def broadcast_sync_complete
    function sync_error (line 49) | def sync_error
    function last_synced_at (line 53) | def last_synced_at
    function last_sync_created_at (line 57) | def last_sync_created_at
    function latest_sync (line 62) | def latest_sync
    function syncer (line 66) | def syncer
    function sync_broadcaster (line 70) | def sync_broadcaster

FILE: app/models/credit_card.rb
  class CreditCard (line 1) | class CreditCard < ApplicationRecord
    method color (line 9) | def color
    method icon (line 13) | def icon
    method classification (line 17) | def classification
    method available_credit_money (line 22) | def available_credit_money
    method minimum_payment_money (line 26) | def minimum_payment_money
    method annual_fee_money (line 30) | def annual_fee_money

FILE: app/models/crypto.rb
  class Crypto (line 1) | class Crypto < ApplicationRecord
    method color (line 5) | def color
    method classification (line 9) | def classification
    method icon (line 13) | def icon
    method display_name (line 17) | def display_name

FILE: app/models/current.rb
  class Current (line 1) | class Current < ActiveSupport::CurrentAttributes
    method user (line 8) | def user
    method impersonated_user (line 12) | def impersonated_user
    method true_user (line 16) | def true_user

FILE: app/models/data_enrichment.rb
  class DataEnrichment (line 1) | class DataEnrichment < ApplicationRecord

FILE: app/models/demo/data_cleaner.rb
  class Demo::DataCleaner (line 2) | class Demo::DataCleaner
    method initialize (line 5) | def initialize
    method destroy_everything! (line 10) | def destroy_everything!
    method ensure_safe_environment! (line 23) | def ensure_safe_environment!

FILE: app/models/demo/generator.rb
  class Demo::Generator (line 1) | class Demo::Generator
    method initialize (line 11) | def initialize(seed: ENV.fetch("DEMO_DATA_SEED", nil))
    method generate_empty_data! (line 33) | def generate_empty_data!(skip_clear: false)
    method generate_new_user_data! (line 48) | def generate_new_user_data!(skip_clear: false)
    method generate_default_data! (line 63) | def generate_default_data!(skip_clear: false, email: "user@maybe.local")
    method with_timing (line 92) | def with_timing(label, max_seconds: nil)
    method rand (line 107) | def rand(*args)
    method clear_all_data! (line 113) | def clear_all_data!
    method create_family_and_users! (line 121) | def create_family_and_users!(family_name, email, onboarded:, subscribed:)
    method create_realistic_categories! (line 156) | def create_realistic_categories!(family)
    method create_realistic_accounts! (line 190) | def create_realistic_accounts!(family)
    method create_realistic_transactions! (line 233) | def create_realistic_transactions!(family)
    method generate_budget_auto_fill! (line 294) | def generate_budget_auto_fill!(family)
    method weighted_random_date (line 330) | def weighted_random_date
    method random_checking_account (line 336) | def random_checking_account
    method generate_salary_history! (line 343) | def generate_salary_history!
    method generate_housing_transactions! (line 393) | def generate_housing_transactions!
    method generate_food_transactions! (line 425) | def generate_food_transactions!
    method generate_transportation_transactions! (line 451) | def generate_transportation_transactions!
    method generate_entertainment_transactions! (line 470) | def generate_entertainment_transactions!
    method generate_shopping_transactions! (line 496) | def generate_shopping_transactions!
    method generate_healthcare_transactions! (line 514) | def generate_healthcare_transactions!
    method generate_travel_transactions! (line 532) | def generate_travel_transactions!
    method generate_personal_care_transactions! (line 557) | def generate_personal_care_transactions!
    method generate_investment_transactions! (line 573) | def generate_investment_transactions!
    method generate_401k_trades! (line 583) | def generate_401k_trades!(security)
    method generate_brokerage_trades! (line 596) | def generate_brokerage_trades!(security)
    method generate_roth_trades! (line 608) | def generate_roth_trades!(security)
    method generate_uk_isa_trades! (line 621) | def generate_uk_isa_trades!(security)
    method collect_payroll_dates (line 633) | def collect_payroll_dates
    method create_trade_for (line 644) | def create_trade_for(account, security, investment_amount, date, memo,...
    method generate_major_purchases! (line 650) | def generate_major_purchases!
    method generate_transfers_and_payments! (line 675) | def generate_transfers_and_payments!
    method generate_additional_savings_transfers! (line 684) | def generate_additional_savings_transfers!
    method generate_monthly_ally_transfers! (line 724) | def generate_monthly_ally_transfers!
    method generate_quarterly_fx_transfers! (line 734) | def generate_quarterly_fx_transfers!
    method first_business_day (line 744) | def first_business_day(date)
    method generate_credit_card_cycles! (line 750) | def generate_credit_card_cycles!
    method generate_credit_card_charges (line 829) | def generate_credit_card_charges(account, base_date, count)
    method random_expense_category (line 852) | def random_expense_category
    method create_transaction! (line 856) | def create_transaction!(account, amount, name, category, date)
    method create_investment_transaction! (line 869) | def create_investment_transaction!(account, security, qty, price, date...
    method create_transfer! (line 879) | def create_transfer!(from_account, to_account, amount, name, date)
    method load_securities! (line 897) | def load_securities!
    method sync_family_accounts! (line 907) | def sync_family_accounts!(family)
    method pick (line 924) | def pick(array)
    method jitter (line 934) | def jitter(num, pct = 0.03)
    method generate_loan_payments! (line 942) | def generate_loan_payments!
    method make_loan_payment! (line 981) | def make_loan_payment!(principal_account:, principal_amount:, interest...
    method generate_regular_expenses! (line 990) | def generate_regular_expenses!
    method generate_micro_transactions! (line 1013) | def generate_micro_transactions!
    method generate_legacy_transactions! (line 1097) | def generate_legacy_transactions!
    method generate_crypto_and_misc_assets! (line 1162) | def generate_crypto_and_misc_assets!
    method reconcile_balances! (line 1171) | def reconcile_balances!(family)

FILE: app/models/depository.rb
  class Depository (line 1) | class Depository < ApplicationRecord
    method display_name (line 13) | def display_name
    method color (line 17) | def color
    method classification (line 21) | def classification
    method icon (line 25) | def icon

FILE: app/models/developer_message.rb
  class DeveloperMessage (line 1) | class DeveloperMessage < Message
    method role (line 2) | def role
    method broadcast? (line 7) | def broadcast?

FILE: app/models/entry.rb
  class Entry (line 1) | class Entry < ApplicationRecord
    method classification (line 37) | def classification
    method lock_saved_attributes! (line 41) | def lock_saved_attributes!
    method sync_account_later (line 46) | def sync_account_later
    method entryable_name_short (line 51) | def entryable_name_short
    method balance_trend (line 55) | def balance_trend(entries, balances)
    method linked? (line 59) | def linked?
    method search (line 64) | def search(params)
    method min_supported_date (line 69) | def min_supported_date
    method bulk_update! (line 73) | def bulk_update!(bulk_update_params)

FILE: app/models/entry_search.rb
  class EntrySearch (line 1) | class EntrySearch
    method apply_search_filter (line 15) | def apply_search_filter(scope, search)
    method apply_date_filters (line 25) | def apply_date_filters(scope, start_date, end_date)
    method apply_amount_filter (line 34) | def apply_amount_filter(scope, amount, amount_operator)
    method apply_accounts_filter (line 51) | def apply_accounts_filter(scope, accounts, account_ids)
    method build_query (line 61) | def build_query(scope)

FILE: app/models/entryable.rb
  type Entryable (line 1) | module Entryable
    function from_type (line 6) | def self.from_type(entryable_type)

FILE: app/models/exchange_rate.rb
  class ExchangeRate (line 1) | class ExchangeRate < ApplicationRecord

FILE: app/models/exchange_rate/importer.rb
  class ExchangeRate::Importer (line 1) | class ExchangeRate::Importer
    method initialize (line 5) | def initialize(exchange_rate_provider:, from:, to:, start_date:, end_d...
    method import_provider_rates (line 15) | def import_provider_rates
    method upsert_rows (line 66) | def upsert_rows(rows)
    method start_rate_value (line 85) | def start_rate_value
    method effective_start_date (line 92) | def effective_start_date
    method provider_rates (line 107) | def provider_rates
    method all_rates_exist? (line 130) | def all_rates_exist?
    method expected_count (line 134) | def expected_count
    method db_count (line 138) | def db_count
    method db_rates (line 142) | def db_rates
    method normalize_end_date (line 152) | def normalize_end_date(requested_end_date)

FILE: app/models/exchange_rate/provided.rb
  type ExchangeRate::Provided (line 1) | module ExchangeRate::Provided
    function provider (line 5) | def provider
    function find_or_fetch_rate (line 10) | def find_or_fetch_rate(from:, to:, date: Date.current, cache: true)
    function import_provider_rates (line 31) | def import_provider_rates(from:, to:, start_date:, end_date:, clear_ca...

FILE: app/models/family.rb
  class Family (line 1) | class Family < ApplicationRecord
    method assigned_merchants (line 39) | def assigned_merchants
    method auto_categorize_transactions_later (line 44) | def auto_categorize_transactions_later(transactions)
    method auto_categorize_transactions (line 48) | def auto_categorize_transactions(transaction_ids)
    method auto_detect_transaction_merchants_later (line 52) | def auto_detect_transaction_merchants_later(transactions)
    method auto_detect_transaction_merchants (line 56) | def auto_detect_transaction_merchants(transaction_ids)
    method balance_sheet (line 60) | def balance_sheet
    method income_statement (line 64) | def income_statement
    method eu? (line 68) | def eu?
    method requires_data_provider? (line 72) | def requires_data_provider?
    method missing_data_provider? (line 87) | def missing_data_provider?
    method oldest_entry_date (line 91) | def oldest_entry_date
    method build_cache_key (line 96) | def build_cache_key(key, invalidate_on_data_updates: false)
    method entries_cache_version (line 110) | def entries_cache_version
    method self_hoster? (line 117) | def self_hoster?

FILE: app/models/family/auto_categorizer.rb
  class Family::AutoCategorizer (line 1) | class Family::AutoCategorizer
    method initialize (line 4) | def initialize(family, transaction_ids: [])
    method auto_categorize (line 9) | def auto_categorize
    method llm_provider (line 50) | def llm_provider
    method user_categories_input (line 54) | def user_categories_input
    method transactions_input (line 66) | def transactions_input
    method scope (line 78) | def scope

FILE: app/models/family/auto_merchant_detector.rb
  class Family::AutoMerchantDetector (line 1) | class Family::AutoMerchantDetector
    method initialize (line 4) | def initialize(family, transaction_ids: [])
    method auto_detect (line 9) | def auto_detect
    method llm_provider (line 64) | def llm_provider
    method default_logo_provider_url (line 68) | def default_logo_provider_url
    method user_merchants_input (line 72) | def user_merchants_input
    method transactions_input (line 81) | def transactions_input
    method scope (line 93) | def scope

FILE: app/models/family/auto_transfer_matchable.rb
  type Family::AutoTransferMatchable (line 1) | module Family::AutoTransferMatchable
    function transfer_match_candidates (line 2) | def transfer_match_candidates
    function auto_match_transfers! (line 49) | def auto_match_transfers!

FILE: app/models/family/data_exporter.rb
  class Family::DataExporter (line 4) | class Family::DataExporter
    method initialize (line 5) | def initialize(family)
    method generate_export (line 9) | def generate_export
    method generate_accounts_csv (line 40) | def generate_accounts_csv
    method generate_transactions_csv (line 59) | def generate_transactions_csv
    method generate_trades_csv (line 81) | def generate_trades_csv
    method generate_categories_csv (line 102) | def generate_categories_csv
    method generate_ndjson (line 118) | def generate_ndjson

FILE: app/models/family/plaid_connectable.rb
  type Family::PlaidConnectable (line 1) | module Family::PlaidConnectable
    function can_connect_plaid_us? (line 8) | def can_connect_plaid_us?
    function can_connect_plaid_eu? (line 13) | def can_connect_plaid_eu?
    function create_plaid_item! (line 17) | def create_plaid_item!(public_token:, item_name:, region:)
    function get_link_token (line 32) | def get_link_token(webhooks_url:, redirect_url:, accountable_type: nil...
    function plaid (line 45) | def plaid(region)

FILE: app/models/family/subscribeable.rb
  type Family::Subscribeable (line 1) | module Family::Subscribeable
    function billing_email (line 8) | def billing_email
    function upgrade_required? (line 18) | def upgrade_required?
    function can_start_trial? (line 25) | def can_start_trial?
    function start_trial_subscription! (line 29) | def start_trial_subscription!
    function trialing? (line 36) | def trialing?
    function has_active_subscription? (line 40) | def has_active_subscription?
    function needs_subscription? (line 44) | def needs_subscription?
    function next_billing_date (line 48) | def next_billing_date
    function start_subscription! (line 52) | def start_subscription!(stripe_subscription_id)
    function days_left_in_trial (line 60) | def days_left_in_trial
    function percentage_of_trial_remaining (line 65) | def percentage_of_trial_remaining
    function percentage_of_trial_completed (line 70) | def percentage_of_trial_completed
    function sync_trial_status! (line 75) | def sync_trial_status!

FILE: app/models/family/sync_complete_event.rb
  class Family::SyncCompleteEvent (line 1) | class Family::SyncCompleteEvent
    method initialize (line 4) | def initialize(family)
    method broadcast (line 8) | def broadcast

FILE: app/models/family/syncer.rb
  class Family::Syncer (line 1) | class Family::Syncer
    method initialize (line 4) | def initialize(family)
    method perform_sync (line 8) | def perform_sync(sync)
    method perform_post_sync (line 23) | def perform_post_sync
    method child_syncables (line 28) | def child_syncables

FILE: app/models/family_export.rb
  class FamilyExport (line 1) | class FamilyExport < ApplicationRecord
    method filename (line 15) | def filename
    method downloadable? (line 19) | def downloadable?

FILE: app/models/family_merchant.rb
  class FamilyMerchant (line 1) | class FamilyMerchant < Merchant
    method set_default_color (line 12) | def set_default_color

FILE: app/models/holding.rb
  class Holding (line 1) | class Holding < ApplicationRecord
    method name (line 17) | def name
    method weight (line 21) | def weight
    method avg_cost (line 29) | def avg_cost
    method trend (line 46) | def trend
    method trades (line 50) | def trades
    method destroy_holding_and_entries! (line 54) | def destroy_holding_and_entries!
    method calculate_trend (line 64) | def calculate_trend

FILE: app/models/holding/forward_calculator.rb
  class Holding::ForwardCalculator (line 1) | class Holding::ForwardCalculator
    method initialize (line 4) | def initialize(account)
    method calculate (line 8) | def calculate
    method portfolio_cache (line 26) | def portfolio_cache
    method empty_portfolio (line 30) | def empty_portfolio
    method generate_starting_portfolio (line 35) | def generate_starting_portfolio
    method transform_portfolio (line 39) | def transform_portfolio(previous_portfolio, trade_entries, direction: ...
    method build_holdings (line 53) | def build_holdings(portfolio, date, price_source: nil)

FILE: app/models/holding/gapfillable.rb
  type Holding::Gapfillable (line 1) | module Holding::Gapfillable
    function gapfill (line 5) | def gapfill(holdings)

FILE: app/models/holding/materializer.rb
  class Holding::Materializer (line 3) | class Holding::Materializer
    method initialize (line 4) | def initialize(account, strategy:)
    method materialize_holdings (line 9) | def materialize_holdings
    method calculate_holdings (line 25) | def calculate_holdings
    method persist_holdings (line 29) | def persist_holdings
    method purge_stale_holdings (line 40) | def purge_stale_holdings
    method calculator (line 53) | def calculator

FILE: app/models/holding/portfolio_cache.rb
  class Holding::PortfolioCache (line 1) | class Holding::PortfolioCache
    class SecurityNotFound (line 4) | class SecurityNotFound < StandardError
      method initialize (line 5) | def initialize(security_id, account_id)
    method initialize (line 10) | def initialize(account, use_holdings: false)
    method get_trades (line 16) | def get_trades(date: nil)
    method get_price (line 24) | def get_price(security_id, date, source: nil)
    method get_securities (line 48) | def get_securities
    method trades (line 55) | def trades
    method holdings (line 59) | def holdings
    method collect_unique_securities (line 63) | def collect_unique_securities
    method load_prices (line 77) | def load_prices

FILE: app/models/holding/portfolio_snapshot.rb
  class Holding::PortfolioSnapshot (line 3) | class Holding::PortfolioSnapshot
    method initialize (line 6) | def initialize(account)
    method to_h (line 12) | def to_h
    method build_portfolio (line 17) | def build_portfolio

FILE: app/models/holding/reverse_calculator.rb
  class Holding::ReverseCalculator (line 1) | class Holding::ReverseCalculator
    method initialize (line 4) | def initialize(account, portfolio_snapshot:)
    method calculate (line 9) | def calculate
    method portfolio_cache (line 20) | def portfolio_cache
    method calculate_holdings (line 24) | def calculate_holdings
    method transform_portfolio (line 43) | def transform_portfolio(previous_portfolio, trade_entries, direction: ...
    method build_holdings (line 57) | def build_holdings(portfolio, date, price_source: nil)

FILE: app/models/impersonation_session.rb
  class ImpersonationSession (line 1) | class ImpersonationSession < ApplicationRecord
    method approve! (line 15) | def approve!
    method reject! (line 19) | def reject!
    method complete! (line 23) | def complete!
    method impersonator_is_super_admin (line 28) | def impersonator_is_super_admin
    method impersonated_is_not_super_admin (line 32) | def impersonated_is_not_super_admin
    method impersonator_different_from_impersonated (line 36) | def impersonator_different_from_impersonated

FILE: app/models/impersonation_session_log.rb
  class ImpersonationSessionLog (line 1) | class ImpersonationSessionLog < ApplicationRecord

FILE: app/models/import.rb
  class Import (line 1) | class Import < ApplicationRecord
    method parse_csv_str (line 45) | def parse_csv_str(csv_str, col_sep: ",")
    method publish_later (line 56) | def publish_later
    method publish (line 65) | def publish
    method revert_later (line 77) | def revert_later
    method revert (line 85) | def revert
    method csv_rows (line 98) | def csv_rows
    method csv_headers (line 102) | def csv_headers
    method csv_sample (line 106) | def csv_sample
    method dry_run (line 110) | def dry_run
    method required_column_keys (line 124) | def required_column_keys
    method column_keys (line 128) | def column_keys
    method generate_rows_from_csv (line 132) | def generate_rows_from_csv
    method sync_mappings (line 156) | def sync_mappings
    method mapping_steps (line 174) | def mapping_steps
    method uploaded? (line 178) | def uploaded?
    method configured? (line 182) | def configured?
    method cleaned? (line 186) | def cleaned?
    method publishable? (line 190) | def publishable?
    method revertable? (line 194) | def revertable?
    method has_unassigned_account? (line 198) | def has_unassigned_account?
    method requires_account? (line 202) | def requires_account?
    method suggested_template (line 207) | def suggested_template
    method apply_template! (line 215) | def apply_template!(import_template)
    method max_row_count (line 228) | def max_row_count
    method row_count_exceeded? (line 233) | def row_count_exceeded?
    method import! (line 237) | def import!
    method default_row_name (line 241) | def default_row_name
    method default_currency (line 245) | def default_currency
    method parsed_csv (line 249) | def parsed_csv
    method sanitize_number (line 253) | def sanitize_number(value)
    method set_default_number_format (line 287) | def set_default_number_format

FILE: app/models/import/account_mapping.rb
  class Import::AccountMapping (line 1) | class Import::AccountMapping < Import::Mapping
    method mappables_by_key (line 5) | def mappables_by_key(import)
    method selectable_values (line 13) | def selectable_values
    method requires_selection? (line 23) | def requires_selection?
    method values_count (line 27) | def values_count
    method mappable_class (line 31) | def mappable_class
    method create_mappable! (line 35) | def create_mappable!
    method requires_mapping? (line 50) | def requires_mapping?

FILE: app/models/import/account_type_mapping.rb
  class Import::AccountTypeMapping (line 1) | class Import::AccountTypeMapping < Import::Mapping
    method mappables_by_key (line 5) | def mappables_by_key(import)
    method selectable_values (line 10) | def selectable_values
    method requires_selection? (line 14) | def requires_selection?
    method values_count (line 18) | def values_count
    method create_mappable! (line 22) | def create_mappable!

FILE: app/models/import/category_mapping.rb
  class Import::CategoryMapping (line 1) | class Import::CategoryMapping < Import::Mapping
    method mappables_by_key (line 3) | def mappables_by_key(import)
    method selectable_values (line 11) | def selectable_values
    method requires_selection? (line 21) | def requires_selection?
    method values_count (line 25) | def values_count
    method mappable_class (line 29) | def mappable_class
    method create_mappable! (line 33) | def create_mappable!

FILE: app/models/import/mapping.rb
  class Import::Mapping (line 1) | class Import::Mapping < ApplicationRecord
    method mappable_for (line 17) | def mappable_for(key)
    method mappables_by_key (line 21) | def mappables_by_key(import)
    method selectable_values (line 26) | def selectable_values
    method values_count (line 30) | def values_count
    method mappable_class (line 34) | def mappable_class
    method creatable? (line 38) | def creatable?
    method create_mappable! (line 42) | def create_mappable!

FILE: app/models/import/row.rb
  class Import::Row (line 1) | class Import::Row < ApplicationRecord
    method tags_list (line 13) | def tags_list
    method date_iso (line 21) | def date_iso
    method signed_amount (line 25) | def signed_amount
    method update_and_sync (line 33) | def update_and_sync(params)
    method apply_trade_signage_convention (line 41) | def apply_trade_signage_convention(value)
    method apply_transaction_signage_convention (line 46) | def apply_transaction_signage_convention(value)
    method required_columns (line 62) | def required_columns
    method date_valid (line 68) | def date_valid
    method currency_is_valid (line 86) | def currency_is_valid

FILE: app/models/import/tag_mapping.rb
  class Import::TagMapping (line 1) | class Import::TagMapping < Import::Mapping
    method mappables_by_key (line 3) | def mappables_by_key(import)
    method selectable_values (line 12) | def selectable_values
    method requires_selection? (line 22) | def requires_selection?
    method values_count (line 26) | def values_count
    method mappable_class (line 30) | def mappable_class
    method create_mappable! (line 34) | def create_mappable!

FILE: app/models/income_statement.rb
  class IncomeStatement (line 1) | class IncomeStatement
    method initialize (line 8) | def initialize(family)
    method totals (line 12) | def totals(transactions_scope: nil)
    method expense_totals (line 27) | def expense_totals(period: Period.current_month)
    method income_totals (line 31) | def income_totals(period: Period.current_month)
    method median_expense (line 35) | def median_expense(interval: "month", category: nil)
    method avg_expense (line 43) | def avg_expense(interval: "month", category: nil)
    method median_income (line 51) | def median_income(interval: "month")
    method categories (line 60) | def categories
    method build_period_total (line 64) | def build_period_total(classification:, period:)
    method family_stats (line 101) | def family_stats(interval: "month")
    method category_stats (line 108) | def category_stats(interval: "month")
    method totals_query (line 115) | def totals_query(transactions_scope:)
    method monetizable_currency (line 123) | def monetizable_currency

FILE: app/models/income_statement/category_stats.rb
  class IncomeStatement::CategoryStats (line 1) | class IncomeStatement::CategoryStats
    method initialize (line 2) | def initialize(family, interval: "month")
    method call (line 7) | def call
    method sanitized_query_sql (line 21) | def sanitized_query_sql
    method query_sql (line 32) | def query_sql

FILE: app/models/income_statement/family_stats.rb
  class IncomeStatement::FamilyStats (line 1) | class IncomeStatement::FamilyStats
    method initialize (line 2) | def initialize(family, interval: "month")
    method call (line 7) | def call
    method sanitized_query_sql (line 20) | def sanitized_query_sql
    method query_sql (line 31) | def query_sql

FILE: app/models/income_statement/totals.rb
  class IncomeStatement::Totals (line 1) | class IncomeStatement::Totals
    method initialize (line 2) | def initialize(family, transactions_scope:)
    method call (line 7) | def call
    method query_sql (line 22) | def query_sql
    method optimized_query_sql (line 31) | def optimized_query_sql
    method sql_params (line 53) | def sql_params

FILE: app/models/investment.rb
  class Investment (line 1) | class Investment < ApplicationRecord
    method color (line 19) | def color
    method classification (line 23) | def classification
    method icon (line 27) | def icon

FILE: app/models/invitation.rb
  class Invitation (line 1) | class Invitation < ApplicationRecord
    method pending? (line 17) | def pending?
    method generate_token (line 23) | def generate_token
    method set_expiration (line 30) | def set_expiration
    method inviter_is_admin (line 34) | def inviter_is_admin

FILE: app/models/invite_code.rb
  class InviteCode (line 1) | class InviteCode < ApplicationRecord
    method claim! (line 5) | def claim!(token)
    method generate! (line 12) | def generate!
    method generate_token (line 19) | def generate_token

FILE: app/models/loan.rb
  class Loan (line 1) | class Loan < ApplicationRecord
    method monthly_payment (line 11) | def monthly_payment
    method original_balance (line 27) | def original_balance
    method color (line 32) | def color
    method icon (line 36) | def icon
    method classification (line 40) | def classification

FILE: app/models/market_data_importer.rb
  class MarketDataImporter (line 1) | class MarketDataImporter
    method initialize (line 8) | def initialize(mode: :full, clear_cache: false)
    method import_all (line 13) | def import_all
    method import_security_prices (line 19) | def import_security_prices
    method import_exchange_rates (line 37) | def import_exchange_rates
    method snapshot? (line 60) | def snapshot?
    method required_exchange_rate_pairs (line 68) | def required_exchange_rate_pairs
    method get_first_required_price_date (line 102) | def get_first_required_price_date(security)
    method get_first_required_exchange_rate_date (line 109) | def get_first_required_exchange_rate_date(from_currency:)
    method default_start_date (line 115) | def default_start_date
    method end_date (line 120) | def end_date
    method set_mode! (line 124) | def set_mode!(mode)

FILE: app/models/measurement.rb
  class Measurement (line 1) | class Measurement
    method initialize (line 11) | def initialize(value, unit)
    method to_s (line 17) | def to_s

FILE: app/models/merchant.rb
  class Merchant (line 1) | class Merchant < ApplicationRecord

FILE: app/models/message.rb
  class Message (line 1) | class Message < ApplicationRecord
    method broadcast? (line 19) | def broadcast?

FILE: app/models/mint_import.rb
  class MintImport (line 1) | class MintImport < Import
    method generate_rows_from_csv (line 4) | def generate_rows_from_csv
    method import! (line 23) | def import!
    method mapping_steps (line 46) | def mapping_steps
    method required_column_keys (line 50) | def required_column_keys
    method column_keys (line 54) | def column_keys
    method csv_template (line 58) | def csv_template
    method signed_csv_amount (line 68) | def signed_csv_amount(csv_row)
    method set_mappings (line 80) | def set_mappings

FILE: app/models/mobile_device.rb
  class MobileDevice (line 1) | class MobileDevice < ApplicationRecord
    method active? (line 13) | def active?
    method update_last_seen! (line 17) | def update_last_seen!
    method create_oauth_application! (line 21) | def create_oauth_application!
    method active_tokens (line 36) | def active_tokens
    method revoke_all_tokens! (line 46) | def revoke_all_tokens!
    method set_last_seen_at (line 52) | def set_last_seen_at

FILE: app/models/other_asset.rb
  class OtherAsset (line 1) | class OtherAsset < ApplicationRecord
    method color (line 5) | def color
    method icon (line 9) | def icon
    method classification (line 13) | def classification

FILE: app/models/other_liability.rb
  class OtherLiability (line 1) | class OtherLiability < ApplicationRecord
    method color (line 5) | def color
    method icon (line 9) | def icon
    method classification (line 13) | def classification

FILE: app/models/period.rb
  class Period (line 1) | class Period
    class InvalidKeyError (line 4) | class InvalidKeyError < StandardError; end
    method from_key (line 70) | def from_key(key)
    method custom (line 80) | def custom(start_date:, end_date:)
    method all (line 84) | def all
    method as_options (line 88) | def as_options
    method initialize (line 99) | def initialize(start_date: nil, end_date: nil, key: nil, date_format: ...
    method <=> (line 107) | def <=>(other)
    method date_range (line 111) | def date_range
    method days (line 115) | def days
    method within? (line 119) | def within?(other)
    method interval (line 123) | def interval
    method label (line 131) | def label
    method label_short (line 139) | def label_short
    method comparison_label (line 147) | def comparison_label
    method key_metadata (line 156) | def key_metadata
    method must_be_valid_date_range (line 160) | def must_be_valid_date_range

FILE: app/models/plaid_account.rb
  class PlaidAccount (line 1) | class PlaidAccount < ApplicationRecord
    method upsert_plaid_snapshot! (line 9) | def upsert_plaid_snapshot!(account_snapshot)
    method upsert_plaid_transactions_snapshot! (line 24) | def upsert_plaid_transactions_snapshot!(transactions_snapshot)
    method upsert_plaid_investments_snapshot! (line 32) | def upsert_plaid_investments_snapshot!(investments_snapshot)
    method upsert_plaid_liabilities_snapshot! (line 40) | def upsert_plaid_liabilities_snapshot!(liabilities_snapshot)
    method has_balance (line 50) | def has_balance

FILE: app/models/plaid_account/importer.rb
  class PlaidAccount::Importer (line 1) | class PlaidAccount::Importer
    method initialize (line 2) | def initialize(plaid_account, account_snapshot:)
    method import (line 7) | def import
    method import_account_info (line 17) | def import_account_info
    method import_transactions (line 21) | def import_transactions
    method import_investments (line 25) | def import_investments
    method import_liabilities (line 29) | def import_liabilities

FILE: app/models/plaid_account/investments/balance_calculator.rb
  class PlaidAccount::Investments::BalanceCalculator (line 3) | class PlaidAccount::Investments::BalanceCalculator
    method initialize (line 7) | def initialize(plaid_account, security_resolver:)
    method balance (line 12) | def balance
    method cash_balance (line 30) | def cash_balance
    method holdings (line 46) | def holdings
    method calculate_investment_brokerage_cash (line 50) | def calculate_investment_brokerage_cash
    method total_investment_account_value (line 57) | def total_investment_account_value
    method true_holdings_value (line 62) | def true_holdings_value

FILE: app/models/plaid_account/investments/holdings_processor.rb
  class PlaidAccount::Investments::HoldingsProcessor (line 1) | class PlaidAccount::Investments::HoldingsProcessor
    method initialize (line 2) | def initialize(plaid_account, security_resolver:)
    method process (line 7) | def process
    method account (line 43) | def account
    method holdings (line 47) | def holdings

FILE: app/models/plaid_account/investments/security_resolver.rb
  class PlaidAccount::Investments::SecurityResolver (line 2) | class PlaidAccount::Investments::SecurityResolver
    method initialize (line 5) | def initialize(plaid_account)
    method resolve (line 11) | def resolve(plaid_security_id:)
    method securities (line 45) | def securities
    method get_plaid_security (line 50) | def get_plaid_security(plaid_security_id)
    method report_unresolvable_security (line 58) | def report_unresolvable_security(plaid_security_id)
    method known_plaid_brokerage_cash_tickers (line 80) | def known_plaid_brokerage_cash_tickers
    method brokerage_cash? (line 84) | def brokerage_cash?(plaid_security)
    method cash_equivalent? (line 89) | def cash_equivalent?(plaid_security)

FILE: app/models/plaid_account/investments/transactions_processor.rb
  class PlaidAccount::Investments::TransactionsProcessor (line 1) | class PlaidAccount::Investments::TransactionsProcessor
    method initialize (line 4) | def initialize(plaid_account, security_resolver:)
    method process (line 9) | def process
    method account (line 22) | def account
    method cash_transaction? (line 26) | def cash_transaction?(transaction)
    method find_or_create_trade_entry (line 30) | def find_or_create_trade_entry(transaction)
    method find_or_create_cash_entry (line 67) | def find_or_create_cash_entry(transaction)
    method transactions (line 87) | def transactions
    method derived_qty (line 95) | def derived_qty(transaction)

FILE: app/models/plaid_account/liabilities/credit_processor.rb
  class PlaidAccount::Liabilities::CreditProcessor (line 1) | class PlaidAccount::Liabilities::CreditProcessor
    method initialize (line 2) | def initialize(plaid_account)
    method process (line 6) | def process
    method account (line 18) | def account
    method credit_data (line 22) | def credit_data

FILE: app/models/plaid_account/liabilities/mortgage_processor.rb
  class PlaidAccount::Liabilities::MortgageProcessor (line 1) | class PlaidAccount::Liabilities::MortgageProcessor
    method initialize (line 2) | def initialize(plaid_account)
    method process (line 6) | def process
    method account (line 18) | def account
    method mortgage_data (line 22) | def mortgage_data

FILE: app/models/plaid_account/liabilities/student_loan_processor.rb
  class PlaidAccount::Liabilities::StudentLoanProcessor (line 1) | class PlaidAccount::Liabilities::StudentLoanProcessor
    method initialize (line 2) | def initialize(plaid_account)
    method process (line 6) | def process
    method account (line 20) | def account
    method term_months (line 24) | def term_months
    method origination_date (line 30) | def origination_date
    method expected_payoff_date (line 34) | def expected_payoff_date
    method parse_date (line 38) | def parse_date(value)
    method student_loan_data (line 47) | def student_loan_data

FILE: app/models/plaid_account/processor.rb
  class PlaidAccount::Processor (line 1) | class PlaidAccount::Processor
    method initialize (line 6) | def initialize(plaid_account)
    method process (line 14) | def process
    method family (line 22) | def family
    method security_resolver (line 27) | def security_resolver
    method process_account! (line 31) | def process_account!
    method process_transactions (line 64) | def process_transactions
    method process_investments (line 70) | def process_investments
    method process_liabilities (line 77) | def process_liabilities
    method balance_calculator (line 90) | def balance_calculator
    method report_exception (line 104) | def report_exception(error)

FILE: app/models/plaid_account/transactions/category_matcher.rb
  class PlaidAccount::Transactions::CategoryMatcher (line 13) | class PlaidAccount::Transactions::CategoryMatcher
    method initialize (line 16) | def initialize(user_categories = [])
    method match (line 20) | def match(plaid_detailed_category)
    method get_plaid_category_details (line 78) | def get_plaid_category_details(plaid_category_name)
    method detailed_plaid_categories (line 82) | def detailed_plaid_categories
    method normalized_user_categories (line 96) | def normalized_user_categories
    method normalize_user_category_name (line 106) | def normalize_user_category_name(name)

FILE: app/models/plaid_account/transactions/category_taxonomy.rb
  type PlaidAccount::Transactions::CategoryTaxonomy (line 2) | module PlaidAccount::Transactions::CategoryTaxonomy

FILE: app/models/plaid_account/transactions/processor.rb
  class PlaidAccount::Transactions::Processor (line 1) | class PlaidAccount::Transactions::Processor
    method initialize (line 2) | def initialize(plaid_account)
    method process (line 6) | def process
    method category_matcher (line 27) | def category_matcher
    method family_categories (line 31) | def family_categories
    method account (line 41) | def account
    method remove_plaid_transaction (line 45) | def remove_plaid_transaction(raw_transaction)
    method modified_transactions (line 50) | def modified_transactions
    method removed_transactions (line 57) | def removed_transactions

FILE: app/models/plaid_account/type_mappable.rb
  type PlaidAccount::TypeMappable (line 1) | module PlaidAccount::TypeMappable
    function map_accountable (line 6) | def map_accountable(plaid_type)
    function map_subtype (line 19) | def map_subtype(plaid_type, plaid_subtype)

FILE: app/models/plaid_entry/processor.rb
  class PlaidEntry::Processor (line 1) | class PlaidEntry::Processor
    method initialize (line 3) | def initialize(plaid_transaction, plaid_account:, category_matcher:)
    method process (line 9) | def process
    method account (line 52) | def account
    method plaid_id (line 56) | def plaid_id
    method name (line 60) | def name
    method amount (line 64) | def amount
    method currency (line 68) | def currency
    method date (line 72) | def date
    method detailed_category (line 76) | def detailed_category
    method merchant (line 80) | def merchant

FILE: app/models/plaid_item.rb
  class PlaidItem (line 1) | class PlaidItem < ApplicationRecord
    method get_update_link_token (line 25) | def get_update_link_token(webhooks_url:, redirect_url:)
    method destroy_later (line 44) | def destroy_later
    method import_latest_plaid_data (line 49) | def import_latest_plaid_data
    method process_accounts (line 56) | def process_accounts
    method schedule_account_syncs (line 63) | def schedule_account_syncs(parent_sync: nil, window_start_date: nil, w...
    method upsert_plaid_snapshot! (line 74) | def upsert_plaid_snapshot!(item_snapshot)
    method upsert_plaid_institution_snapshot! (line 85) | def upsert_plaid_institution_snapshot!(institution_snapshot)
    method supports_product? (line 96) | def supports_product?(product)
    method remove_plaid_item (line 101) | def remove_plaid_item
    method supported_products (line 117) | def supported_products

FILE: app/models/plaid_item/accounts_snapshot.rb
  class PlaidItem::AccountsSnapshot (line 4) | class PlaidItem::AccountsSnapshot
    method initialize (line 5) | def initialize(plaid_item, plaid_provider:)
    method accounts (line 10) | def accounts
    method get_account_data (line 14) | def get_account_data(account_id)
    method transactions_cursor (line 23) | def transactions_cursor
    method account_scoped_transactions_data (line 36) | def account_scoped_transactions_data(account_id)
    method account_scoped_investments_data (line 46) | def account_scoped_investments_data(account_id)
    method account_scoped_liabilities_data (line 60) | def account_scoped_liabilities_data(account_id)
    method can_fetch_transactions? (line 70) | def can_fetch_transactions?
    method transactions_data (line 74) | def transactions_data
    method can_fetch_investments? (line 83) | def can_fetch_investments?
    method investments_data (line 88) | def investments_data
    method can_fetch_liabilities? (line 93) | def can_fetch_liabilities?
    method liabilities_data (line 101) | def liabilities_data

FILE: app/models/plaid_item/importer.rb
  class PlaidItem::Importer (line 1) | class PlaidItem::Importer
    method initialize (line 2) | def initialize(plaid_item, plaid_provider:)
    method import (line 7) | def import
    method handle_plaid_error (line 19) | def handle_plaid_error(error)
    method fetch_and_import_item_data (line 30) | def fetch_and_import_item_data
    method fetch_and_import_accounts_data (line 38) | def fetch_and_import_accounts_data

FILE: app/models/plaid_item/provided.rb
  type PlaidItem::Provided (line 1) | module PlaidItem::Provided
    function plaid_provider (line 4) | def plaid_provider

FILE: app/models/plaid_item/sync_complete_event.rb
  class PlaidItem::SyncCompleteEvent (line 1) | class PlaidItem::SyncCompleteEvent
    method initialize (line 4) | def initialize(plaid_item)
    method broadcast (line 8) | def broadcast

FILE: app/models/plaid_item/syncer.rb
  class PlaidItem::Syncer (line 1) | class PlaidItem::Syncer
    method initialize (line 4) | def initialize(plaid_item)
    method perform_sync (line 8) | def perform_sync(sync)
    method perform_post_sync (line 23) | def perform_post_sync

FILE: app/models/plaid_item/webhook_processor.rb
  class PlaidItem::WebhookProcessor (line 1) | class PlaidItem::WebhookProcessor
    method initialize (line 4) | def initialize(webhook_body)
    method process (line 12) | def process
    method plaid_item (line 40) | def plaid_item
    method handle_missing_item (line 44) | def handle_missing_item

FILE: app/models/property.rb
  class Property (line 1) | class Property < ApplicationRecord
    method icon (line 20) | def icon
    method color (line 24) | def color
    method classification (line 28) | def classification
    method area (line 33) | def area
    method purchase_price (line 37) | def purchase_price
    method trend (line 41) | def trend
    method balance_display_name (line 45) | def balance_display_name
    method opening_balance_display_name (line 49) | def opening_balance_display_name
    method first_valuation_amount (line 54) | def first_valuation_amount

FILE: app/models/provider.rb
  class Provider (line 1) | class Provider
    class Error (line 4) | class Error < StandardError
      method initialize (line 7) | def initialize(message, details: nil)
      method as_json (line 12) | def as_json
    method with_provider_response (line 24) | def with_provider_response(error_transformer: nil, &block)
    method default_error_transformer (line 47) | def default_error_transformer(error)

FILE: app/models/provider/exchange_rate_concept.rb
  type Provider::ExchangeRateConcept (line 1) | module Provider::ExchangeRateConcept
    function fetch_exchange_rate (line 6) | def fetch_exchange_rate(from:, to:, date:)
    function fetch_exchange_rates (line 10) | def fetch_exchange_rates(from:, to:, start_date:, end_date:)

FILE: app/models/provider/github.rb
  class Provider::Github (line 1) | class Provider::Github
    method initialize (line 4) | def initialize
    method fetch_latest_release_notes (line 10) | def fetch_latest_release_notes
    method repo (line 34) | def repo

FILE: app/models/provider/llm_concept.rb
  type Provider::LlmConcept (line 1) | module Provider::LlmConcept
    function auto_categorize (line 6) | def auto_categorize(transactions)
    function auto_detect_merchants (line 12) | def auto_detect_merchants(transactions)
    function chat_response (line 21) | def chat_response(prompt, model:, instructions: nil, functions: [], fu...

FILE: app/models/provider/openai.rb
  class Provider::Openai (line 1) | class Provider::Openai < Provider
    method initialize (line 9) | def initialize(access_token)
    method supports_model? (line 13) | def supports_model?(model)
    method auto_categorize (line 17) | def auto_categorize(transactions: [], user_categories: [])
    method auto_detect_merchants (line 29) | def auto_detect_merchants(transactions: [], user_merchants: [])
    method chat_response (line 41) | def chat_response(prompt, model:, instructions: nil, functions: [], fu...

FILE: app/models/provider/openai/auto_categorizer.rb
  class Provider::Openai::AutoCategorizer (line 1) | class Provider::Openai::AutoCategorizer
    method initialize (line 2) | def initialize(client, transactions: [], user_categories: [])
    method auto_categorize (line 8) | def auto_categorize
    method build_response (line 33) | def build_response(categorizations)
    method normalize_category_name (line 42) | def normalize_category_name(category_name)
    method extract_categorizations (line 48) | def extract_categorizations(response)
    method json_schema (line 53) | def json_schema
    method developer_message (line 84) | def developer_message
    method instructions (line 100) | def instructions

FILE: app/models/provider/openai/auto_merchant_detector.rb
  class Provider::Openai::AutoMerchantDetector (line 1) | class Provider::Openai::AutoMerchantDetector
    method initialize (line 2) | def initialize(client, transactions:, user_merchants:)
    method auto_detect_merchants (line 8) | def auto_detect_merchants
    method build_response (line 33) | def build_response(categorizations)
    method normalize_ai_value (line 43) | def normalize_ai_value(ai_value)
    method extract_categorizations (line 49) | def extract_categorizations(response)
    method json_schema (line 54) | def json_schema
    method developer_message (line 88) | def developer_message
    method instructions (line 106) | def instructions

FILE: app/models/provider/openai/chat_config.rb
  class Provider::Openai::ChatConfig (line 1) | class Provider::Openai::ChatConfig
    method initialize (line 2) | def initialize(functions: [], function_results: [])
    method tools (line 7) | def tools
    method build_input (line 19) | def build_input(prompt)

FILE: app/models/provider/openai/chat_parser.rb
  class Provider::Openai::ChatParser (line 1) | class Provider::Openai::ChatParser
    method initialize (line 4) | def initialize(object)
    method parsed (line 8) | def parsed
    method response_id (line 24) | def response_id
    method response_model (line 28) | def response_model
    method messages (line 32) | def messages
    method function_requests (line 47) | def function_requests

FILE: app/models/provider/openai/chat_stream_parser.rb
  class Provider::Openai::ChatStreamParser (line 1) | class Provider::Openai::ChatStreamParser
    method initialize (line 4) | def initialize(object)
    method parsed (line 8) | def parsed
    method parse_response (line 25) | def parse_response(response)

FILE: app/models/provider/plaid.rb
  class Provider::Plaid (line 1) | class Provider::Plaid
    method initialize (line 7) | def initialize(config, region: :us)
    method validate_webhook! (line 14) | def validate_webhook!(verification_header, raw_body)
    method get_link_token (line 45) | def get_link_token(user_id:, webhooks_url:, redirect_url:, accountable...
    method exchange_public_token (line 68) | def exchange_public_token(token)
    method get_item (line 76) | def get_item(access_token)
    method remove_item (line 81) | def remove_item(access_token)
    method get_item_accounts (line 86) | def get_item_accounts(access_token)
    method get_transactions (line 91) | def get_transactions(access_token, next_cursor: nil)
    method get_item_investments (line 119) | def get_item_investments(access_token, start_date: nil, end_date: Date...
    method get_item_liabilities (line 129) | def get_item_liabilities(access_token)
    method get_institution (line 135) | def get_institution(institution_id)
    method get_item_holdings (line 150) | def get_item_holdings(access_token:)
    method get_item_investment_transactions (line 157) | def get_item_investment_transactions(access_token:, start_date:, end_d...
    method get_primary_product (line 182) | def get_primary_product(accountable_type)
    method get_additional_consented_products (line 195) | def get_additional_consented_products(accountable_type)
    method eu? (line 201) | def eu?
    method country_codes (line 205) | def country_codes

FILE: app/models/provider/plaid_sandbox.rb
  class Provider::PlaidSandbox (line 1) | class Provider::PlaidSandbox < Provider::Plaid
    method initialize (line 4) | def initialize
    method create_public_token (line 9) | def create_public_token(username: nil)
    method fire_webhook (line 21) | def fire_webhook(item, type: "TRANSACTIONS", code: "SYNC_UPDATES_AVAIL...
    method reset_login (line 31) | def reset_login(item)
    method create_client (line 40) | def create_client

FILE: app/models/provider/registry.rb
  class Provider::Registry (line 1) | class Provider::Registry
    method for_concept (line 11) | def for_concept(concept)
    method get_provider (line 15) | def get_provider(name)
    method plaid_provider_for_region (line 21) | def plaid_provider_for_region(region)
    method stripe (line 26) | def stripe
    method synth (line 35) | def synth
    method plaid_us (line 43) | def plaid_us
    method plaid_eu (line 51) | def plaid_eu
    method github (line 59) | def github
    method openai (line 63) | def openai
    method initialize (line 72) | def initialize(concept)
    method providers (line 77) | def providers
    method get_provider (line 81) | def get_provider(name)
    method available_providers (line 92) | def available_providers

FILE: app/models/provider/security_concept.rb
  type Provider::SecurityConcept (line 1) | module Provider::SecurityConcept
    function search_securities (line 8) | def search_securities(symbol, country_code: nil, exchange_operating_mi...
    function fetch_security_info (line 12) | def fetch_security_info(symbol:, exchange_operating_mic:)
    function fetch_security_price (line 16) | def fetch_security_price(symbol:, exchange_operating_mic:, date:)
    function fetch_security_prices (line 20) | def fetch_security_prices(symbol:, exchange_operating_mic:, start_date...

FILE: app/models/provider/stripe.rb
  class Provider::Stripe (line 1) | class Provider::Stripe
    method initialize (line 4) | def initialize(secret_key:, webhook_secret:)
    method process_event (line 9) | def process_event(event_id)
    method process_webhook_later (line 20) | def process_webhook_later(webhook_body, sig_header)
    method create_checkout_session (line 25) | def create_checkout_session(plan:, family_id:, family_email:, success_...
    method get_checkout_result (line 45) | def get_checkout_result(session_id)
    method create_billing_portal_session_url (line 59) | def create_billing_portal_session_url(customer_id:, return_url:)
    method update_customer_metadata (line 66) | def update_customer_metadata(customer_id:, metadata:)
    method price_id_for (line 76) | def price_id_for(plan)
    method retrieve_event (line 85) | def retrieve_event(event_id)

FILE: app/models/provider/stripe/event_processor.rb
  class Provider::Stripe::EventProcessor (line 1) | class Provider::Stripe::EventProcessor
    method initialize (line 2) | def initialize(event)
    method process (line 6) | def process
    method event_data (line 13) | def event_data

FILE: app/models/provider/stripe/subscription_event_processor.rb
  class Provider::Stripe::SubscriptionEventProcessor (line 1) | class Provider::Stripe::SubscriptionEventProcessor < Provider::Stripe::E...
    method process (line 4) | def process
    method family (line 18) | def family
    method subscription_details (line 22) | def subscription_details
    method subscription (line 26) | def subscription

FILE: app/models/provider/synth.rb
  class Provider::Synth (line 1) | class Provider::Synth < Provider
    method initialize (line 9) | def initialize(api_key)
    method healthy? (line 13) | def healthy?
    method usage (line 20) | def usage
    method fetch_exchange_rate (line 43) | def fetch_exchange_rate(from:, to:, date:)
    method fetch_exchange_rates (line 57) | def fetch_exchange_rates(from:, to:, start_date:, end_date:)
    method search_securities (line 91) | def search_securities(symbol, country_code: nil, exchange_operating_mi...
    method fetch_security_info (line 116) | def fetch_security_info(symbol:, exchange_operating_mic:)
    method fetch_security_price (line 136) | def fetch_security_price(symbol:, exchange_operating_mic: nil, date:)
    method fetch_security_prices (line 146) | def fetch_security_prices(symbol:, exchange_operating_mic: nil, start_...
    method base_url (line 191) | def base_url
    method app_name (line 195) | def app_name
    method app_type (line 199) | def app_type
    method client (line 203) | def client
    method fetch_page (line 219) | def fetch_page(url, page, params = {})
    method paginate (line 223) | def paginate(url, params = {})

FILE: app/models/provider_merchant.rb
  class ProviderMerchant (line 1) | class ProviderMerchant < Merchant

FILE: app/models/rejected_transfer.rb
  class RejectedTransfer (line 1) | class RejectedTransfer < ApplicationRecord

FILE: app/models/rule.rb
  class Rule (line 1) | class Rule < ApplicationRecord
    method action_executors (line 21) | def action_executors
    method condition_filters (line 25) | def condition_filters
    method registry (line 29) | def registry
    method affected_resource_count (line 38) | def affected_resource_count
    method apply (line 42) | def apply(ignore_attribute_locks: false)
    method apply_later (line 48) | def apply_later(ignore_attribute_locks: false)
    method primary_condition_title (line 52) | def primary_condition_title
    method matching_resources_scope (line 65) | def matching_resources_scope
    method min_actions (line 81) | def min_actions
    method no_duplicate_actions (line 87) | def no_duplicate_actions
    method no_nested_compound_conditions (line 94) | def no_nested_compound_conditions
    method normalize_name (line 106) | def normalize_name

FILE: app/models/rule/action.rb
  class Rule::Action (line 1) | class Rule::Action < ApplicationRecord
    method apply (line 6) | def apply(resource_scope, ignore_attribute_locks: false)
    method options (line 10) | def options
    method value_display (line 14) | def value_display
    method executor (line 26) | def executor

FILE: app/models/rule/action_executor.rb
  class Rule::ActionExecutor (line 1) | class Rule::ActionExecutor
    method initialize (line 4) | def initialize(rule)
    method key (line 8) | def key
    method label (line 12) | def label
    method type (line 16) | def type
    method options (line 20) | def options
    method execute (line 24) | def execute(scope, value: nil, ignore_attribute_locks: false)
    method as_json (line 28) | def as_json
    method family (line 40) | def family

FILE: app/models/rule/action_executor/auto_categorize.rb
  class Rule::ActionExecutor::AutoCategorize (line 1) | class Rule::ActionExecutor::AutoCategorize < Rule::ActionExecutor
    method label (line 2) | def label
    method execute (line 10) | def execute(transaction_scope, value: nil, ignore_attribute_locks: false)

FILE: app/models/rule/action_executor/auto_detect_merchants.rb
  class Rule::ActionExecutor::AutoDetectMerchants (line 1) | class Rule::ActionExecutor::AutoDetectMerchants < Rule::ActionExecutor
    method label (line 2) | def label
    method execute (line 10) | def execute(transaction_scope, value: nil, ignore_attribute_locks: false)

FILE: app/models/rule/action_executor/set_transaction_category.rb
  class Rule::ActionExecutor::SetTransactionCategory (line 1) | class Rule::ActionExecutor::SetTransactionCategory < Rule::ActionExecutor
    method type (line 2) | def type
    method options (line 6) | def options
    method execute (line 10) | def execute(transaction_scope, value: nil, ignore_attribute_locks: false)

FILE: app/models/rule/action_executor/set_transaction_merchant.rb
  class Rule::ActionExecutor::SetTransactionMerchant (line 1) | class Rule::ActionExecutor::SetTransactionMerchant < Rule::ActionExecutor
    method type (line 2) | def type
    method options (line 6) | def options
    method execute (line 10) | def execute(transaction_scope, value: nil, ignore_attribute_locks: false)

FILE: app/models/rule/action_executor/set_transaction_name.rb
  class Rule::ActionExecutor::SetTransactionName (line 1) | class Rule::ActionExecutor::SetTransactionName < Rule::ActionExecutor
    method type (line 2) | def type
    method options (line 6) | def options
    method execute (line 10) | def execute(transaction_scope, value: nil, ignore_attribute_locks: false)

FILE: app/models/rule/action_executor/set_transaction_tags.rb
  class Rule::ActionExecutor::SetTransactionTags (line 1) | class Rule::ActionExecutor::SetTransactionTags < Rule::ActionExecutor
    method type (line 2) | def type
    method options (line 6) | def options
    method execute (line 10) | def execute(transaction_scope, value: nil, ignore_attribute_locks: false)

FILE: app/models/rule/condition.rb
  class Rule::Condition (line 1) | class Rule::Condition < ApplicationRecord
    method rule (line 14) | def rule
    method compound? (line 18) | def compound?
    method apply (line 22) | def apply(scope)
    method prepare (line 30) | def prepare(scope)
    method value_display (line 38) | def value_display
    method options (line 50) | def options
    method operators (line 54) | def operators
    method filter (line 58) | def filter
    method build_compound_scope (line 63) | def build_compound_scope(scope)

FILE: app/models/rule/condition_filter.rb
  class Rule::ConditionFilter (line 1) | class Rule::ConditionFilter
    method initialize (line 12) | def initialize(rule)
    method type (line 16) | def type
    method number_step (line 20) | def number_step
    method key (line 25) | def key
    method label (line 29) | def label
    method options (line 33) | def options
    method operators (line 37) | def operators
    method prepare (line 42) | def prepare(scope)
    method apply (line 47) | def apply(scope, operator, value)
    method as_json (line 51) | def as_json
    method family (line 65) | def family
    method build_sanitized_where_condition (line 69) | def build_sanitized_where_condition(field, operator, value)
    method sanitize_operator (line 78) | def sanitize_operator(operator)

FILE: app/models/rule/condition_filter/transaction_amount.rb
  class Rule::ConditionFilter::TransactionAmount (line 1) | class Rule::ConditionFilter::TransactionAmount < Rule::ConditionFilter
    method type (line 2) | def type
    method prepare (line 6) | def prepare(scope)
    method apply (line 10) | def apply(scope, operator, value)

FILE: app/models/rule/condition_filter/transaction_merchant.rb
  class Rule::ConditionFilter::TransactionMerchant (line 1) | class Rule::ConditionFilter::TransactionMerchant < Rule::ConditionFilter
    method type (line 2) | def type
    method options (line 6) | def options
    method prepare (line 10) | def prepare(scope)
    method apply (line 14) | def apply(scope, operator, value)

FILE: app/models/rule/condition_filter/transaction_name.rb
  class Rule::ConditionFilter::TransactionName (line 1) | class Rule::ConditionFilter::TransactionName < Rule::ConditionFilter
    method prepare (line 2) | def prepare(scope)
    method apply (line 6) | def apply(scope, operator, value)

FILE: app/models/rule/registry.rb
  class Rule::Registry (line 1) | class Rule::Registry
    method initialize (line 5) | def initialize(rule)
    method resource_scope (line 9) | def resource_scope
    method condition_filters (line 13) | def condition_filters
    method action_executors (line 17) | def action_executors
    method get_filter! (line 21) | def get_filter!(key)
    method get_executor! (line 27) | def get_executor!(key)
    method as_json (line 33) | def as_json
    method family (line 43) | def family

FILE: app/models/rule/registry/transaction_resource.rb
  class Rule::Registry::TransactionResource (line 1) | class Rule::Registry::TransactionResource < Rule::Registry
    method resource_scope (line 2) | def resource_scope
    method condition_filters (line 6) | def condition_filters
    method action_executors (line 14) | def action_executors
    method ai_enabled? (line 31) | def ai_enabled?

FILE: app/models/security.rb
  class Security (line 1) | class Security < ApplicationRecord
    method current_price (line 14) | def current_price
    method to_combobox_option (line 20) | def to_combobox_option
    method upcase_symbols (line 31) | def upcase_symbols

FILE: app/models/security/health_checker.rb
  class Security::HealthChecker (line 12) | class Security::HealthChecker
    method check_all (line 18) | def check_all
    method never_checked_scope (line 32) | def never_checked_scope
    method due_for_check_scope (line 39) | def due_for_check_scope
    method initialize (line 45) | def initialize(security)
    method run_check (line 49) | def run_check
    method provider (line 68) | def provider
    method latest_provider_price (line 72) | def latest_provider_price
    method handle_success (line 87) | def handle_success
    method handle_failure (line 95) | def handle_failure
    method convert_to_offline_security! (line 110) | def convert_to_offline_security!

FILE: app/models/security/price.rb
  class Security::Price (line 1) | class Security::Price < ApplicationRecord

FILE: app/models/security/price/importer.rb
  class Security::Price::Importer (line 1) | class Security::Price::Importer
    method initialize (line 5) | def initialize(security:, security_provider:, start_date:, end_date:, ...
    method import_provider_prices (line 15) | def import_provider_prices
    method provider_prices (line 71) | def provider_prices
    method db_prices (line 96) | def db_prices
    method all_prices_exist? (line 103) | def all_prices_exist?
    method expected_count (line 107) | def expected_count
    method effective_start_date (line 112) | def effective_start_date
    method start_price_value (line 118) | def start_price_value
    method upsert_rows (line 126) | def upsert_rows(rows)
    method db_price_currency (line 142) | def db_price_currency
    method prev_price_currency (line 146) | def prev_price_currency
    method normalize_end_date (line 151) | def normalize_end_date(requested_end_date)

FILE: app/models/security/provided.rb
  type Security::Provided (line 1) | module Security::Provided
    function provider (line 7) | def provider
    function search_provider (line 12) | def search_provider(symbol, country_code: nil, exchange_operating_mic:...
    function find_or_fetch_price (line 39) | def find_or_fetch_price(date: Date.current, cache: true)
    function import_provider_details (line 64) | def import_provider_details(clear_cache: false)
    function import_provider_prices (line 93) | def import_provider_prices(start_date:, end_date:, clear_cache: false)
    function provider (line 109) | def provider

FILE: app/models/security/resolver.rb
  class Security::Resolver (line 1) | class Security::Resolver
    method initialize (line 2) | def initialize(symbol, exchange_operating_mic: nil, country_code: nil)
    method resolve (line 13) | def resolve
    method validate_symbol! (line 25) | def validate_symbol!(symbol)
    method offline_security (line 30) | def offline_security
    method exact_match_from_db (line 46) | def exact_match_from_db
    method exact_match_from_provider (line 57) | def exact_match_from_provider
    method close_match_from_provider (line 77) | def close_match_from_provider
    method find_or_create_provider_match! (line 103) | def find_or_create_provider_match!(match)
    method provider_search_result (line 115) | def provider_search_result
    method sorted_country_codes_by_relevance (line 126) | def sorted_country_codes_by_relevance
    method sorted_exchange_operating_mics_by_relevance (line 132) | def sorted_exchange_operating_mics_by_relevance

FILE: app/models/security/synth_combobox_option.rb
  class Security::SynthComboboxOption (line 1) | class Security::SynthComboboxOption
    method id (line 6) | def id
    method to_combobox_display (line 10) | def to_combobox_display

FILE: app/models/series.rb
  class Series (line 1) | class Series
    method each (line 9) | def each(&block)
    method from_raw_values (line 24) | def from_raw_values(values, interval: "1 day")
    method initialize (line 51) | def initialize(start_date:, end_date:, interval:, values:, favorable_d...
    method trend (line 59) | def trend
    method as_json (line 67) | def as_json

FILE: app/models/session.rb
  class Session (line 1) | class Session < ApplicationRecord
    method get_preferred_tab (line 13) | def get_preferred_tab(tab_key)
    method set_preferred_tab (line 17) | def set_preferred_tab(tab_key, tab_value)

FILE: app/models/setting.rb
  class Setting (line 2) | class Setting < RailsSettings::Base

FILE: app/models/subscription.rb
  class Subscription (line 1) | class Subscription < ApplicationRecord
    method new_trial_ends_at (line 23) | def new_trial_ends_at
    method name (line 28) | def name

FILE: app/models/sync.rb
  class Sync (line 1) | class Sync < ApplicationRecord
    method clean (line 55) | def clean
    method perform (line 60) | def perform
    method finalize_if_all_children_finalized (line 83) | def finalize_if_all_children_finalized
    method expand_window_if_needed (line 107) | def expand_window_if_needed(new_window_start_date, new_window_end_date)
    method log_status_change (line 130) | def log_status_change
    method has_failed_children? (line 134) | def has_failed_children?
    method all_children_finalized? (line 138) | def all_children_finalized?
    method perform_post_sync (line 142) | def perform_post_sync
    method report_error (line 151) | def report_error(error)
    method report_warnings (line 157) | def report_warnings
    method handle_start_transition (line 168) | def handle_start_transition
    method handle_transition (line 172) | def handle_transition
    method handle_completion_transition (line 176) | def handle_completion_transition
    method window_valid (line 180) | def window_valid
    method update_family_sync_timestamp (line 186) | def update_family_sync_timestamp
    method family (line 190) | def family

FILE: app/models/tag.rb
  class Tag (line 1) | class Tag < ApplicationRecord
    method replace_and_destroy! (line 15) | def replace_and_destroy!(replacement)

FILE: app/models/tagging.rb
  class Tagging (line 1) | class Tagging < ApplicationRecord

FILE: app/models/tool_call.rb
  class ToolCall (line 1) | class ToolCall < ApplicationRecord

FILE: app/models/tool_call/function.rb
  class ToolCall::Function (line 1) | class ToolCall::Function < ToolCall
    method from_function_request (line 7) | def from_function_request(function_request, result)
    method to_result (line 18) | def to_result

FILE: app/models/trade.rb
  class Trade (line 1) | class Trade < ApplicationRecord
    method build_name (line 12) | def build_name(type, qty, ticker)
    method unrealized_gain_loss (line 18) | def unrealized_gain_loss

FILE: app/models/trade/create_form.rb
  class Trade::CreateForm (line 1) | class Trade::CreateForm
    method create (line 9) | def create
    method security (line 22) | def security
    method create_trade (line 31) | def create_trade
    method create_interest_income (line 56) | def create_interest_income
    method create_transfer (line 75) | def create_transfer
    method create_unlinked_transfer (line 93) | def create_unlinked_transfer

FILE: app/models/trade_import.rb
  class TradeImport (line 1) | class TradeImport < Import
    method import! (line 2) | def import!
    method mapping_steps (line 39) | def mapping_steps
    method required_column_keys (line 45) | def required_column_keys
    method column_keys (line 49) | def column_keys
    method dry_run (line 55) | def dry_run
    method csv_template (line 65) | def csv_template
    method find_or_create_security (line 79) | def find_or_create_security(ticker: nil, exchange_operating_mic: nil)

FILE: app/models/transaction.rb
  class Transaction (line 1) | class Transaction < ApplicationRecord
    method transfer? (line 21) | def transfer?
    method set_category! (line 25) | def set_category!(category)

FILE: app/models/transaction/ruleable.rb
  type Transaction::Ruleable (line 1) | module Transaction::Ruleable
    function eligible_for_category_rule? (line 4) | def eligible_for_category_rule?
    function rules (line 14) | def rules

FILE: app/models/transaction/search.rb
  class Transaction::Search (line 1) | class Transaction::Search
    method initialize (line 20) | def initialize(family, filters: {})
    method transactions_scope (line 25) | def transactions_scope
    method totals (line 45) | def totals
    method cache_key_base (line 71) | def cache_key_base
    method apply_active_accounts_filter (line 82) | def apply_active_accounts_filter(query, active_accounts_only_filter)
    method apply_category_filter (line 91) | def apply_category_filter(query, categories)
    method apply_type_filter (line 108) | def apply_type_filter(query, types)
    method apply_merchant_filter (line 134) | def apply_merchant_filter(query, merchants)
    method apply_tag_filter (line 139) | def apply_tag_filter(query, tags)

FILE: app/models/transaction/transferable.rb
  type Transaction::Transferable (line 1) | module Transaction::Transferable
    function transfer (line 13) | def transfer
    function transfer_match_candidates (line 17) | def transfer_match_candidates
    function family_matches_scope (line 33) | def family_matches_scope

FILE: app/models/transaction_import.rb
  class TransactionImport (line 1) | class TransactionImport < Import
    method import! (line 2) | def import!
    method required_column_keys (line 35) | def required_column_keys
    method column_keys (line 39) | def column_keys
    method mapping_steps (line 45) | def mapping_steps
    method selectable_amount_type_values (line 51) | def selectable_amount_type_values
    method csv_template (line 57) | def csv_template

FILE: app/models/transfer.rb
  class Transfer (line 1) | class Transfer < ApplicationRecord
    method kind_for_account (line 16) | def kind_for_account(account)
    method reject! (line 27) | def reject!
    method destroy! (line 35) | def destroy!
    method confirm! (line 43) | def confirm!
    method date (line 47) | def date
    method sync_account_later (line 51) | def sync_account_later
    method to_account (line 56) | def to_account
    method from_account (line 60) | def from_account
    method amount_abs (line 64) | def amount_abs
    method name (line 68) | def name
    method payment? (line 77) | def payment?
    method loan_payment? (line 81) | def loan_payment?
    method liability_payment? (line 85) | def liability_payment?
    method regular_transfer? (line 89) | def regular_transfer?
    method transfer_type (line 93) | def transfer_type
    method categorizable? (line 99) | def categorizable?
    method transfer_has_different_accounts (line 104) | def transfer_has_different_accounts
    method transfer_has_same_family (line 109) | def transfer_has_same_family
    method transfer_has_opposite_amounts (line 114) | def transfer_has_opposite_amounts
    method transfer_within_date_range (line 132) | def transfer_within_date_range

FILE: app/models/transfer/creator.rb
  class Transfer::Creator (line 1) | class Transfer::Creator
    method initialize (line 2) | def initialize(family:, source_account_id:, destination_account_id:, d...
    method create (line 10) | def create
    method outflow_transaction (line 28) | def outflow_transaction
    method inflow_transaction (line 42) | def inflow_transaction
    method inflow_converted_money (line 58) | def inflow_converted_money
    method outflow_transaction_kind (line 68) | def outflow_transaction_kind
    method name_prefix (line 78) | def name_prefix

FILE: app/models/trend.rb
  class Trend (line 1) | class Trend
    method initialize (line 10) | def initialize(current:, previous:, favorable_direction: nil)
    method direction (line 18) | def direction
    method color (line 28) | def color
    method icon (line 39) | def icon
    method value (line 49) | def value
    method percent (line 53) | def percent
    method percent_formatted (line 62) | def percent_formatted
    method as_json (line 70) | def as_json
    method red_hex (line 83) | def red_hex
    method green_hex (line 87) | def green_hex
    method gray_hex (line 91) | def gray_hex

FILE: app/models/user.rb
  class User (line 1) | class User < ApplicationRecord
    method pending_email_change? (line 40) | def pending_email_change?
    method initiate_email_change (line 44) | def initiate_email_change(new_email)
    method request_impersonation_for (line 60) | def request_impersonation_for(user_id)
    method admin? (line 65) | def admin?
    method display_name (line 69) | def display_name
    method initial (line 73) | def initial
    method initials (line 77) | def initials
    method show_ai_sidebar? (line 85) | def show_ai_sidebar?
    method ai_available? (line 89) | def ai_available?
    method ai_enabled? (line 93) | def ai_enabled?
    method deactivate (line 101) | def deactivate
    method can_deactivate (line 105) | def can_deactivate
    method purge_later (line 111) | def purge_later
    method purge (line 115) | def purge
    method setup_mfa! (line 124) | def setup_mfa!
    method enable_mfa! (line 132) | def enable_mfa!
    method disable_mfa! (line 139) | def disable_mfa!
    method verify_otp? (line 147) | def verify_otp?(code)
    method provisioning_uri (line 153) | def provisioning_uri
    method onboarded? (line 158) | def onboarded?
    method needs_onboarding? (line 162) | def needs_onboarding?
    method ensure_valid_profile_image (line 167) | def ensure_valid_profile_image
    method last_user_in_family? (line 176) | def last_user_in_family?
    method deactivated_email (line 180) | def deactivated_email
    method profile_image_size (line 184) | def profile_image_size
    method totp (line 190) | def totp
    method verify_backup_code? (line 194) | def verify_backup_code?(code)
    method generate_backup_codes (line 208) | def generate_backup_codes

FILE: app/models/user_message.rb
  class UserMessage (line 1) | class UserMessage < Message
    method role (line 6) | def role
    method request_response_later (line 10) | def request_response_later
    method request_response (line 14) | def request_response

FILE: app/models/valuation.rb
  class Valuation (line 1) | class Valuation < ApplicationRecord
    method build_reconciliation_name (line 11) | def build_reconciliation_name(accountable_type)
    method build_opening_anchor_name (line 15) | def build_opening_anchor_name(accountable_type)
    method build_current_anchor_name (line 19) | def build_current_anchor_name(accountable_type)

FILE: app/models/valuation/name.rb
  class Valuation::Name (line 1) | class Valuation::Name
    method initialize (line 2) | def initialize(valuation_kind, accountable_type)
    method to_s (line 7) | def to_s
    method opening_anchor_name (line 21) | def opening_anchor_name
    method current_anchor_name (line 34) | def current_anchor_name
    method recon_name (line 47) | def recon_name

FILE: app/models/vehicle.rb
  class Vehicle (line 1) | class Vehicle < ApplicationRecord
    method mileage (line 6) | def mileage
    method purchase_price (line 10) | def purchase_price
    method trend (line 14) | def trend
    method color (line 19) | def color
    method icon (line 23) | def icon
    method classification (line 27) | def classification
    method first_valuation_amount (line 33) | def first_valuation_amount

FILE: app/services/api_rate_limiter.rb
  class ApiRateLimiter (line 1) | class ApiRateLimiter
    method initialize (line 11) | def initialize(api_key)
    method rate_limit_exceeded? (line 17) | def rate_limit_exceeded?
    method increment_request_count! (line 22) | def increment_request_count!
    method current_count (line 35) | def current_count
    method rate_limit (line 45) | def rate_limit
    method reset_time (line 51) | def reset_time
    method usage_info (line 58) | def usage_info
    method usage_for (line 69) | def self.usage_for(api_key)
    method limit (line 73) | def self.limit(api_key)
    method redis_key (line 85) | def redis_key
    method determine_tier (line 89) | def determine_tier

FILE: app/services/noop_api_rate_limiter.rb
  class NoopApiRateLimiter (line 1) | class NoopApiRateLimiter
    method initialize (line 2) | def initialize(api_key)
    method rate_limit_exceeded? (line 6) | def rate_limit_exceeded?
    method increment_request_count! (line 10) | def increment_request_count!
    method current_count (line 14) | def current_count
    method rate_limit (line 18) | def rate_limit
    method reset_time (line 22) | def reset_time
    method usage_info (line 26) | def usage_info
    method usage_for (line 36) | def self.usage_for(api_key)

FILE: config/application.rb
  type Maybe (line 9) | module Maybe
    class Application (line 10) | class Application < Rails::Application

FILE: config/initializers/rack_attack.rb
  class Rack::Attack (line 3) | class Rack::Attack

FILE: config/initializers/version.rb
  type Maybe (line 1) | module Maybe
    function version (line 3) | def version
    function commit_sha (line 7) | def commit_sha
    function semver (line 16) | def semver

FILE: db/migrate/20240201183314_enable_uuid.rb
  class EnableUuid (line 1) | class EnableUuid < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240201184038_create_families.rb
  class CreateFamilies (line 1) | class CreateFamilies < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240201184212_create_users.rb
  class CreateUsers (line 1) | class CreateUsers < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202015428_create_accounts.rb
  class CreateAccounts (line 1) | class CreateAccounts < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202191425_create_account_loans.rb
  class CreateAccountLoans (line 1) | class CreateAccountLoans < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202191746_add_accountable_to_account.rb
  class AddAccountableToAccount (line 1) | class AddAccountableToAccount < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202192214_create_account_depositories.rb
  class CreateAccountDepositories (line 1) | class CreateAccountDepositories < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202192231_create_account_credits.rb
  class CreateAccountCredits (line 1) | class CreateAccountCredits < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202192238_create_account_investments.rb
  class CreateAccountInvestments (line 1) | class CreateAccountInvestments < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202192312_create_account_properties.rb
  class CreateAccountProperties (line 1) | class CreateAccountProperties < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202192319_create_account_vehicles.rb
  class CreateAccountVehicles (line 1) | class CreateAccountVehicles < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202192327_create_account_other_assets.rb
  class CreateAccountOtherAssets (line 1) | class CreateAccountOtherAssets < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202192333_create_account_other_liabilities.rb
  class CreateAccountOtherLiabilities (line 1) | class CreateAccountOtherLiabilities < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240202230325_create_invite_codes.rb
  class CreateInviteCodes (line 1) | class CreateInviteCodes < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240203030754_remove_type_from_accounts.rb
  class RemoveTypeFromAccounts (line 1) | class RemoveTypeFromAccounts < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240203050018_add_token_index_to_invite_codes.rb
  class AddTokenIndexToInviteCodes (line 1) | class AddTokenIndexToInviteCodes < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240206031739_replace_money_field.rb
  class ReplaceMoneyField (line 1) | class ReplaceMoneyField < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240209153232_add_currency_to_families.rb
  class AddCurrencyToFamilies (line 1) | class AddCurrencyToFamilies < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240209174912_redo_money_storage.rb
  class RedoMoneyStorage (line 1) | class RedoMoneyStorage < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240209200519_create_currencies.rb
  class CreateCurrencies (line 1) | class CreateCurrencies < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240209200924_create_exchange_rates.rb
  class CreateExchangeRates (line 1) | class CreateExchangeRates < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240210155058_create_good_jobs.rb
  class CreateGoodJobs (line 3) | class CreateGoodJobs < ActiveRecord::Migration[7.2]
    method change (line 4) | def change

FILE: db/migrate/20240212150110_create_account_balances.rb
  class CreateAccountBalances (line 1) | class CreateAccountBalances < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240215201527_create_valuations.rb
  class CreateValuations (line 1) | class CreateValuations < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240221004818_remove_valuation_type.rb
  class RemoveValuationType (line 1) | class RemoveValuationType < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240222144849_add_status_to_account.rb
  class AddStatusToAccount (line 1) | class AddStatusToAccount < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240223162105_create_transactions.rb
  class CreateTransactions (line 1) | class CreateTransactions < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240227142457_rename_account_balance.rb
  class RenameAccountBalance (line 1) | class RenameAccountBalance < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240302145715_add_classification_to_accounts.rb
  class AddClassificationToAccounts (line 1) | class AddClassificationToAccounts < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240306193345_add_is_active_to_account.rb
  class AddIsActiveToAccount (line 1) | class AddIsActiveToAccount < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240307082827_create_transaction_categories.rb
  class CreateTransactionCategories (line 1) | class CreateTransactionCategories < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240308121431_remove_currency_table.rb
  class RemoveCurrencyTable (line 1) | class RemoveCurrencyTable < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240308214956_add_notes_and_excluded_to_transaction.rb
  class AddNotesAndExcludedToTransaction (line 1) | class AddNotesAndExcludedToTransaction < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240309180636_add_sync_status_fields_to_account.rb
  class AddSyncStatusFieldsToAccount (line 1) | class AddSyncStatusFieldsToAccount < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240313141813_update_unique_indexes_for_account_balance_and_exchange_rate.rb
  class UpdateUniqueIndexesForAccountBalanceAndExchangeRate (line 1) | class UpdateUniqueIndexesForAccountBalanceAndExchangeRate < ActiveRecord...
    method change (line 2) | def change

FILE: db/migrate/20240313203622_remove_converted_balance_from_account.rb
  class RemoveConvertedBalanceFromAccount (line 1) | class RemoveConvertedBalanceFromAccount < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240319154732_create_account_cryptos.rb
  class CreateAccountCryptos (line 1) | class CreateAccountCryptos < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240325064211_add_uniq_index_to_users_email.rb
  class AddUniqIndexToUsersEmail (line 1) | class AddUniqIndexToUsersEmail < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240401213443_add_last_sync_date_to_accounts.rb
  class AddLastSyncDateToAccounts (line 1) | class AddLastSyncDateToAccounts < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240403192649_add_last_login_at_to_users.rb
  class AddLastLoginAtToUsers (line 1) | class AddLastLoginAtToUsers < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240404112829_change_transaction_category_delete_behavior.rb
  class ChangeTransactionCategoryDeleteBehavior (line 1) | class ChangeTransactionCategoryDeleteBehavior < ActiveRecord::Migration[...
    method change (line 2) | def change

FILE: db/migrate/20240410183531_create_settings.rb
  class CreateSettings (line 1) | class CreateSettings < ActiveRecord::Migration[7.2]
    method up (line 2) | def self.up
    method down (line 12) | def self.down

FILE: db/migrate/20240411102931_add_last_seen_upgrade_to_user.rb
  class AddLastSeenUpgradeToUser (line 1) | class AddLastSeenUpgradeToUser < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240425000110_add_role_to_users.rb
  class AddRoleToUsers (line 1) | class AddRoleToUsers < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240426162500_create_active_storage_tables.active_storage.rb
  class CreateActiveStorageTables (line 2) | class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
    method change (line 3) | def change
    method primary_and_foreign_key_types (line 50) | def primary_and_foreign_key_types

FILE: db/migrate/20240426191312_add_transaction_merchants.rb
  class AddTransactionMerchants (line 1) | class AddTransactionMerchants < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240430111641_add_active_to_users.rb
  class AddActiveToUsers (line 1) | class AddActiveToUsers < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240502205006_create_imports.rb
  class CreateImports (line 1) | class CreateImports < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240520074309_add_admin_role_to_current_users.rb
  class AddAdminRoleToCurrentUsers (line 1) | class AddAdminRoleToCurrentUsers < ActiveRecord::Migration[7.2]
    method up (line 2) | def up

FILE: db/migrate/20240522133147_create_tags.rb
  class CreateTags (line 1) | class CreateTags < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240522151453_create_taggings.rb
  class CreateTaggings (line 1) | class CreateTaggings < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240524203959_change_account_error_columns_default.rb
  class ChangeAccountErrorColumnsDefault (line 1) | class ChangeAccountErrorColumnsDefault < ActiveRecord::Migration[7.2]
    method up (line 2) | def up

FILE: db/migrate/20240612164751_create_institutions.rb
  class CreateInstitutions (line 1) | class CreateInstitutions < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240612164944_add_institution_to_accounts.rb
  class AddInstitutionToAccounts (line 1) | class AddInstitutionToAccounts < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240614120946_create_transfers.rb
  class CreateTransfers (line 1) | class CreateTransfers < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240614121110_add_transfer_fields_to_transaction.rb
  class AddTransferFieldsToTransaction (line 1) | class AddTransferFieldsToTransaction < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240619125949_rename_accountable_tables.rb
  class RenameAccountableTables (line 1) | class RenameAccountableTables < ActiveRecord::Migration[7.2]
    method change (line 2) | def change
    method update_accountable_types (line 80) | def update_accountable_types(mapping)

FILE: db/migrate/20240620114307_rename_categories_table.rb
  class RenameCategoriesTable (line 1) | class RenameCategoriesTable < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240620122201_rename_merchants_table.rb
  class RenameMerchantsTable (line 1) | class RenameMerchantsTable < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240620125026_rename_transfer_table.rb
  class RenameTransferTable (line 1) | class RenameTransferTable < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240620221801_rename_valuation_table.rb
  class RenameValuationTable (line 1) | class RenameValuationTable < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240621212528_rename_transactions_table.rb
  class RenameTransactionsTable (line 1) | class RenameTransactionsTable < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240624160611_create_account_entries.rb
  class CreateAccountEntries (line 1) | class CreateAccountEntries < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240624161153_migrate_entryables.rb
  class MigrateEntryables (line 1) | class MigrateEntryables < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240624164119_remove_old_columns_from_entryables.rb
  class RemoveOldColumnsFromEntryables (line 1) | class RemoveOldColumnsFromEntryables < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240628104551_move_transfers_association_from_transactions_to_entries.rb
  class MoveTransfersAssociationFromTransactionsToEntries (line 1) | class MoveTransfersAssociationFromTransactionsToEntries < ActiveRecord::...
    method change (line 2) | def change

FILE: db/migrate/20240706151026_rename_rate_fields.rb
  class RenameRateFields (line 1) | class RenameRateFields < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240707130331_create_account_syncs.rb
  class CreateAccountSyncs (line 1) | class CreateAccountSyncs < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240709113713_create_good_job_execution_error_backtrace.rb
  class CreateGoodJobExecutionErrorBacktrace (line 3) | class CreateGoodJobExecutionErrorBacktrace < ActiveRecord::Migration[7.2]
    method change (line 4) | def change

FILE: db/migrate/20240709113714_create_good_job_process_lock_ids.rb
  class CreateGoodJobProcessLockIds (line 3) | class CreateGoodJobProcessLockIds < ActiveRecord::Migration[7.2]
    method change (line 4) | def change

FILE: db/migrate/20240709113715_create_good_job_process_lock_indexes.rb
  class CreateGoodJobProcessLockIndexes (line 3) | class CreateGoodJobProcessLockIndexes < ActiveRecord::Migration[7.2]
    method change (line 6) | def change

FILE: db/migrate/20240709152243_create_good_job_execution_duration.rb
  class CreateGoodJobExecutionDuration (line 3) | class CreateGoodJobExecutionDuration < ActiveRecord::Migration[7.2]
    method change (line 4) | def change

FILE: db/migrate/20240710182529_create_securities.rb
  class CreateSecurities (line 1) | class CreateSecurities < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240710182728_create_security_prices.rb
  class CreateSecurityPrices (line 1) | class CreateSecurityPrices < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240710184048_create_account_trades.rb
  class CreateAccountTrades (line 1) | class CreateAccountTrades < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240710184249_create_account_holdings.rb
  class CreateAccountHoldings (line 1) | class CreateAccountHoldings < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240717113535_remove_default_from_account_balance.rb
  class RemoveDefaultFromAccountBalance (line 1) | class RemoveDefaultFromAccountBalance < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240725163339_add_last_synced_at_to_family.rb
  class AddLastSyncedAtToFamily (line 1) | class AddLastSyncedAtToFamily < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240731191344_change_primary_identifier_for_security.rb
  class ChangePrimaryIdentifierForSecurity (line 1) | class ChangePrimaryIdentifierForSecurity < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240807153618_add_currency_field_to_trade.rb
  class AddCurrencyFieldToTrade (line 1) | class AddCurrencyFieldToTrade < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240813170608_fix_invalid_accountable_data.rb
  class FixInvalidAccountableData (line 1) | class FixInvalidAccountableData < ActiveRecord::Migration[7.2]
    method up (line 2) | def up
    method down (line 12) | def down

FILE: db/migrate/20240815125404_create_issues.rb
  class CreateIssues (line 1) | class CreateIssues < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240815190722_remove_warnings_from_sync.rb
  class RemoveWarningsFromSync (line 1) | class RemoveWarningsFromSync < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240816071555_add_col_sep_to_imports.rb
  class AddColSepToImports (line 1) | class AddColSepToImports < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240817144454_rename_import_raw_csv_str_to_raw_file_str.rb
  class RenameImportRawCsvStrToRawFileStr (line 1) | class RenameImportRawCsvStrToRawFileStr < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240822174006_create_addresses.rb
  class CreateAddresses (line 1) | class CreateAddresses < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240822180845_add_property_attributes.rb
  class AddPropertyAttributes (line 1) | class AddPropertyAttributes < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240823125526_add_details_to_vehicle.rb
  class AddDetailsToVehicle (line 1) | class AddDetailsToVehicle < ActiveRecord::Migration[7.2]
    method change (line 2) | def change

FILE: db/migrate/20240911143158_add_last_synced_at_institution.rb
  class AddLastSyncedAtInstitution (line 1) | cla
Condensed preview — 1578 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,989K chars).
[
  {
    "path": ".cursor/rules/cursor_rules.mdc",
    "chars": 1551,
    "preview": "---\ndescription: Guidelines for creating and maintaining Cursor rules to ensure consistency and effectiveness.\nglobs: .c"
  },
  {
    "path": ".cursor/rules/general-rules.mdc",
    "chars": 998,
    "preview": "---\ndescription: Miscellaneous rules to get the AI to behave\nglobs: *\nalwaysApply: true\n---\n# General rules for AI \n\n- U"
  },
  {
    "path": ".cursor/rules/project-conventions.mdc",
    "chars": 4576,
    "preview": "---\ndescription: \nglobs: \nalwaysApply: true\n---\nThis rule serves as high-level documentation for how you should write co"
  },
  {
    "path": ".cursor/rules/project-design.mdc",
    "chars": 15289,
    "preview": "---\ndescription: This rule explains the system architecture and data flow of the Rails app\nglobs: *\nalwaysApply: true\n--"
  },
  {
    "path": ".cursor/rules/self_improve.mdc",
    "chars": 2426,
    "preview": "---\ndescription: Guidelines for continuously improving Cursor rules based on emerging code patterns and best practices.\n"
  },
  {
    "path": ".cursor/rules/stimulus_conventions.mdc",
    "chars": 2255,
    "preview": "---\ndescription: \nglobs: \nalwaysApply: false\n---\nThis rule describes how to write Stimulus controllers.\n\n- **Use declara"
  },
  {
    "path": ".cursor/rules/testing.mdc",
    "chars": 3408,
    "preview": "---\ndescription: \nglobs: test/**\nalwaysApply: false\n---\nUse this rule to learn how to write tests for the Maybe codebase"
  },
  {
    "path": ".cursor/rules/ui-ux-design-guidelines.mdc",
    "chars": 1248,
    "preview": "---\ndescription: This file describes Maybe's design system and how views should be styled\nglobs: app/views/**,app/helper"
  },
  {
    "path": ".cursor/rules/view_conventions.mdc",
    "chars": 4303,
    "preview": "---\ndescription: \nglobs: app/views/**,app/javascript/**,app/components/**/*.js\nalwaysApply: false\n---\nUse this rule to l"
  },
  {
    "path": ".devcontainer/Dockerfile",
    "chars": 533,
    "preview": "ARG RUBY_VERSION=3.4.4\nFROM ruby:${RUBY_VERSION}-slim-bullseye\n\nRUN apt-get update && export DEBIAN_FRONTEND=noninteract"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 508,
    "preview": "{\n  \"name\": \"Maybe\",\n  \"dockerComposeFile\": \"docker-compose.yml\",\n  \"service\": \"app\",\n  \"workspaceFolder\": \"/workspace\","
  },
  {
    "path": ".devcontainer/docker-compose.yml",
    "chars": 1159,
    "preview": "x-db-env: &db_env\n  POSTGRES_USER: postgres\n  POSTGRES_DB: postgres\n  POSTGRES_PASSWORD: postgres\n\nx-rails-env: &rails_e"
  },
  {
    "path": ".dockerignore",
    "chars": 811,
    "preview": "# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.\n\n# Ignore git d"
  },
  {
    "path": ".editorconfig",
    "chars": 86,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_style = space\nindent_size = 2"
  },
  {
    "path": ".env.example",
    "chars": 3459,
    "preview": "# ================================ PLEASE READ ===========================================================\n# This file o"
  },
  {
    "path": ".env.local.example",
    "chars": 162,
    "preview": "# To enable / disable self-hosting features.\nSELF_HOSTED=false\n\n# Enable Synth market data (careful, this will use your "
  },
  {
    "path": ".env.test.example",
    "chars": 474,
    "preview": "SELF_HOSTED=false\n\n# ================\n# Data Providers\n# ---------------------------------------------------------------"
  },
  {
    "path": ".erb_lint.yml",
    "chars": 204,
    "preview": "EnableDefaultLinters: true\nlinters:\n  Rubocop:\n    enabled: true\n    only: [Style/StringLiterals]\n    rubocop_config:\n  "
  },
  {
    "path": ".gitattributes",
    "chars": 348,
    "preview": "# See https://git-scm.com/docs/gitattributes for more about git attribute files.\n\n# Mark the database schema as having b"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/feature-requests.yml",
    "chars": 926,
    "preview": "title: Feature Request\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in Maybe"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1893,
    "preview": "---\nname: Bug report\nabout: Open a bug report when you experience broken functionality within the latest\n  version of th"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/other.md",
    "chars": 1529,
    "preview": "---\nname: Other\nabout: All other issues\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n## Before you start (required)\n\n### Is "
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 267,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: bundler\n    directory: \"/\"\n    schedule:\n      interval: weekly\n    open-pull"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 3253,
    "preview": "name: CI\n\non:\n  workflow_call:\n\njobs:\n  scan_ruby:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      -"
  },
  {
    "path": ".github/workflows/pr.yml",
    "chars": 89,
    "preview": "name: Pull Request\n\non:\n  pull_request:\n\njobs:\n  ci:\n    uses: ./.github/workflows/ci.yml"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 2344,
    "preview": "name: Publish Docker image\n\non:\n  workflow_dispatch:\n    inputs:\n      ref:\n        description: 'Git ref (tag or commit"
  },
  {
    "path": ".gitignore",
    "chars": 1853,
    "preview": "# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring t"
  },
  {
    "path": ".rubocop.yml",
    "chars": 274,
    "preview": "inherit_gem:\n  rubocop-rails-omakase: rubocop.yml\n  \nLayout/IndentationWidth:\n  Enabled: true\n\nLayout/IndentationStyle:\n"
  },
  {
    "path": ".ruby-version",
    "chars": 6,
    "preview": "3.4.4\n"
  },
  {
    "path": "CLAUDE.md",
    "chars": 10952,
    "preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3241,
    "preview": "# Contributing to Maybe\n\nIt means so much that you're interested in contributing to Maybe! Seriously. Thank you. The ent"
  },
  {
    "path": "Dockerfile",
    "chars": 2050,
    "preview": "# syntax = docker/dockerfile:1\n\n# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile\nARG RUBY_"
  },
  {
    "path": "Gemfile",
    "chars": 2138,
    "preview": "source \"https://rubygems.org\"\n\nruby file: \".ruby-version\"\n\n# Rails\ngem \"rails\", \"~> 7.2.2\"\n\n# Drivers\ngem \"pg\", \"~> 1.5\""
  },
  {
    "path": "LICENSE",
    "chars": 34522,
    "preview": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C)"
  },
  {
    "path": "Procfile.dev",
    "chars": 157,
    "preview": "web: bundle exec ${DEBUG:+rdbg -O -n -c --} bin/rails server -b 0.0.0.0\ncss: bundle exec bin/rails tailwindcss:watch 2>/"
  },
  {
    "path": "README.md",
    "chars": 2364,
    "preview": "\n<img width=\"1190\" alt=\"maybe_hero\" src=\"https://github.com/user-attachments/assets/5ed08763-a9ee-42b2-a436-e05038fcf573"
  },
  {
    "path": "Rakefile",
    "chars": 227,
    "preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
  },
  {
    "path": "app/assets/builds/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "app/assets/tailwind/application.css",
    "chars": 3105,
    "preview": "@import 'tailwindcss';\n\n@import \"./maybe-design-system.css\";\n\n@import \"./geist-font.css\";\n@import \"./geist-mono-font.css"
  },
  {
    "path": "app/assets/tailwind/geist-font.css",
    "chars": 1867,
    "preview": "\n\n/* Variable font */\n@font-face {\n  font-family: 'Geist';\n  src: url('./geist/Geist[wght].woff2') format('woff2-variati"
  },
  {
    "path": "app/assets/tailwind/geist-mono-font.css",
    "chars": 2006,
    "preview": "/* Variable font */\n@font-face {\n  font-family: 'Geist Mono';\n  src: url('./geist_mono/GeistMono[wght].woff2') format('w"
  },
  {
    "path": "app/assets/tailwind/maybe-design-system/background-utils.css",
    "chars": 1278,
    "preview": "@utility bg-surface {\n  @apply bg-gray-50;\n\n  @variant theme-dark {\n    @apply bg-black;\n  }\n}\n\n@utility bg-surface-hove"
  },
  {
    "path": "app/assets/tailwind/maybe-design-system/border-utils.css",
    "chars": 1918,
    "preview": "/* Custom shadow borders used for surfaces / containers  */\n@utility shadow-border-xs {\n  box-shadow: var(--shadow-xs), "
  },
  {
    "path": "app/assets/tailwind/maybe-design-system/component-utils.css",
    "chars": 1754,
    "preview": "/* Button Backgrounds */\n@utility button-bg-primary {\n  @apply bg-gray-900;\n  /* Maps to fg-primary light */\n\n  @variant"
  },
  {
    "path": "app/assets/tailwind/maybe-design-system/foreground-utils.css",
    "chars": 840,
    "preview": "@utility fg-gray {\n  @apply text-gray-500;\n\n  @variant theme-dark {\n    @apply text-gray-400;\n  }\n}\n\n@utility fg-contras"
  },
  {
    "path": "app/assets/tailwind/maybe-design-system/text-utils.css",
    "chars": 520,
    "preview": "@utility text-primary {\n  @apply text-gray-900;\n\n  @variant theme-dark {\n   @apply text-white;\n  }\n}\n\n@utility text-inve"
  },
  {
    "path": "app/assets/tailwind/maybe-design-system.css",
    "chars": 14432,
    "preview": "/* \n  This file contains all of the Figma design tokens, components, etc. that \n  are used globally across the app. \n\n  "
  },
  {
    "path": "app/assets/tailwind/simonweb_pickr.css",
    "chars": 9167,
    "preview": "/*! Pickr 1.9.1 MIT | https://github.com/Simonwep/pickr */\n.pickr{position:relative;overflow:visible;transform:translate"
  },
  {
    "path": "app/channels/application_cable/channel.rb",
    "chars": 79,
    "preview": "module ApplicationCable\n  class Channel < ActionCable::Channel::Base\n  end\nend\n"
  },
  {
    "path": "app/channels/application_cable/connection.rb",
    "chars": 221,
    "preview": "module ApplicationCable\n  class Connection < ActionCable::Connection::Base\n    rescue_from StandardError, with: :report_"
  },
  {
    "path": "app/components/DS/alert.html.erb",
    "chars": 188,
    "preview": "<div class=\"<%= container_classes %>\">\n  <%= helpers.icon icon_name, size: \"sm\", color: icon_color, class: \"shrink-0\" %>"
  },
  {
    "path": "app/components/DS/alert.rb",
    "chars": 1441,
    "preview": "class DS::Alert < DesignSystemComponent\n  def initialize(message:, variant: :info)\n    @message = message\n    @variant ="
  },
  {
    "path": "app/components/DS/button.html.erb",
    "chars": 341,
    "preview": "<%= container do %>\n  <% if icon && (icon_position != :right) %>\n    <%= helpers.icon(icon, size: size, color: icon_colo"
  },
  {
    "path": "app/components/DS/button.rb",
    "chars": 988,
    "preview": "# frozen_string_literal: true\n\n# An extension to `button_to` helper.  All options are passed through to the `button_to` "
  },
  {
    "path": "app/components/DS/buttonish.rb",
    "chars": 4631,
    "preview": "class DS::Buttonish < DesignSystemComponent\n  VARIANTS = {\n    primary: {\n      container_classes: \"text-inverse bg-inve"
  },
  {
    "path": "app/components/DS/dialog.html.erb",
    "chars": 1210,
    "preview": "<%= wrapper_element do %>\n  <%= tag.dialog class: \"w-full h-full bg-transparent theme-dark:backdrop:bg-alpha-black-900 b"
  },
  {
    "path": "app/components/DS/dialog.rb",
    "chars": 3276,
    "preview": "class DS::Dialog < DesignSystemComponent\n  renders_one :header, ->(title: nil, subtitle: nil, hide_close_icon: false, **"
  },
  {
    "path": "app/components/DS/dialog_controller.js",
    "chars": 727,
    "preview": "import { Controller } from \"@hotwired/stimulus\";\n\n// Connects to data-controller=\"dialog\"\nexport default class extends C"
  },
  {
    "path": "app/components/DS/disclosure.html.erb",
    "chars": 872,
    "preview": "<details class=\"group\" <%= \"open\" if open %>>\n  <%= tag.summary class: class_names(\n    \"px-3 py-2 rounded-xl cursor-poi"
  },
  {
    "path": "app/components/DS/disclosure.rb",
    "chars": 276,
    "preview": "class DS::Disclosure < DesignSystemComponent\n  renders_one :summary_content\n\n  attr_reader :title, :align, :open, :opts\n"
  },
  {
    "path": "app/components/DS/filled_icon.html.erb",
    "chars": 275,
    "preview": "<%= tag.div style: transparent? ? container_styles : nil,\n            class: container_classes do %>\n  <% if icon %>\n   "
  },
  {
    "path": "app/components/DS/filled_icon.rb",
    "chars": 2139,
    "preview": "class DS::FilledIcon < DesignSystemComponent\n  attr_reader :icon, :text, :hex_color, :size, :rounded, :variant\n\n  VARIAN"
  },
  {
    "path": "app/components/DS/link.html.erb",
    "chars": 340,
    "preview": "<%= link_to href, **merged_opts do %>\n  <% if icon && (icon_position != \"right\") %>\n    <%= helpers.icon(icon, size: siz"
  },
  {
    "path": "app/components/DS/link.rb",
    "chars": 682,
    "preview": "# An extension to `link_to` helper.  All options are passed through to the `link_to` helper with some additional\n# optio"
  },
  {
    "path": "app/components/DS/menu.html.erb",
    "chars": 1011,
    "preview": "<%= tag.div data: { controller: \"DS--menu\", DS__menu_placement_value: placement, DS__menu_offset_value: offset, testid: "
  },
  {
    "path": "app/components/DS/menu.rb",
    "chars": 1153,
    "preview": "# frozen_string_literal: true\n\nclass DS::Menu < DesignSystemComponent\n  attr_reader :variant, :avatar_url, :initials, :p"
  },
  {
    "path": "app/components/DS/menu_controller.js",
    "chars": 2898,
    "preview": "import {\n  autoUpdate,\n  computePosition,\n  flip,\n  offset,\n  shift,\n} from \"@floating-ui/dom\";\nimport { Controller } fr"
  },
  {
    "path": "app/components/DS/menu_item.html.erb",
    "chars": 330,
    "preview": "<% if variant == :divider %>\n  <%= render \"shared/ruler\", classes: \"my-1\" %>\n<% else %>\n  <div class=\"px-1\">\n    <%= wra"
  },
  {
    "path": "app/components/DS/menu_item.rb",
    "chars": 1624,
    "preview": "class DS::MenuItem < DesignSystemComponent\n  VARIANTS = %i[link button divider].freeze\n\n  attr_reader :variant, :text, :"
  },
  {
    "path": "app/components/DS/tab.rb",
    "chars": 167,
    "preview": "class DS::Tab < DesignSystemComponent\n  attr_reader :id, :label\n\n  def initialize(id:, label:)\n    @id = id\n    @label ="
  },
  {
    "path": "app/components/DS/tabs/nav.rb",
    "chars": 930,
    "preview": "class DS::Tabs::Nav < DesignSystemComponent\n  erb_template <<~ERB\n    <%= tag.nav class: classes do %>\n      <% btns.eac"
  },
  {
    "path": "app/components/DS/tabs/panel.rb",
    "chars": 156,
    "preview": "class DS::Tabs::Panel < DesignSystemComponent\n  attr_reader :tab_id\n\n  def initialize(tab_id:)\n    @tab_id = tab_id\n  en"
  },
  {
    "path": "app/components/DS/tabs.html.erb",
    "chars": 428,
    "preview": "<%= tag.div data: {\n  controller: \"DS--tabs\",\n  testid: testid,\n  DS__tabs_session_key_value: session_key,\n  DS__tabs_ur"
  },
  {
    "path": "app/components/DS/tabs.rb",
    "chars": 2001,
    "preview": "class DS::Tabs < DesignSystemComponent\n  renders_one :nav, ->(classes: nil) do\n    DS::Tabs::Nav.new(\n      active_tab: "
  },
  {
    "path": "app/components/DS/tabs_controller.js",
    "chars": 1794,
    "preview": "import { Controller } from \"@hotwired/stimulus\";\n\n// Connects to data-controller=\"tabs--components\"\nexport default class"
  },
  {
    "path": "app/components/DS/toggle.html.erb",
    "chars": 298,
    "preview": "<div class=\"relative inline-block select-none\">\n  <%= hidden_field_tag name, unchecked_value, id: nil %>\n  <%= check_box"
  },
  {
    "path": "app/components/DS/toggle.rb",
    "chars": 971,
    "preview": "class DS::Toggle < DesignSystemComponent\n  attr_reader :id, :name, :checked, :disabled, :checked_value, :unchecked_value"
  },
  {
    "path": "app/components/DS/tooltip.html.erb",
    "chars": 509,
    "preview": "<span data-controller=\"DS--tooltip\" data-DS--tooltip-placement-value=\"<%= placement %>\" data-DS--tooltip-offset-value=\"<"
  },
  {
    "path": "app/components/DS/tooltip.rb",
    "chars": 455,
    "preview": "class DS::Tooltip < ApplicationComponent\n  attr_reader :placement, :offset, :cross_axis, :icon_name, :size, :color\n\n  de"
  },
  {
    "path": "app/components/DS/tooltip_controller.js",
    "chars": 1994,
    "preview": "import {\n  autoUpdate,\n  computePosition,\n  flip,\n  offset,\n  shift,\n} from \"@floating-ui/dom\";\nimport { Controller } fr"
  },
  {
    "path": "app/components/UI/account/activity_date.html.erb",
    "chars": 1713,
    "preview": "<%= tag.div id: id, data: { bulk_select_target: \"group\" }, class: \"bg-container-inset rounded-xl p-1 w-full\" do %>\n  <de"
  },
  {
    "path": "app/components/UI/account/activity_date.rb",
    "chars": 598,
    "preview": "class UI::Account::ActivityDate < ApplicationComponent\n  attr_reader :account, :data\n\n  delegate :date, :entries, :balan"
  },
  {
    "path": "app/components/UI/account/activity_feed.html.erb",
    "chars": 3687,
    "preview": "<%= turbo_frame_tag dom_id(account, \"entries\") do %>\n  <div class=\"bg-container p-5 shadow-border-xs rounded-xl\">\n    <d"
  },
  {
    "path": "app/components/UI/account/activity_feed.rb",
    "chars": 606,
    "preview": "class UI::Account::ActivityFeed < ApplicationComponent\n  attr_reader :feed_data, :pagy, :search\n\n  def initialize(feed_d"
  },
  {
    "path": "app/components/UI/account/balance_reconciliation.html.erb",
    "chars": 836,
    "preview": "<div class=\"space-y-3\">\n  <% reconciliation_items.each_with_index do |item, index| %>\n    <% if item[:style] == :subtota"
  },
  {
    "path": "app/components/UI/account/balance_reconciliation.rb",
    "chars": 7282,
    "preview": "class UI::Account::BalanceReconciliation < ApplicationComponent\n  attr_reader :balance, :account\n\n  def initialize(balan"
  },
  {
    "path": "app/components/UI/account/chart.html.erb",
    "chars": 2540,
    "preview": "<div id=\"<%= dom_id(account, :chart) %>\" class=\"bg-container shadow-border-xs rounded-xl space-y-2\">\n  <div class=\"flex "
  },
  {
    "path": "app/components/UI/account/chart.rb",
    "chars": 1454,
    "preview": "class UI::Account::Chart < ApplicationComponent\n  attr_reader :account\n\n  def initialize(account:, period: nil, view: ni"
  },
  {
    "path": "app/components/UI/account_page.html.erb",
    "chars": 1037,
    "preview": "<%= turbo_stream_from account %>\n\n<%= turbo_frame_tag id do %>\n  <%= tag.div class: \"space-y-4 pb-32\" do %>\n    <%= rend"
  },
  {
    "path": "app/components/UI/account_page.rb",
    "chars": 1412,
    "preview": "class UI::AccountPage < ApplicationComponent\n  attr_reader :account, :chart_view, :chart_period\n\n  renders_one :activity"
  },
  {
    "path": "app/components/application_component.rb",
    "chars": 198,
    "preview": "class ApplicationComponent < ViewComponent::Base\n  # These don't work as expected with helpers.turbo_frame_tag, etc., so"
  },
  {
    "path": "app/components/design_system_component.rb",
    "chars": 54,
    "preview": "class DesignSystemComponent < ViewComponent::Base\nend\n"
  },
  {
    "path": "app/controllers/accountable_sparklines_controller.rb",
    "chars": 1150,
    "preview": "class AccountableSparklinesController < ApplicationController\n  def show\n    @accountable = Accountable.from_type(params"
  },
  {
    "path": "app/controllers/accounts_controller.rb",
    "chars": 1918,
    "preview": "class AccountsController < ApplicationController\n  before_action :set_account, only: %i[sync sparkline toggle_active sho"
  },
  {
    "path": "app/controllers/api/v1/accounts_controller.rb",
    "chars": 1310,
    "preview": "# frozen_string_literal: true\n\nclass Api::V1::AccountsController < Api::V1::BaseController\n  include Pagy::Backend\n\n  # "
  },
  {
    "path": "app/controllers/api/v1/auth_controller.rb",
    "chars": 6992,
    "preview": "module Api\n  module V1\n    class AuthController < BaseController\n      include Invitable\n\n      skip_before_action :auth"
  },
  {
    "path": "app/controllers/api/v1/base_controller.rb",
    "chars": 10432,
    "preview": "# frozen_string_literal: true\n\nclass Api::V1::BaseController < ApplicationController\n  include Doorkeeper::Rails::Helper"
  },
  {
    "path": "app/controllers/api/v1/chats_controller.rb",
    "chars": 2158,
    "preview": "# frozen_string_literal: true\n\nclass Api::V1::ChatsController < Api::V1::BaseController\n  include Pagy::Backend\n  before"
  },
  {
    "path": "app/controllers/api/v1/messages_controller.rb",
    "chars": 1517,
    "preview": "# frozen_string_literal: true\n\nclass Api::V1::MessagesController < Api::V1::BaseController\n  before_action :require_ai_e"
  },
  {
    "path": "app/controllers/api/v1/test_controller.rb",
    "chars": 1380,
    "preview": "# frozen_string_literal: true\n\n# Test controller for API V1 Base Controller functionality\n# This controller is only used"
  },
  {
    "path": "app/controllers/api/v1/transactions_controller.rb",
    "chars": 9538,
    "preview": "# frozen_string_literal: true\n\nclass Api::V1::TransactionsController < Api::V1::BaseController\n  include Pagy::Backend\n\n"
  },
  {
    "path": "app/controllers/api/v1/usage_controller.rb",
    "chars": 1202,
    "preview": "class Api::V1::UsageController < Api::V1::BaseController\n  # GET /api/v1/usage\n  def show\n    return unless authorize_sc"
  },
  {
    "path": "app/controllers/application_controller.rb",
    "chars": 1098,
    "preview": "class ApplicationController < ActionController::Base\n  include RestoreLayoutPreferences, Onboardable, Localize, AutoSync"
  },
  {
    "path": "app/controllers/budget_categories_controller.rb",
    "chars": 1722,
    "preview": "class BudgetCategoriesController < ApplicationController\n  before_action :set_budget\n\n  def index\n    @budget_categories"
  },
  {
    "path": "app/controllers/budgets_controller.rb",
    "chars": 1111,
    "preview": "class BudgetsController < ApplicationController\n  before_action :set_budget, only: %i[show edit update]\n\n  def index\n   "
  },
  {
    "path": "app/controllers/categories_controller.rb",
    "chars": 2472,
    "preview": "class CategoriesController < ApplicationController\n  before_action :set_category, only: %i[edit update destroy]\n  before"
  },
  {
    "path": "app/controllers/category/deletions_controller.rb",
    "chars": 622,
    "preview": "class Category::DeletionsController < ApplicationController\n  before_action :set_category\n  before_action :set_replaceme"
  },
  {
    "path": "app/controllers/category/dropdowns_controller.rb",
    "chars": 583,
    "preview": "class Category::DropdownsController < ApplicationController\n  before_action :set_from_params\n\n  def show\n    @categories"
  },
  {
    "path": "app/controllers/chats_controller.rb",
    "chars": 1631,
    "preview": "class ChatsController < ApplicationController\n  include ActionView::RecordIdentifier\n\n  before_action :set_chat, only: ["
  },
  {
    "path": "app/controllers/concerns/accountable_resource.rb",
    "chars": 2520,
    "preview": "module AccountableResource\n  extend ActiveSupport::Concern\n\n  included do\n    include Periodable\n\n    before_action :set"
  },
  {
    "path": "app/controllers/concerns/authentication.rb",
    "chars": 1612,
    "preview": "module Authentication\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :set_request_details\n    before_a"
  },
  {
    "path": "app/controllers/concerns/auto_sync.rb",
    "chars": 609,
    "preview": "module AutoSync\n  extend ActiveSupport::Concern\n\n  # included do\n  #   before_action :sync_family, if: :family_needs_aut"
  },
  {
    "path": "app/controllers/concerns/breadcrumbable.rb",
    "chars": 316,
    "preview": "module Breadcrumbable\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :set_breadcrumbs\n  end\n\n  private"
  },
  {
    "path": "app/controllers/concerns/entryable_resource.rb",
    "chars": 1029,
    "preview": "module EntryableResource\n  extend ActiveSupport::Concern\n\n  included do\n    include StreamExtensions, ActionView::Record"
  },
  {
    "path": "app/controllers/concerns/feature_guardable.rb",
    "chars": 546,
    "preview": "# Simple feature guard that renders a 403 Forbidden status with a message\n# when the feature is disabled.\n#\n# Example:\n#"
  },
  {
    "path": "app/controllers/concerns/impersonatable.rb",
    "chars": 538,
    "preview": "module Impersonatable\n  extend ActiveSupport::Concern\n\n  included do\n    after_action :create_impersonation_session_log\n"
  },
  {
    "path": "app/controllers/concerns/invitable.rb",
    "chars": 384,
    "preview": "module Invitable\n  extend ActiveSupport::Concern\n\n  included do\n    helper_method :invite_code_required?\n  end\n\n  privat"
  },
  {
    "path": "app/controllers/concerns/localize.rb",
    "chars": 438,
    "preview": "module Localize\n  extend ActiveSupport::Concern\n\n  included do\n    around_action :switch_locale\n    around_action :switc"
  },
  {
    "path": "app/controllers/concerns/notifiable.rb",
    "chars": 1592,
    "preview": "module Notifiable\n  extend ActiveSupport::Concern\n\n  included do\n    helper_method :render_flash_notifications\n    helpe"
  },
  {
    "path": "app/controllers/concerns/onboardable.rb",
    "chars": 1162,
    "preview": "module Onboardable\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :require_onboarding_and_upgrade\n  en"
  },
  {
    "path": "app/controllers/concerns/periodable.rb",
    "chars": 295,
    "preview": "module Periodable\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :set_period\n  end\n\n  private\n    def "
  },
  {
    "path": "app/controllers/concerns/restore_layout_preferences.rb",
    "chars": 589,
    "preview": "module RestoreLayoutPreferences\n  extend ActiveSupport::Concern\n\n  included do\n    before_action :restore_active_tabs\n  "
  },
  {
    "path": "app/controllers/concerns/self_hostable.rb",
    "chars": 1018,
    "preview": "module SelfHostable\n  extend ActiveSupport::Concern\n\n  included do\n    helper_method :self_hosted?, :self_hosted_first_l"
  },
  {
    "path": "app/controllers/concerns/store_location.rb",
    "chars": 793,
    "preview": "module StoreLocation\n  extend ActiveSupport::Concern\n\n  included do\n    helper_method :previous_path\n    before_action :"
  },
  {
    "path": "app/controllers/concerns/stream_extensions.rb",
    "chars": 686,
    "preview": "module StreamExtensions\n  extend ActiveSupport::Concern\n\n  def stream_redirect_to(path, notice: nil, alert: nil)\n    cus"
  },
  {
    "path": "app/controllers/cookie_sessions_controller.rb",
    "chars": 550,
    "preview": "class CookieSessionsController < ApplicationController\n  def update\n    save_kv_to_session(\n      cookie_session_params["
  },
  {
    "path": "app/controllers/credit_cards_controller.rb",
    "chars": 229,
    "preview": "class CreditCardsController < ApplicationController\n  include AccountableResource\n\n  permitted_accountable_attributes(\n "
  },
  {
    "path": "app/controllers/cryptos_controller.rb",
    "chars": 82,
    "preview": "class CryptosController < ApplicationController\n  include AccountableResource\nend\n"
  },
  {
    "path": "app/controllers/currencies_controller.rb",
    "chars": 235,
    "preview": "class CurrenciesController < ApplicationController\n  def show\n    currency = Money::Currency.all_instances.find { |curre"
  },
  {
    "path": "app/controllers/current_sessions_controller.rb",
    "chars": 385,
    "preview": "class CurrentSessionsController < ApplicationController\n  def update\n    if session_params[:tab_key].present? && session"
  },
  {
    "path": "app/controllers/depositories_controller.rb",
    "chars": 88,
    "preview": "class DepositoriesController <  ApplicationController\n  include AccountableResource\nend\n"
  },
  {
    "path": "app/controllers/email_confirmations_controller.rb",
    "chars": 553,
    "preview": "class EmailConfirmationsController < ApplicationController\n  skip_before_action :set_request_details, only: :new\n  skip_"
  },
  {
    "path": "app/controllers/family_exports_controller.rb",
    "chars": 1216,
    "preview": "class FamilyExportsController < ApplicationController\n  include StreamExtensions\n\n  before_action :require_admin\n  befor"
  },
  {
    "path": "app/controllers/family_merchants_controller.rb",
    "chars": 1435,
    "preview": "class FamilyMerchantsController < ApplicationController\n  before_action :set_merchant, only: %i[edit update destroy]\n\n  "
  },
  {
    "path": "app/controllers/holdings_controller.rb",
    "chars": 753,
    "preview": "class HoldingsController < ApplicationController\n  before_action :set_holding, only: %i[show destroy]\n\n  def index\n    @"
  },
  {
    "path": "app/controllers/impersonation_sessions_controller.rb",
    "chars": 1821,
    "preview": "class ImpersonationSessionsController < ApplicationController\n  before_action :require_super_admin!, only: [ :create, :j"
  },
  {
    "path": "app/controllers/import/cleans_controller.rb",
    "chars": 555,
    "preview": "class Import::CleansController < ApplicationController\n  layout \"imports\"\n\n  before_action :set_import\n\n  def show\n    r"
  },
  {
    "path": "app/controllers/import/configurations_controller.rb",
    "chars": 1029,
    "preview": "class Import::ConfigurationsController < ApplicationController\n  layout \"imports\"\n\n  before_action :set_import\n\n  def sh"
  },
  {
    "path": "app/controllers/import/confirms_controller.rb",
    "chars": 462,
    "preview": "class Import::ConfirmsController < ApplicationController\n  layout \"imports\"\n\n  before_action :set_import\n\n  def show\n   "
  },
  {
    "path": "app/controllers/import/mappings_controller.rb",
    "chars": 1054,
    "preview": "class Import::MappingsController < ApplicationController\n  before_action :set_import\n\n  def update\n    mapping = @import"
  },
  {
    "path": "app/controllers/import/rows_controller.rb",
    "chars": 549,
    "preview": "class Import::RowsController < ApplicationController\n  before_action :set_import_row\n\n  def update\n    @row.update_and_s"
  },
  {
    "path": "app/controllers/import/uploads_controller.rb",
    "chars": 1446,
    "preview": "class Import::UploadsController < ApplicationController\n  layout \"imports\"\n\n  before_action :set_import\n\n  def show\n  en"
  },
  {
    "path": "app/controllers/imports_controller.rb",
    "chars": 1943,
    "preview": "class ImportsController < ApplicationController\n  before_action :set_import, only: %i[show publish destroy revert apply_"
  },
  {
    "path": "app/controllers/investments_controller.rb",
    "chars": 86,
    "preview": "class InvestmentsController < ApplicationController\n  include AccountableResource\nend\n"
  },
  {
    "path": "app/controllers/invitations_controller.rb",
    "chars": 1408,
    "preview": "class InvitationsController < ApplicationController\n  skip_authentication only: :accept\n  def new\n    @invitation = Invi"
  },
  {
    "path": "app/controllers/invite_codes_controller.rb",
    "chars": 453,
    "preview": "class InviteCodesController < ApplicationController\n  before_action :ensure_self_hosted\n\n  def index\n    @invite_codes ="
  },
  {
    "path": "app/controllers/loans_controller.rb",
    "chars": 189,
    "preview": "class LoansController < ApplicationController\n  include AccountableResource\n\n  permitted_accountable_attributes(\n    :id"
  },
  {
    "path": "app/controllers/lookbooks_controller.rb",
    "chars": 81,
    "preview": "class LookbooksController < Lookbook::PreviewController\n  layout \"lookbooks\"\nend\n"
  },
  {
    "path": "app/controllers/messages_controller.rb",
    "chars": 533,
    "preview": "class MessagesController < ApplicationController\n  guard_feature unless: -> { Current.user.ai_enabled? }\n\n  before_actio"
  },
  {
    "path": "app/controllers/mfa_controller.rb",
    "chars": 1289,
    "preview": "class MfaController < ApplicationController\n  layout :determine_layout\n  skip_authentication only: [ :verify, :verify_co"
  },
  {
    "path": "app/controllers/onboardings_controller.rb",
    "chars": 383,
    "preview": "class OnboardingsController < ApplicationController\n  layout \"wizard\"\n\n  before_action :set_user\n  before_action :load_i"
  },
  {
    "path": "app/controllers/other_assets_controller.rb",
    "chars": 86,
    "preview": "class OtherAssetsController < ApplicationController\n  include AccountableResource\nend\n"
  },
  {
    "path": "app/controllers/other_liabilities_controller.rb",
    "chars": 91,
    "preview": "class OtherLiabilitiesController < ApplicationController\n  include AccountableResource\nend\n"
  },
  {
    "path": "app/controllers/pages_controller.rb",
    "chars": 5446,
    "preview": "class PagesController < ApplicationController\n  include Periodable\n\n  skip_authentication only: :redis_configuration_err"
  },
  {
    "path": "app/controllers/password_resets_controller.rb",
    "chars": 1006,
    "preview": "class PasswordResetsController < ApplicationController\n  skip_authentication\n\n  layout \"auth\"\n\n  before_action :set_user"
  },
  {
    "path": "app/controllers/passwords_controller.rb",
    "chars": 426,
    "preview": "class PasswordsController < ApplicationController\n  def edit\n  end\n\n  def update\n    if Current.user.update(password_par"
  },
  {
    "path": "app/controllers/plaid_items_controller.rb",
    "chars": 1939,
    "preview": "class PlaidItemsController < ApplicationController\n  before_action :set_plaid_item, only: %i[edit destroy sync]\n\n  def n"
  },
  {
    "path": "app/controllers/properties_controller.rb",
    "chars": 2589,
    "preview": "class PropertiesController < ApplicationController\n  include AccountableResource, StreamExtensions\n\n  before_action :set"
  },
  {
    "path": "app/controllers/registrations_controller.rb",
    "chars": 2427,
    "preview": "class RegistrationsController < ApplicationController\n  skip_authentication\n\n  layout \"auth\"\n\n  before_action :set_user,"
  },
  {
    "path": "app/controllers/rules_controller.rb",
    "chars": 2145,
    "preview": "class RulesController < ApplicationController\n  include StreamExtensions\n\n  before_action :set_rule, only: [  :edit, :up"
  },
  {
    "path": "app/controllers/securities_controller.rb",
    "chars": 204,
    "preview": "class SecuritiesController < ApplicationController\n  def index\n    @securities = Security.search_provider(\n      params["
  },
  {
    "path": "app/controllers/sessions_controller.rb",
    "chars": 803,
    "preview": "class SessionsController < ApplicationController\n  before_action :set_session, only: :destroy\n  skip_authentication only"
  },
  {
    "path": "app/controllers/settings/api_keys_controller.rb",
    "chars": 1805,
    "preview": "# frozen_string_literal: true\n\nclass Settings::ApiKeysController < ApplicationController\n  layout \"settings\"\n\n  before_a"
  },
  {
    "path": "app/controllers/settings/billings_controller.rb",
    "chars": 130,
    "preview": "class Settings::BillingsController < ApplicationController\n  layout \"settings\"\n\n  def show\n    @family = Current.family\n"
  },
  {
    "path": "app/controllers/settings/hostings_controller.rb",
    "chars": 1349,
    "preview": "class Settings::HostingsController < ApplicationController\n  layout \"settings\"\n\n  guard_feature unless: -> { self_hosted"
  },
  {
    "path": "app/controllers/settings/preferences_controller.rb",
    "chars": 129,
    "preview": "class Settings::PreferencesController < ApplicationController\n  layout \"settings\"\n\n  def show\n    @user = Current.user\n "
  },
  {
    "path": "app/controllers/settings/profiles_controller.rb",
    "chars": 971,
    "preview": "class Settings::ProfilesController < ApplicationController\n  layout \"settings\"\n\n  def show\n    @user = Current.user\n    "
  },
  {
    "path": "app/controllers/settings/securities_controller.rb",
    "chars": 103,
    "preview": "class Settings::SecuritiesController < ApplicationController\n  layout \"settings\"\n\n  def show\n  end\nend\n"
  },
  {
    "path": "app/controllers/subscriptions_controller.rb",
    "chars": 2197,
    "preview": "class SubscriptionsController < ApplicationController\n  # Disables subscriptions for self hosted instances\n  guard_featu"
  },
  {
    "path": "app/controllers/tag/deletions_controller.rb",
    "chars": 498,
    "preview": "class Tag::DeletionsController < ApplicationController\n  before_action :set_tag\n  before_action :set_replacement_tag, on"
  },
  {
    "path": "app/controllers/tags_controller.rb",
    "chars": 1018,
    "preview": "class TagsController < ApplicationController\n  before_action :set_tag, only: %i[edit update destroy]\n\n  def index\n    @t"
  },
  {
    "path": "app/controllers/trades_controller.rb",
    "chars": 2613,
    "preview": "class TradesController < ApplicationController\n  include EntryableResource\n\n  # Defaults to a buy trade\n  def new\n    @a"
  },
  {
    "path": "app/controllers/transaction_categories_controller.rb",
    "chars": 1533,
    "preview": "class TransactionCategoriesController < ApplicationController\n  include ActionView::RecordIdentifier\n\n  def update\n    @"
  },
  {
    "path": "app/controllers/transactions/bulk_deletions_controller.rb",
    "chars": 458,
    "preview": "class Transactions::BulkDeletionsController < ApplicationController\n  def create\n    destroyed = Current.family.entries."
  },
  {
    "path": "app/controllers/transactions/bulk_updates_controller.rb",
    "chars": 542,
    "preview": "class Transactions::BulkUpdatesController < ApplicationController\n  def new\n  end\n\n  def create\n    updated = Current.fa"
  },
  {
    "path": "app/controllers/transactions_controller.rb",
    "chars": 5712,
    "preview": "class TransactionsController < ApplicationController\n  include EntryableResource\n\n  before_action :store_params!, only: "
  },
  {
    "path": "app/controllers/transfer_matches_controller.rb",
    "chars": 2195,
    "preview": "class TransferMatchesController < ApplicationController\n  before_action :set_entry\n\n  def new\n    @accounts = Current.fa"
  },
  {
    "path": "app/controllers/transfers_controller.rb",
    "chars": 2304,
    "preview": "class TransfersController < ApplicationController\n  include StreamExtensions\n\n  before_action :set_transfer, only: %i[sh"
  },
  {
    "path": "app/controllers/users_controller.rb",
    "chars": 3206,
    "preview": "class UsersController < ApplicationController\n  before_action :set_user\n  before_action :ensure_admin, only: :reset\n\n  d"
  },
  {
    "path": "app/controllers/valuations_controller.rb",
    "chars": 2601,
    "preview": "class ValuationsController < ApplicationController\n  include EntryableResource, StreamExtensions\n\n  def confirm_create\n "
  },
  {
    "path": "app/controllers/vehicles_controller.rb",
    "chars": 185,
    "preview": "class VehiclesController < ApplicationController\n  include AccountableResource\n\n  permitted_accountable_attributes(\n    "
  },
  {
    "path": "app/controllers/webhooks_controller.rb",
    "chars": 1791,
    "preview": "class WebhooksController < ApplicationController\n  skip_before_action :verify_authenticity_token\n  skip_authentication\n\n"
  },
  {
    "path": "app/data_migrations/balance_component_migrator.rb",
    "chars": 2285,
    "preview": "class BalanceComponentMigrator\n  def self.run\n    ActiveRecord::Base.transaction do\n      # Step 1: Update flows factor\n"
  },
  {
    "path": "app/helpers/accounts_helper.rb",
    "chars": 164,
    "preview": "module AccountsHelper\n  def summary_card(title:, &block)\n    content = capture(&block)\n    render \"accounts/summary_card"
  },
  {
    "path": "app/helpers/application_helper.rb",
    "chars": 3466,
    "preview": "module ApplicationHelper\n  include Pagy::Frontend\n\n  def styled_form_with(**options, &block)\n    options[:builder] = Sty"
  },
  {
    "path": "app/helpers/categories_helper.rb",
    "chars": 535,
    "preview": "module CategoriesHelper\n  def transfer_category\n    Category.new \\\n      name: \"Transfer\",\n      color: Category::TRANSF"
  },
  {
    "path": "app/helpers/chats_helper.rb",
    "chars": 275,
    "preview": "module ChatsHelper\n  def chat_frame\n    :sidebar_chat\n  end\n\n  def chat_view_path(chat)\n    return new_chat_path if para"
  },
  {
    "path": "app/helpers/custom_confirm.rb",
    "chars": 1327,
    "preview": "# The shape of data expected by `confirm_dialog_controller.js` to override the\n# default browser confirm API via Turbo.\n"
  },
  {
    "path": "app/helpers/entries_helper.rb",
    "chars": 1200,
    "preview": "module EntriesHelper\n  def entries_by_date(entries, totals: false)\n    transfer_groups = entries.group_by do |entry|\n   "
  },
  {
    "path": "app/helpers/imports_helper.rb",
    "chars": 2122,
    "preview": "module ImportsHelper\n  def mapping_label(mapping_class)\n    {\n      \"Import::AccountTypeMapping\" => \"Account Type\",\n    "
  },
  {
    "path": "app/helpers/languages_helper.rb",
    "chars": 9097,
    "preview": "module LanguagesHelper\n  LANGUAGE_MAPPING = {\n    en: \"English\",\n    ru: \"Russian\",\n    ar: \"Arabic\",\n    bg: \"Bulgarian"
  },
  {
    "path": "app/helpers/mfa_helper.rb",
    "chars": 546,
    "preview": "module MfaHelper\n  def generate_mfa_qr_code(provisioning_uri)\n    qr_code = RQRCode::QRCode.new(provisioning_uri).as_svg"
  },
  {
    "path": "app/helpers/settings_helper.rb",
    "chars": 2323,
    "preview": "module SettingsHelper\n  SETTINGS_ORDER = [\n    { name: \"Account\", path: :settings_profile_path },\n    { name: \"Preferenc"
  },
  {
    "path": "app/helpers/styled_form_builder.rb",
    "chars": 4630,
    "preview": "class StyledFormBuilder < ActionView::Helpers::FormBuilder\n  class_attribute :text_field_helpers, default: field_helpers"
  },
  {
    "path": "app/helpers/transactions_helper.rb",
    "chars": 726,
    "preview": "module TransactionsHelper\n  def transaction_search_filters\n    [\n      { key: \"account_filter\", label: \"Account\", icon: "
  },
  {
    "path": "app/javascript/application.js",
    "chars": 236,
    "preview": "// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails\nimport \"@hotwir"
  },
  {
    "path": "app/javascript/controllers/app_layout_controller.js",
    "chars": 1683,
    "preview": "import { Controller } from \"@hotwired/stimulus\";\n\n// Connects to data-controller=\"dialog\"\nexport default class extends C"
  },
  {
    "path": "app/javascript/controllers/application.js",
    "chars": 489,
    "preview": "import { Application } from \"@hotwired/stimulus\";\n\nconst application = Application.start();\n\n// Configure Stimulus devel"
  },
  {
    "path": "app/javascript/controllers/auto_submit_form_controller.js",
    "chars": 2436,
    "preview": "import { Controller } from \"@hotwired/stimulus\";\n\nexport default class extends Controller {\n  // By default, auto-submit"
  },
  {
    "path": "app/javascript/controllers/budget_form_controller.js",
    "chars": 716,
    "preview": "import { Controller } from \"@hotwired/stimulus\";\n\n// Connects to data-controller=\"budget-form\"\nexport default class exte"
  }
]

// ... and 1378 more files (download for full content)

About this extraction

This page contains the full source code of the maybe-finance/maybe GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1578 files (3.5 MB), approximately 1.0M tokens, and a symbol index with 4709 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!