ariadna 1.1.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1ed375271ac768caefa266c693b81aabf5721cbe01cba600ba219a25594de3c
4
- data.tar.gz: 0253d51a13f639d93785d01bb72459020d42afceac232282c798975faf629bf4
3
+ metadata.gz: a59ce08ab4d7f1165dd59dac034ac04e5725263a3022bebbd2c3c39fdb0a3c23
4
+ data.tar.gz: 2eb175ba24a25c5114e3b76f83bbfef0275a21dc114f00d7376390508cb54a87
5
5
  SHA512:
6
- metadata.gz: ae19b2a21a2713c0e15f9dacc0d06a4306d47b3620b0e7c0ea78c87a109e11f35c6f396efb5e2b3b4e7ddf404f1db94cecf01df10144213911eadcb59cc6e360
7
- data.tar.gz: 580e4a7376e86aa30f705d1502264729c9be324711b0daa2f54caa1818acd42d67101859811b5d2a46a9ce321fbaacc74ddb08e6746ffd51165588723842843b
6
+ metadata.gz: 11f2127685615ea902f97bfc9fc813e20e74f354b055672568d39552d3d551d31896ba73b5ad3434d1ac84dc6d593f8d385818e78fc7cae24844f45720558f80
7
+ data.tar.gz: cec523e574d6182711229ddf5fa7519929f3c9fb9a144a0eb4928cf46a24d4761e9f718cf3678cf2dde812f9cd655647ca2c12776fcf29aa526831ad9df017a9
@@ -23,7 +23,7 @@ Load and follow the project's backend guide for domain-specific patterns:
23
23
  - **Models & Concerns:** Concern-driven architecture, intention-revealing APIs, smart association defaults
24
24
  - **Controllers:** Thin controllers delegating to rich models, RESTful resource nesting
25
25
  - **Jobs:** Ultra-thin jobs with _now/_later pattern, multi-tenancy context
26
- - **Migrations:** UUID primary keys, proper foreign key references
26
+ - **Migrations:** Proper foreign key references
27
27
  - **Configuration:** Rails conventions, initializers, routing
28
28
 
29
29
  **When executing backend tasks:**
@@ -17,6 +17,7 @@ Your job: Produce PLAN.md files that Claude executors can implement without inte
17
17
 
18
18
  **Core responsibilities:**
19
19
  - **FIRST: Parse and honor user decisions from CONTEXT.md** (locked decisions are NON-NEGOTIABLE)
20
+ - Use Rails conventions (from `rails-conventions.md`) for standard task decomposition
20
21
  - Decompose phases into parallel-optimized plans with 2-3 tasks each
21
22
  - Build dependency graphs and assign execution waves
22
23
  - Derive must-haves using goal-backward methodology
@@ -25,6 +26,33 @@ Your job: Produce PLAN.md files that Claude executors can implement without inte
25
26
  - Return structured results to orchestrator
26
27
  </role>
27
28
 
29
+ <rails_awareness>
30
+ ## Rails-Aware Planning
31
+
32
+ Load Rails conventions from your required reading for standard task decomposition patterns.
33
+
34
+ @~/.claude/ariadna/references/rails-conventions.md
35
+
36
+ **Use domain templates** for common Rails work:
37
+ - "Add model" → migration + model + tests + fixtures
38
+ - "Add controller" → routes + controller + views + tests
39
+ - "Add authentication" → auth scaffold + user model + session controller + tests
40
+ - "Add background job" → job class + model method + tests
41
+ - "Add mailer" → mailer + views + tests
42
+ - "Add Turbo/Hotwire feature" → Turbo Frame + controller response + Stimulus (if needed) + system test
43
+
44
+ **Known domains (skip discovery):** Models, Controllers, Views, Auth, Jobs, Email, File Uploads, Real-time, Testing, API Mode, Caching. See `rails-conventions.md` `<known_domains>` for the full list.
45
+
46
+ **Discovery only for:** External API integrations, novel gems, payment systems, or anything not in the known domains list.
47
+
48
+ **Pitfall prevention:** Apply common Rails pitfalls from `rails-conventions.md` proactively:
49
+ - Include `includes()` for associations in controller queries (N+1)
50
+ - Add database indexes in migration tasks
51
+ - Use strong_parameters in controller tasks
52
+ - Keep controllers thin, models rich
53
+ - Use background jobs for external calls
54
+ </rails_awareness>
55
+
28
56
  <context_fidelity>
