11 KiB
11 KiB
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 onlybin/rails console- Open Rails console
Testing
bin/rails test- Run all testsbin/rails test:db- Run tests with database resetbin/rails test:system- Run system tests only (use sparingly - they take longer)bin/rails test test/models/account_test.rb- Run specific test filebin/rails test test/models/account_test.rb:42- Run specific test at line
Linting & Formatting
bin/rubocop- Run Ruby linternpm run lint- Check JavaScript/TypeScript codenpm run lint:fix- Fix JavaScript/TypeScript issuesnpm run format- Format JavaScript/TypeScript codebin/brakeman- Run security analysis
Database
bin/rails db:prepare- Create and migrate databasebin/rails db:migrate- Run pending migrationsbin/rails db:rollback- Rollback last migrationbin/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:
-
Tests (Required):
bin/rails test- Run all tests (always required)bin/rails test:system- Run system tests (only when applicable, they take longer)
-
Linting (Required):
bin/rubocop -f github -a- Ruby linting with auto-correctbundle exec erb_lint ./app/**/*.erb -a- ERB linting with auto-correct
-
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.userfor the current user. Do NOT usecurrent_user. - Use
Current.familyfor the current family. Do NOT usecurrent_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 serverin 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:
- Plaid Integration: Real-time bank account syncing
PlaidItemmanages connectionsSynctracks sync operations- Background jobs handle data updates
- CSV Import: Manual data import with mapping
Importmanages 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-primarynottext-white) - Prefer semantic HTML elements over JS components
- Use
iconhelper for icons, neverlucide_icondirectly
- Design system defined in
Multi-Currency Support
- All monetary values stored in base currency (user's primary currency)
- Exchange rates fetched from Synth API
Moneyobjects 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
.envfiles - 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, avoidapp/services/ - Use Rails concerns and POROs for organization
- Models should answer questions about themselves:
account.balance_seriesnotAccountSeries.new(account).call
Convention 3: Hotwire-First Frontend
- Native HTML preferred over JS components
- Use
<dialog>for modals,<details><summary>for disclosures
- Use
- 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
iconhelper inapplication_helper.rb, NEVERlucide_icondirectly
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.cssfor primitives and tokens - Use functional tokens defined in design system:
text-primaryinstead oftext-whitebg-containerinstead ofbg-whiteborder border-primaryinstead ofborder 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):
<!-- 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-*-valueattributes, 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
# 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
mochagem - Prefer
OpenStructfor mock instances - Only mock what's necessary