1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-18 20:59:39 +02:00
Maybe/CLAUDE.md
Zach Gollwitzer fcf14f5f27
Some checks failed
Publish Docker image / ci (push) Has been cancelled
Publish Docker image / Build docker image (push) Has been cancelled
Add pre-pull request flow for Claude code
2025-06-20 17:33:03 -04:00

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

<!-- 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

# 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