29
57
  ## CRITICAL: User Decision Fidelity
30
58
 
@@ -180,7 +208,7 @@ Each task: **15-60 minutes** Claude execution time.
180
208
  | "Create the API" | "Create POST /projects endpoint in ProjectsController#create accepting {name, description}, validates name length 3-50 chars, returns 201 with project JSON" |
181
209
  | "Style the dashboard" | "Add CSS classes to dashboard view: grid layout (3 cols on lg via media query, 1 on mobile), card shadows via --shadow variable, hover states on action buttons per style guide" |
182
210
  | "Handle errors" | "Add rescue_from in ApplicationController, render JSON errors on 4xx/5xx, show flash messages on server-rendered pages" |
183
- | "Set up the database" | "Add User and Project models with UUID primary keys, email unique constraint, timestamps, run rails db:migrate" |
211
+ | "Set up the database" | "Add User and Project models, email unique constraint, timestamps, run rails db:migrate" |
184
212
 
185
213
  **Test:** Could a different Claude instance execute without asking clarifying questions? If not, add specificity.
186
214
 
@@ -21,7 +21,7 @@ Load and follow the project's testing guide for domain-specific patterns:
21
21
 
22
22
  **Focus areas:**
23
23
  - **Minitest conventions:** `ActiveSupport::TestCase` for models, `ActionDispatch::IntegrationTest` for controllers
24
- - **Fixtures:** YAML fixtures for deterministic test data, UUID-based fixture IDs
24
+ - **Fixtures:** YAML fixtures for deterministic test data
25
25
  - **Current context:** Always set `Current.session = sessions(:name)` in setup blocks
26
26
  - **assert_difference:** Use for state changes, nest for multiple record types
27
27
  - **Testing patterns:** Model tests for business logic, controller tests for delegation, job tests for enqueuing
@@ -0,0 +1,384 @@
1
+ <rails_conventions>
2
+
3
+ Pre-baked Rails knowledge for Ariadna planning and execution agents. This document replaces generic research for standard Rails projects, encoding well-known conventions, patterns, and pitfalls so agents don't need to web-search for common Rails patterns.
4
+
5
+ <standard_stack>
6
+
7
+ ## Standard Rails Stack (2025)
8
+
9
+ | Layer | Technology | Notes |
10
+ |-------|-----------|-------|
11
+ | Framework | Rails 8+ | Defaults to SQLite in dev, includes Solid Queue/Cache/Cable |
12
+ | Database | PostgreSQL (production) | SQLite for dev/test is fine for most projects |
13
+ | Background Jobs | Solid Queue | Rails 8 default, replaces Sidekiq for most cases |
14
+ | Caching | Solid Cache | Rails 8 default, database-backed cache |
15
+ | WebSockets | Action Cable + Solid Cable | Rails 8 default |
16
+ | Real-time UI | Turbo (Hotwire) | Turbo Drive, Frames, Streams |
17
+ | JS Sprinkles | Stimulus (Hotwire) | Controllers for interactive behavior |
18
+ | CSS | Tailwind CSS or Propshaft | Rails 8 defaults to Propshaft asset pipeline |
19
+ | Auth | Rails built-in `has_secure_password` or Devise | Rails 8 includes auth generator |
20
+ | Email | Action Mailer | Built-in |
21
+ | File Upload | Active Storage | Built-in |
22
+ | API | Rails API mode or Jbuilder | Built-in |
23
+ | Testing | Minitest | Rails default, use fixtures not factories |
24
+ | Linting | RuboCop + rubocop-rails | Standard community linting |
25
+
26
+ **What NOT to use (and why):**
27
+ - Factories (FactoryBot) when fixtures suffice — fixtures are faster, declarative, and Rails-native
28
+ - RSpec unless the project already uses it — Minitest is simpler and Rails-native
29
+ - Webpacker/Shakapacker — replaced by importmap-rails or jsbundling-rails
30
+ - Sprockets — replaced by Propshaft in Rails 8
31
+ - Redis for jobs/cache — Solid Queue/Cache use the database, simpler ops
32
+
33
+ </standard_stack>
34
+
35
+ <architecture_patterns>
36
+
37
+ ## Rails Architecture Patterns
38
+
39
+ ### MVC Foundation
40
+ - **Models:** Business logic lives here. Validations, scopes, callbacks, associations.
41
+ - **Controllers:** Thin. Receive request, call model, render response. 7 RESTful actions max.
42
+ - **Views:** ERB templates. Logic delegated to presenters or helpers.
43
+
44
+ ### Concern-Driven Architecture
45
+ ```
46
+ app/models/concerns/
47
+ shared/ # Cross-model concerns (Trackable, Searchable)
48
+ model_name/ # Model-specific concerns (User::Authenticatable)
49
+ ```
50
+
51
+ **When to extract a concern:**
52
+ - Behavior reused across 2+ models → shared concern
53
+ - Model file exceeds ~100 lines → model-specific concern
54
+ - Logical grouping of related methods → named concern
55
+
56
+ ### Service Objects (When Needed)
57
+ Use plain Ruby objects in `app/services/` for:
58
+ - Multi-model operations (CreateOrderWithPayment)
59
+ - External API integrations (StripeChargeService)
60
+ - Complex business processes spanning multiple steps
61
+
62
+ **Don't use for:** Simple CRUD, single-model operations, or anything a model method handles.
63
+
64
+ ### Presenter Pattern
65
+ Plain Ruby classes for complex view logic:
66
+ ```ruby
67
+ # app/models/dashboard_presenter.rb (NOT app/presenters/)
68
+ class DashboardPresenter
69
+ include ActionView::Helpers::TagHelper
70
+
71
+ def initialize(user)
72
+ @user = user
73
+ end
74
+
75
+ def greeting
76
+ "Welcome, #{@user.name}"
77
+ end
78
+ end
79
+ ```
80
+
81
+ ### RESTful Resource Design
82
+ - Prefer creating new controllers over adding custom actions
83
+ - `POST /messages/:id/archive` → `ArchivesController#create`
84
+ - Nest resources max 1 level: `/posts/:post_id/comments`
85
+ - Use `concerns` in routes for shared resource patterns
86
+
87
+ ### Current Attributes
88
+ ```ruby
89
+ # app/models/current.rb
90
+ class Current < ActiveSupport::CurrentAttributes
91
+ attribute :user, :session, :account
92
+ end
93
+ ```
94
+ Set in `ApplicationController`, access everywhere. No parameter passing for auth context.
95
+
96
+ </architecture_patterns>
97
+
98
+ <common_pitfalls>
99
+
100
+ ## Common Rails Pitfalls (with Prevention)
101
+
102
+ ### 1. N+1 Queries
103
+ **Problem:** Loading associated records in a loop.
104
+ **Prevention:** Use `includes`, `preload`, or `eager_load` in controllers. Add `strict_loading` to models in development.
105
+ ```ruby
106
+ # Bad
107
+ @posts = Post.all # then post.comments in view
108
+
109
+ # Good
110
+ @posts = Post.includes(:comments, :author).all
111
+ ```
112
+
113
+ ### 2. Missing Database Indexes
114
+ **Prevention:** Always add indexes for:
115
+ - Foreign keys (`add_index :posts, :user_id`)
116
+ - Columns used in `where` clauses
117
+ - Columns used in `order` clauses
118
+ - Unique constraints (`add_index :users, :email, unique: true`)
119
+
120
+ ### 3. Mass Assignment Vulnerabilities
121
+ **Prevention:** Always use `strong_parameters` in controllers.
122
+ ```ruby
123
+ def post_params
124
+ params.require(:post).permit(:title, :body, :published)
125
+ end
126
+ ```
127
+
128
+ ### 4. Callback Hell
129
+ **Prevention:** Limit callbacks to:
130
+ - `before_validation` for normalization (strip whitespace, downcase email)
131
+ - `after_create_commit` for async side effects (send email, broadcast)
132
+ - Avoid `after_save` chains that trigger cascading updates
133
+
134
+ ### 5. Fat Controllers
135
+ **Prevention:** Controllers should only:
136
+ 1. Authenticate/authorize
137
+ 2. Load/build the resource
138
+ 3. Call save/update/destroy
139
+ 4. Respond with redirect or render
140
+
141
+ ### 6. Missing Validations
142
+ **Prevention:** Validate at model level, not just in forms:
143
+ - Presence on required fields
144
+ - Uniqueness with database-level constraint
145
+ - Format for emails, URLs, phone numbers
146
+ - Numericality for quantities, prices
147
+
148
+ ### 7. Unscoped Queries (Multi-tenancy)
149
+ **Prevention:** Always scope queries to current user/account:
150
+ ```ruby
151
+ # Bad
152
+ Post.find(params[:id])
153
+
154
+ # Good
155
+ Current.user.posts.find(params[:id])
156
+ ```
157
+
158
+ ### 8. Missing Error Handling
159
+ **Prevention:** Add `rescue_from` in `ApplicationController`:
160
+ ```ruby
161
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found
162
+ rescue_from ActionController::ParameterMissing, with: :bad_request
163
+ ```
164
+
165
+ ### 9. Synchronous External Calls
166
+ **Prevention:** Always use background jobs for:
167
+ - Sending emails
168
+ - Calling external APIs
169
+ - Processing uploads
170
+ - Generating reports
171
+
172
+ ### 10. Missing CSRF Protection
173
+ **Prevention:** Rails enables CSRF by default. Don't disable `protect_from_forgery`. For API endpoints, use token auth instead.
174
+
175
+ </common_pitfalls>
176
+
177
+ <testing_patterns>
178
+
179
+ ## Rails Testing Patterns (Minitest)
180
+
181
+ ### Test Organization
182
+ ```
183
+ test/
184
+ models/ # Unit tests for models
185
+ controllers/ # Integration tests for request/response
186
+ system/ # Browser-based end-to-end tests
187
+ helpers/ # Helper method tests
188
+ jobs/ # Background job tests
189
+ mailers/ # Mailer tests
190
+ fixtures/ # YAML test data
191
+ test_helper.rb # Shared setup
192
+ ```
193
+
194
+ ### Fixtures Over Factories
195
+ ```yaml
196
+ # test/fixtures/users.yml
197
+ alice:
198
+ name: Alice
199
+ email: alice@example.com
200
+ password_digest: <%= BCrypt::Password.create('password') %>
201
+
202
+ bob:
203
+ name: Bob
204
+ email: bob@example.com
205
+ password_digest: <%= BCrypt::Password.create('password') %>
206
+ ```
207
+
208
+ **Why fixtures:** Faster (loaded once per test suite), declarative, Rails-native, no external gem needed.
209
+
210
+ ### Model Test Pattern
211
+ ```ruby
212
+ class UserTest < ActiveSupport::TestCase
213
+ setup do
214
+ Current.session = sessions(:alice_session) # Always set Current context
215
+ end
216
+
217
+ test "validates email presence" do
218
+ user = User.new(name: "Test")
219
+ assert_not user.valid?
220
+ assert_includes user.errors[:email], "can't be blank"
221
+ end
222
+
223
+ test "creates user with valid attributes" do
224
+ assert_difference "User.count", 1 do
225
+ User.create!(name: "New", email: "new@example.com", password: "password")
226
+ end
227
+ end
228
+ end
229
+ ```
230
+
231
+ ### Controller Test Pattern (Integration)
232
+ ```ruby
233
+ class PostsControllerTest < ActionDispatch::IntegrationTest
234
+ setup do
235
+ @user = users(:alice)
236
+ sign_in @user # Helper method
237
+ end
238
+
239
+ test "index returns posts" do
240
+ get posts_url
241
+ assert_response :success
242
+ assert_select "h2", posts(:first).title
243
+ end
244
+
245
+ test "create redirects on success" do
246
+ assert_difference "Post.count", 1 do
247
+ post posts_url, params: { post: { title: "New", body: "Content" } }
248
+ end
249
+ assert_redirected_to post_url(Post.last)
250
+ end
251
+ end
252
+ ```
253
+
254
+ ### System Test Pattern
255
+ ```ruby
256
+ class UserFlowsTest < ApplicationSystemTestCase
257
+ test "user can sign up and create a post" do
258
+ visit new_registration_url
259
+ fill_in "Name", with: "Test User"
260
+ fill_in "Email", with: "test@example.com"
261
+ fill_in "Password", with: "password123"
262
+ click_on "Sign up"
263
+
264
+ assert_text "Welcome, Test User"
265
+
266
+ click_on "New Post"
267
+ fill_in "Title", with: "My First Post"
268
+ fill_in "Body", with: "Hello world"
269
+ click_on "Create Post"
270
+
271
+ assert_text "My First Post"
272
+ end
273
+ end
274
+ ```
275
+
276
+ ### Key Testing Conventions
277
+ - Use `assert_difference` for state changes, not just boolean checks
278
+ - Set `Current.session` in setup blocks for multi-tenancy
279
+ - Test happy path and one key failure path per method
280
+ - Use `assert_select` for HTML assertions in controller tests
281
+ - Run `bin/rails test` (not `rspec`) for the full suite
282
+
283
+ </testing_patterns>
284
+
285
+ <domain_templates>
286
+
287
+ ## Rails Task Templates for Planning
288
+
289
+ These templates help the planner agent decompose common Rails work into well-structured tasks.
290
+
291
+ ### Add Model
292
+ ```
293
+ Tasks:
294
+ 1. Create migration + model with validations, associations, and concerns
295
+ Files: db/migrate/xxx_create_[model].rb, app/models/[model].rb
296
+ 2. Add model tests + fixtures
297
+ Files: test/models/[model]_test.rb, test/fixtures/[model].yml
298
+ ```
299
+
300
+ ### Add Controller (with views)
301
+ ```
302
+ Tasks:
303
+ 1. Add routes + controller with RESTful actions
304
+ Files: config/routes.rb, app/controllers/[model]_controller.rb
305
+ 2. Add views (index, show, new, edit, _form partial)
306
+ Files: app/views/[model]/*.html.erb
307
+ 3. Add controller tests
308
+ Files: test/controllers/[model]_controller_test.rb
309
+ ```
310
+
311
+ ### Add Authentication
312
+ ```
313
+ Tasks:
314
+ 1. Generate auth scaffold (Rails 8: bin/rails generate authentication)
315
+ or: Add User model with has_secure_password, Session model, SessionsController
316
+ Files: app/models/user.rb, app/models/session.rb, app/controllers/sessions_controller.rb
317
+ 2. Add auth views (login, registration)
318
+ Files: app/views/sessions/*.html.erb, app/views/registrations/*.html.erb
319
+ 3. Add auth tests
320
+ Files: test/controllers/sessions_controller_test.rb, test/models/user_test.rb
321
+ ```
322
+
323
+ ### Add Background Job
324
+ ```
325
+ Tasks:
326
+ 1. Create job class + model method it delegates to
327
+ Files: app/jobs/[name]_job.rb, app/models/[model].rb
328
+ 2. Add job tests
329
+ Files: test/jobs/[name]_job_test.rb
330
+ ```
331
+
332
+ ### Add Mailer
333
+ ```
334
+ Tasks:
335
+ 1. Create mailer + views
336
+ Files: app/mailers/[name]_mailer.rb, app/views/[name]_mailer/*.html.erb
337
+ 2. Add mailer tests
338
+ Files: test/mailers/[name]_mailer_test.rb
339
+ ```
340
+
341
+ ### Add Turbo/Hotwire Feature
342
+ ```
343
+ Tasks:
344
+ 1. Add Turbo Frame wrapping + controller turbo_stream response
345
+ Files: app/views/[model]/*.html.erb, app/controllers/[model]_controller.rb
346
+ 2. Add Stimulus controller (if interactive behavior needed)
347
+ Files: app/javascript/controllers/[name]_controller.js
348
+ 3. Add system test for real-time behavior
349
+ Files: test/system/[feature]_test.rb
350
+ ```
351
+
352
+ </domain_templates>
353
+
354
+ <known_domains>
355
+
356
+ ## Known Rails Domains (Skip Research)
357
+
358
+ These domains are well-understood in Rails and don't need web research:
359
+
360
+ | Domain | Key Patterns | Research Needed? |
361
+ |--------|-------------|-----------------|
362
+ | Models & Migrations | ActiveRecord, validations, associations, concerns | No |
363
+ | Controllers & Routes | RESTful resources, before_action, strong params | No |
364
+ | Views & Templates | ERB, partials, layouts, content_for | No |
365
+ | Authentication | has_secure_password, Devise, Rails 8 auth generator | No |
366
+ | Authorization | Pundit, CanCanCan, or hand-rolled | No |
367
+ | Background Jobs | Solid Queue, ActiveJob | No |
368
+ | Email | Action Mailer, letter_opener | No |
369
+ | File Uploads | Active Storage | No |
370
+ | Real-time | Action Cable, Turbo Streams | No |
371
+ | Testing | Minitest, fixtures, system tests | No |
372
+ | API Mode | Jbuilder, API-only controllers, token auth | No |
373
+ | Caching | Fragment caching, Russian doll, Solid Cache | No |
374
+ | Search | pg_search, Ransack | Maybe (depends on complexity) |
375
+ | Payments | Stripe, Pay gem | Yes (API details change) |
376
+ | External APIs | Third-party integrations | Yes (API-specific) |
377
+ | Novel Gems | Unfamiliar libraries | Yes |
378
+ | Infrastructure | Docker, Kamal, deployment | Maybe |
379
+
380
+ **Heuristic:** If all phase requirements map to "No" domains, skip research automatically. If any requirement maps to "Yes", consider `--research` flag.
381
+
382
+ </known_domains>
383
+
384
+ </rails_conventions>
@@ -17,7 +17,7 @@ Template for `.planning/codebase/ARCHITECTURE.md` - captures conceptual code org
17
17
 
18
18
  **Overall:** [Pattern name: e.g., "Rails Monolith", "Rails API-only", "Rails + Hotwire", "Rails Engine-based"]
19
19
 
20
- **Multi-Tenancy:** [e.g., "Path-based with CurrentAttributes", "Subdomain-based", "acts_as_tenant gem", "Single-tenant", "None"]
20
+ **Multi-Tenancy:** [e.g., "Path-based with CurrentAttributes", "Subdomain-based", "session based", "Single-tenant", "None"]
21
21
 
22
22
  **Key Characteristics:**
23
23
  - [Characteristic 1: e.g., "Server-rendered with Turbo"]
@@ -277,7 +277,7 @@ Template for `.planning/codebase/ARCHITECTURE.md` - captures conceptual code org
277
277
  **Key Domain Models:**
278
278
  - `Account` — Tenant root. All data scoped to an account
279
279
  - `Board` — Project workspace containing cards, columns, and access rules
280
- - `Card` — Primary work item. Most concern-composed model (20+ concerns). Uses `number` (integer) for user-facing IDs, UUID internally
280
+ - `Card` — Primary work item. Most concern-composed model (20+ concerns).
281
281
  - `Event` — Audit trail record. Polymorphic `eventable`, JSON `particulars` for action-specific data
282
282
  - `User` — Account member with role-based permissions. Resolved from `Current.session` → `identity` → `user`
283
283
 
@@ -357,11 +357,6 @@ Template for `.planning/codebase/ARCHITECTURE.md` - captures conceptual code org
357
357
  - Location: `app/models/` subdirectories — `User::Filtering`, `Event::Description`, `User::DayTimeline`
358
358
  - Pattern: Constructor injection, memoized collections (`@boards ||= ...`), boolean methods for conditional display (`show_tags?`), cache keys for fragment caching. Some include `ActionView::Helpers::TagHelper` for HTML generation. Instantiated via controller concerns or factory methods on models (`event.description_for(user)`)
359
359
 
360
- **Pundit Policies:**
361
- - Purpose: Authorize user actions on resources
362
- - Examples: `ProjectPolicy`, `TaskPolicy`, `MembershipPolicy`
363
- - Pattern: Policy class per model with `?` predicate methods
364
-
365
360
  ## Multi-Tenancy & Current Context
366
361
 
367
362
  **Approach:** Path-based — account slug extracted from URL path by `AccountSlug::Extractor` middleware. Slug moves from `PATH_INFO` to `SCRIPT_NAME`. No subdomain configuration needed.
@@ -400,7 +395,7 @@ Template for `.planning/codebase/ARCHITECTURE.md` - captures conceptual code org
400
395
 
401
396
  **Patterns:**
