Files
maybe/CLAUDE.md
Josh Pigford b803ddac96 Add comprehensive API v1 with OAuth and API key authentication (#2389)
* OAuth

* Add API test routes and update Doorkeeper token handling for test environment

- Introduced API namespace with test routes for controller testing in the test environment.
- Updated Doorkeeper configuration to allow fallback to plain tokens in the test environment for easier testing.
- Modified schema to change resource_owner_id type from bigint to string.

* Implement API key authentication and enhance access control

- Replaced Doorkeeper OAuth authentication with a custom method supporting both OAuth and API keys in the BaseController.
- Added methods for API key authentication, including validation and logging.
- Introduced scope-based authorization for API keys in the TestController.
- Updated routes to include API key management endpoints.
- Enhanced logging for API access to include authentication method details.
- Added tests for API key functionality, including validation, scope checks, and access control enforcement.

* Add API key rate limiting and usage tracking

- Implemented rate limiting for API key authentication in BaseController.
- Added methods to check rate limits, render appropriate responses, and include rate limit headers in responses.
- Updated routes to include a new usage resource for tracking API usage.
- Enhanced tests to verify rate limit functionality, including exceeding limits and per-key tracking.
- Cleaned up Redis data in tests to ensure isolation between test cases.

* Add Jbuilder for JSON rendering and refactor AccountsController

- Added Jbuilder gem for improved JSON response handling.
- Refactored index action in AccountsController to utilize Jbuilder for rendering JSON.
- Removed manual serialization of accounts and streamlined response structure.
- Implemented a before_action in BaseController to enforce JSON format for all API requests.

* Add transactions resource to API routes

- Added routes for transactions, allowing index, show, create, update, and destroy actions.
- This enhancement supports comprehensive transaction management within the API.

* Enhance API authentication and onboarding handling

- Updated BaseController to skip onboarding requirements for API endpoints and added manual token verification for OAuth authentication.
- Improved error handling and logging for invalid access tokens.
- Introduced a method to set up the current context for API requests, ensuring compatibility with session-like behavior.
- Excluded API paths from onboarding redirects in the Onboardable concern.
- Updated database schema to change resource_owner_id type from bigint to string for OAuth access grants.

* Fix rubocop offenses

- Fix indentation and spacing issues
- Convert single quotes to double quotes
- Add spaces inside array brackets
- Fix comment alignment
- Add missing trailing newlines
- Correct else/end alignment

🤖 Generated with [Claude Code](https://claude.ai/code)

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

* Fix API test failures and improve test reliability

- Fix ApiRateLimiterTest by removing mock users method and using fixtures
- Fix UsageControllerTest by removing mock users method and using fixtures
- Fix BaseControllerTest by using different users for multiple API keys
- Use unique display_key values with SecureRandom to avoid conflicts
- Fix double render issue in UsageController by returning after authorize_scope\!
- Specify controller name in routes for usage resource
- Remove trailing whitespace and empty lines per Rubocop

All tests now pass and linting is clean.

🤖 Generated with [Claude Code](https://claude.ai/code)

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

* Add API transactions controller warning to brakeman ignore

The account_id parameter in the API transactions controller is properly
validated on line 79: family.accounts.find(transaction_params[:account_id])
This ensures users can only create transactions in accounts belonging to
their family, making this a false positive.

🤖 Generated with [Claude Code](https://claude.ai/code)

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

---------

Signed-off-by: Josh Pigford <josh@joshpigford.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-06-17 15:57:05 -05:00

7.3 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
  • 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)

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

Key Service Objects & Patterns

  • Query Objects: Complex database queries isolated in app/queries/
  • Service Objects: Business logic in app/services/
  • Form Objects: Complex forms with validation
  • Concerns: Shared functionality across models/controllers
  • Jobs: Background processing logic

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
  • When adding dependencies, favor old and reliable over new and flashy
  • Strong technical or business reason required for new dependencies

Convention 2: POROs and Concerns over Service Objects

  • "Skinny controller, fat models" convention
  • Everything in app/models/ folder, avoid separate folders like app/services/
  • Use Rails concerns for better organization (can be one-off concerns)
  • Models should answer questions about themselves (e.g., account.balance_series)

Convention 3: Leverage Hotwire and Server-Side Solutions

  • Native HTML preferred over JS components (e.g., <dialog>, <details>)
  • Use Turbo frames to break up pages
  • Leverage query params for state over local storage
  • Format values server-side, pass to Stimulus for display only
  • Client-side code only where it truly shines (e.g., bulk selections)

Convention 4: Optimize for Simplicity and Clarity

  • Prioritize good OOP domain design over performance
  • Only focus on performance in critical/global areas
  • Be mindful of N+1 queries and large data payloads

Convention 5: ActiveRecord for Complex Validations, DB for Simple Ones

  • Enforce null checks, unique indexes in the DB
  • ActiveRecord validations for convenience in forms
  • Complex validations and business logic in ActiveRecord