@@ -12,7 +12,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
1212### Testing
1313- ` bin/rails test ` - Run all tests
1414- ` bin/rails test:db ` - Run tests with database reset
15- - ` bin/rails test:system ` - Run system tests only
15+ - ` bin/rails test:system ` - Run system tests only (use sparingly - they take longer)
1616- ` bin/rails test test/models/account_test.rb ` - Run specific test file
1717- ` bin/rails test test/models/account_test.rb:42 ` - Run specific test at line
1818
@@ -32,6 +32,23 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
3232### Setup
3333- ` bin/setup ` - Initial project setup (installs dependencies, prepares database)
3434
35+ ## Pre-Pull Request CI Workflow
36+
37+ ALWAYS run these commands before opening a pull request:
38+
39+ 1 . ** Tests** (Required):
40+ - ` bin/rails test ` - Run all tests (always required)
41+ - ` bin/rails test:system ` - Run system tests (only when applicable, they take longer)
42+
43+ 2 . ** Linting** (Required):
44+ - ` bin/rubocop -f github -a ` - Ruby linting with auto-correct
45+ - ` bundle exec erb_lint ./app/**/*.erb -a ` - ERB linting with auto-correct
46+
47+ 3 . ** Security** (Required):
48+ - ` bin/brakeman --no-pager ` - Security analysis
49+
50+ Only proceed with pull request creation if ALL checks pass.
51+
3552## General Development Rules
3653
3754### Authentication Context
@@ -110,13 +127,6 @@ Sidekiq handles asynchronous tasks:
110127- Scoped permissions system for API access
111128- Strong parameters and CSRF protection throughout
112129
113- ### Key Service Objects & Patterns
114- - ** Query Objects** : Complex database queries isolated in ` app/queries/ `
115- - ** Service Objects** : Business logic in ` app/services/ `
116- - ** Form Objects** : Complex forms with validation
117- - ** Concerns** : Shared functionality across models/controllers
118- - ** Jobs** : Background processing logic
119-
120130### Testing Philosophy
121131- Comprehensive test coverage using Rails' built-in Minitest
122132- Fixtures for test data (avoid FactoryBot)
@@ -145,28 +155,119 @@ Sidekiq handles asynchronous tasks:
145155
146156### Convention 1: Minimize Dependencies
147157- Push Rails to its limits before adding new dependencies
148- - When adding dependencies, favor old and reliable over new and flashy
149- - Strong technical or business reason required for new dependencies
150-
151- ### Convention 2: POROs and Concerns over Service Objects
152- - "Skinny controller, fat models" convention
153- - Everything in ` app/models/ ` folder, avoid separate folders like ` app/services/ `
154- - Use Rails concerns for better organization (can be one-off concerns)
155- - Models should answer questions about themselves (e.g., ` account.balance_series ` )
156-
157- ### Convention 3: Leverage Hotwire and Server-Side Solutions
158- - Native HTML preferred over JS components (e.g., ` <dialog> ` , ` <details> ` )
159- - Use Turbo frames to break up pages
160- - Leverage query params for state over local storage
161- - Format values server -side, pass to Stimulus for display only
162- - Client-side code only where it truly shines (e.g., bulk selections)
163-
164- ### Convention 4: Optimize for Simplicity and Clarity
158+ - Strong technical/business reason required for new dependencies
159+ - Favor old and reliable over new and flashy
160+
161+ ### Convention 2: Skinny Controllers, Fat Models
162+ - Business logic in ` app/ models/ ` folder, avoid ` app/services/ `
163+ - Use Rails concerns and POROs for organization
164+ - Models should answer questions about themselves: ` account.balance_series ` not ` AccountSeries.new(account).call `
165+
166+ ### Convention 3: Hotwire-First Frontend
167+ - ** Native HTML preferred over JS components **
168+ - Use ` <dialog> ` for modals , ` <details><summary> ` for disclosures
169+ - ** Leverage Turbo frames** for page sections over client-side solutions
170+ - ** Query params for state** over localStorage/sessions
171+ - ** Server -side formatting ** for currencies, numbers, dates
172+ - ** Always use ` icon ` helper ** in ` application_helper.rb ` , NEVER ` lucide_icon ` directly
173+
174+ ### Convention 4: Optimize for Simplicity
165175- Prioritize good OOP domain design over performance
166- - Only focus on performance in critical/global areas
167- - Be mindful of N+1 queries and large data payloads
176+ - Focus performance only on critical/global areas (avoid N+1 queries, mindful of global layouts)
177+
178+ ### Convention 5: Database vs ActiveRecord Validations
179+ - Simple validations (null checks, unique indexes) in DB
180+ - ActiveRecord validations for convenience in forms (prefer client-side when possible)
181+ - Complex validations and business logic in ActiveRecord
182+
183+ ## TailwindCSS Design System
184+
185+ ### Design System Rules
186+ - ** Always reference ` app/assets/tailwind/maybe-design-system.css ` ** for primitives and tokens
187+ - ** Use functional tokens** defined in design system:
188+ - ` text-primary ` instead of ` text-white `
189+ - ` bg-container ` instead of ` bg-white `
190+ - ` border border-primary ` instead of ` border border-gray-200 `
191+ - ** NEVER create new styles** in design system files without permission
192+ - ** Always generate semantic HTML**
193+
194+ ## Component Architecture
195+
196+ ### ViewComponent vs Partials Decision Making
197+
198+ ** Use ViewComponents when:**
199+ - Element has complex logic or styling patterns
200+ - Element will be reused across multiple views/contexts
201+ - Element needs structured styling with variants/sizes
202+ - Element requires interactive behavior or Stimulus controllers
203+ - Element has configurable slots or complex APIs
204+ - Element needs accessibility features or ARIA support
205+
206+ ** Use Partials when:**
207+ - Element is primarily static HTML with minimal logic
208+ - Element is used in only one or few specific contexts
209+ - Element is simple template content
210+ - Element doesn't need variants, sizes, or complex configuration
211+ - Element is more about content organization than reusable functionality
212+
213+ ** Component Guidelines:**
214+ - Prefer components over partials when available
215+ - Keep domain logic OUT of view templates
216+ - Logic belongs in component files, not template files
217+
218+ ### Stimulus Controller Guidelines
219+
220+ ** Declarative Actions (Required):**
221+ ``` erb
222+ <!-- GOOD: Declarative - HTML declares what happens -->
223+ <div data-controller="toggle">
224+ <button data-action="click->toggle#toggle" data-toggle-target="button">Show</button>
225+ <div data-toggle-target="content" class="hidden">Hello World!</div>
226+ </div>
227+ ```
228+
229+ ** Controller Best Practices:**
230+ - Keep controllers lightweight and simple (< 7 targets)
231+ - Use private methods and expose clear public API
232+ - Single responsibility or highly related responsibilities
233+ - Component controllers stay in component directory, global controllers in ` app/javascript/controllers/ `
234+ - Pass data via ` data-*-value ` attributes, not inline JavaScript
235+
236+ ## Testing Philosophy
237+
238+ ### General Testing Rules
239+ - ** ALWAYS use Minitest + fixtures** (NEVER RSpec or factories)
240+ - Keep fixtures minimal (2-3 per model for base cases)
241+ - Create edge cases on-the-fly within test context
242+ - Use Rails helpers for large fixture creation needs
243+
244+ ### Test Quality Guidelines
245+ - ** Write minimal, effective tests** - system tests sparingly
246+ - ** Only test critical and important code paths**
247+ - ** Test boundaries correctly:**
248+ - Commands: test they were called with correct params
249+ - Queries: test output
250+ - Don't test implementation details of other classes
251+
252+ ### Testing Examples
253+
254+ ``` ruby
255+ # GOOD - Testing critical domain business logic
256+ test " syncs balances" do
257+ Holding ::Syncer .any_instance.expects(:sync_holdings ).returns([]).once
258+ assert_difference " @account.balances.count" , 2 do
259+ Balance ::Syncer .new (@account , strategy: :forward ).sync_balances
260+ end
261+ end
262+
263+ # BAD - Testing ActiveRecord functionality
264+ test " saves balance" do
265+ balance_record = Balance .new (balance: 100 , currency: " USD" )
266+ assert balance_record.save
267+ end
268+ ```
168269
169- ### Convention 5: ActiveRecord for Complex Validations, DB for Simple Ones
170- - Enforce null checks, unique indexes in the DB
171- - ActiveRecord validations for convenience in forms
172- - Complex validations and business logic in ActiveRecord
270+ ### Stubs and Mocks
271+ - Use ` mocha ` gem
272+ - Prefer ` OpenStruct ` for mock instances
273+ - Only mock what's necessary
0 commit comments