402
397
  - `rescue_from ActiveRecord::RecordNotFound` → 404 page
403
- - `rescue_from Pundit::NotAuthorizedError` → 403 or redirect with flash
398
+ - `rescue_from NotAuthorizedError` → 403 or redirect with flash
404
399
  - Model validation errors re-render form with `@model.errors`
405
400
  - Service objects return `Result` structs (success/failure) instead of raising
406
401
  - Jobs use `retry_on` for transient failures, `discard_on` for permanent ones
@@ -421,7 +416,6 @@ Template for `.planning/codebase/ARCHITECTURE.md` - captures conceptual code org
421
416
  - `require_authentication` filter on all non-public controllers
422
417
 
423
418
  **Authorization:**
424
- - Pundit policies per resource
425
419
  - `authorize` calls in controller actions
426
420
  - Scoped queries via `policy_scope`
427
421
 
@@ -190,8 +190,8 @@ Template for `.planning/codebase/CONCERNS.md` - captures known issues and areas
190
190
  **Missing authorization checks on nested resources:**
191
191
  - Risk: Card comments endpoint does not verify user has access to the parent board
192
192
  - Files: `app/controllers/comments_controller.rb`, missing `authorize @comment` call
193
- - Current mitigation: Obscured by UUID-based URLs (hard to guess)
194
- - Recommendations: Add Pundit `authorize` call or `before_action` scope check, add `CommentPolicy` with board-access verification
193
+ - Current mitigation: Denormalise tables so all include account_id and rely on `Current.account` scope, but no explicit check on board access.
194
+ - Recommendations: Add `before_action` scope check.
195
195
 
196
196
  **Unscoped queries leaking tenant data:**
197
197
  - Risk: `Admin::ReportsController` uses `Card.where(created_at: range)` without `Current.account` scope
@@ -251,7 +251,7 @@ end
251
251
  - Model validation errors re-render form with `@model.errors`
252
252
 
253
253
  **Error Types:**
254
- - Raise on authorization failures: `rescue_from Pundit::NotAuthorizedError`
254
+ - Raise on authorization failures: `rescue_from NotAuthorizedError`
255
255
  - Raise on missing records: `rescue_from ActiveRecord::RecordNotFound`
256
256
  - Return `false`/`nil` for expected domain failures
257
257
  - Jobs: `retry_on` for transient failures (network, timeouts), `discard_on ActiveRecord::RecordNotFound`
@@ -123,9 +123,8 @@ Template for `.planning/codebase/STACK.md` - captures the technology foundation.
123
123
 
124
124
  **Critical:**
125
125
  - authentication (built-in) — Session-based auth
126
- - punditAuthorization
126
+ - authorization - custom implementation (no gem) Role-based access control, pundit
127
127
  - solid_queue — Background jobs (Rails 8 default)
128
- - stripe — Payment processing
129
128
 
130
129
  **Infrastructure:**
131
130
  - sqlite3 — SQLite adapter (Rails default)
@@ -164,7 +164,57 @@ test/ # [test framework: Minitest (default) or spec/ if RSp
164
164
  ### Authentication and Authorization
165
165
 
166
166
  **Authentication:** [Rails authentication generator / has_secure_password / custom / other]
167
- **Authorization:** [Pundit / CanCanCan / custom / Action Policy / other]
167
+ **Authorization:** [Custom / Pundit / CanCanCan / Action Policy / other]
168
+
169
+ ### Internationalization (I18n)
170
+
171
+ **Configuration:**
172
+ - Default locale: [discovered from `config.i18n.default_locale`]
173
+ - Available locales: [discovered from `config.i18n.available_locales`]
174
+ - Fallback chain: [discovered from `config.i18n.fallbacks`]
175
+
176
+ **Locale file organization:**
177
+ ```
178
+ config/locales/
179
+ ├── [default locale].yml # [application-wide defaults]
180
+ ├── activerecord.[lang].yml # [model and attribute translations]
181
+ ├── [feature].[lang].yml # [per-feature locale files if present]
182
+ └── [additional locale files discovered]
183
+ ```
184
+
185
+ **ActiveRecord translations:**
186
+ ```yaml
187
+ # config/locales/activerecord.[lang].yml
188
+ [lang]:
189
+ activerecord:
190
+ models:
191
+ [model]: [translated model name]
192
+ attributes:
193
+ [model]:
194
+ [attribute]: [translated attribute name]
195
+ ```
196
+
197
+ **Translation approach:**
198
+
199
+ | Context | Recommended Approach | What This Project Does |
200
+ |---------|---------------------|------------------------|
201
+ | Model names | `activerecord.models.*` — automatic lookup by Rails | [discovered approach] |
202
+ | Attribute names | `activerecord.attributes.*` — automatic lookup by `form.label`, validations, etc. | [discovered approach] |
203
+ | Form labels | `form.label :name` — resolves from `activerecord.attributes` automatically | [discovered approach] |
204
+ | Validation messages | `activerecord.errors.models.*` / `errors.messages.*` — automatic lookup | [discovered approach] |
205
+ | View text | Lazy lookup `t(".title")` or explicit `t("views.controller.action.title")` | [discovered approach] |
206
+ | Enum values | `activerecord.attributes.[model].[enum_attribute]/[value]` | [discovered approach] |
207
+ | Flash messages | Controller lazy lookup `t(".success")` or explicit keys | [discovered approach] |
208
+ | Mailer subjects | `I18n.t("mailer_name.action_name.subject")` — automatic from mailer class | [discovered approach] |
209
+
210
+ **CLDR / base locale data:**
211
+ - `rails-i18n` gem: [present/absent — provides date, time, currency, number formats for non-English locales]
212
+ - Custom date/time formats: [discovered in locale files or initializers]
213
+
214
+ **Example from codebase:**
215
+ ```ruby
216
+ # [Brief code example showing the project's actual I18n usage pattern]
217
+ ```
168
218
 
169
219
  ## Data Flow
170
220
 
@@ -377,4 +427,13 @@ Client receives → DOM update
377
427
  - Note external API integration patterns and HTTP client choices
378
428
  - Look for engine boundaries and module interfaces
379
429
 
430
+ **Internationalization (I18n):**
431
+ - Check `config/application.rb` for `i18n.default_locale`, `i18n.available_locales`, and `i18n.fallbacks`
432
+ - Inspect `config/locales/` file organization — per-model, per-feature, or flat structure
433
+ - Look for `activerecord.models.*` and `activerecord.attributes.*` keys in locale files — these power automatic lookup for model names, form labels, and validation messages
434
+ - Check whether form labels use automatic lookup (`form.label :name`) vs explicit `t()` calls — explicit calls duplicate what Rails provides for free
435
+ - Check Gemfile for `rails-i18n` gem — provides CLDR base data (dates, times, currency, numbers) for non-English locales
436
+ - Look for validation error message customization under `activerecord.errors.models.*`
437
+ - Check for lazy lookup usage in views (`t(".key")`) and controllers
438
+
380
439
  </guidelines>