Skip to content

Latest commit

 

History

History
105 lines (77 loc) · 4.33 KB

File metadata and controls

105 lines (77 loc) · 4.33 KB

CLAUDE.md

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

Common Commands

Development

bin/dev                          # Start Rails + Vite dev servers (via Procfile.dev)
bin/rails db:setup               # Create and seed database

Testing

bin/rails test                   # Run unit/integration tests
bin/rails test:system            # Run Capybara system tests (requires Chrome)
bin/rails test test/path/to/test_file.rb  # Run a single test file
bin/rails test test/path/to/test_file.rb:42  # Run a single test at line

Linting & Formatting

bin/rubocop                      # Lint Ruby (Rails Omakase style)
bin/rubocop -a                   # Auto-fix Ruby offenses
npm run lint                     # Lint TypeScript with Biome
npm run lint:fix                 # Auto-fix TypeScript
npm run format                   # Format frontend code
npm run check                    # TypeScript type checking

Security

bin/brakeman                     # Rails security scan
bin/bundler-audit                # Gem vulnerability audit

Type Generation

bin/rails types_from_serializers:generate  # Regenerate TypeScript types from serializers

Architecture Overview

Backend → Frontend Data Flow

This app uses Inertia.js to bridge Rails and React — no traditional API. Controllers render Inertia responses (not JSON or HTML views), passing serialized data as props directly to React page components.

  1. Rails controller calls render inertia: 'ComponentName', props: { data: serializer.new(record) }
  2. InertiaController (base controller) shares flash and authenticated user props on every request
  3. Serializers (in app/serializers/) use oj_serializers and transform keys to camelCase for React
  4. types_from_serializers gem generates TypeScript types from serializers — run the rake task after modifying serializers
  5. React page components receive typed props and render without additional API calls

Page Components

React pages live in app/frontend/pages/ and are resolved by name in app/frontend/entrypoints/inertia.tsx. Each page file name matches the component name passed to render inertia:.

Routing

Routes are split into modular files under config/routes/:

  • public.rb — unauthenticated pages
  • devise.rb — auth routes
  • demo.rb — demo/example routes
  • items.rb — CRUD resource routes

JS route helpers are generated by the js-routes gem and available in app/frontend/lib/.

Authentication & Authorization

  • Devise handles authentication (email/password + Google OAuth2)
  • ActionPolicy handles authorization via policy classes in app/policies/
  • Controllers call authorize! before actions; authorized_scope for collections
  • ItemPolicy restricts all CRUD to the record owner via owner? predicate

Key Patterns

Soft deletes: Item uses the Discard gem. A default_scope filters to kept records — use Item.with_discarded to include soft-deleted records.

Audit trail: Item has has_paper_trail — all changes are stored in the versions table with whodunnit (user ID).

Serialization: Extend BaseSerializer which auto-converts keys to camelCase. Add new serializers here when exposing new models to the frontend. The BaseSerializer is in app/serializers/base_serializer.rb.

Pagination: Use Pagy for collections. Pass @pagy metadata via PagySerializer to the frontend.

Frontend imports: Use @/ or ~/ path aliases (both resolve to app/frontend/).

Tech Stack

Layer Technology
Backend Rails 8.1, Ruby 3.3
Frontend React 19, TypeScript 5, Vite 7
Styling Tailwind CSS v4
UI components Radix UI + shadcn/ui pattern
DB (dev/test) SQLite (separate DBs for cache/queue/cable)
Auth Devise + OmniAuth Google
Authorization ActionPolicy
Background jobs Solid Queue + Mission Control Jobs
Linting (Ruby) RuboCop (Rails Omakase)
Linting (JS) Biome (single quotes, no semicolons, 100 char width)
Git hooks Lefthook (auto-format on commit, test on push)

Environment Variables

See .env.example for all required variables. Key ones for local development: APP_HOST, APP_PORT, and Google OAuth credentials (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET).