ariadna 1.3.0 → 2.0.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.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/ariadna.gemspec +0 -1
  3. data/data/agents/ariadna-codebase-mapper.md +34 -722
  4. data/data/agents/ariadna-debugger.md +44 -1139
  5. data/data/agents/ariadna-executor.md +75 -396
  6. data/data/agents/ariadna-planner.md +78 -1215
  7. data/data/agents/ariadna-roadmapper.md +55 -582
  8. data/data/agents/ariadna-verifier.md +60 -702
  9. data/data/ariadna/templates/config.json +8 -33
  10. data/data/ariadna/workflows/debug.md +28 -0
  11. data/data/ariadna/workflows/execute-phase.md +31 -513
  12. data/data/ariadna/workflows/map-codebase.md +20 -319
  13. data/data/ariadna/workflows/new-milestone.md +20 -365
  14. data/data/ariadna/workflows/new-project.md +19 -880
  15. data/data/ariadna/workflows/plan-phase.md +24 -443
  16. data/data/ariadna/workflows/progress.md +20 -376
  17. data/data/ariadna/workflows/quick.md +19 -221
  18. data/data/ariadna/workflows/roadmap-ops.md +28 -0
  19. data/data/ariadna/workflows/verify-work.md +23 -560
  20. data/data/commands/ariadna/add-phase.md +11 -22
  21. data/data/commands/ariadna/debug.md +11 -143
  22. data/data/commands/ariadna/execute-phase.md +12 -30
  23. data/data/commands/ariadna/insert-phase.md +7 -14
  24. data/data/commands/ariadna/map-codebase.md +16 -49
  25. data/data/commands/ariadna/new-milestone.md +12 -25
  26. data/data/commands/ariadna/new-project.md +22 -26
  27. data/data/commands/ariadna/plan-phase.md +13 -22
  28. data/data/commands/ariadna/progress.md +16 -6
  29. data/data/commands/ariadna/quick.md +9 -11
  30. data/data/commands/ariadna/remove-phase.md +9 -12
  31. data/data/commands/ariadna/verify-work.md +14 -19
  32. data/data/skills/rails-backend/API.md +138 -0
  33. data/data/skills/rails-backend/CONTROLLERS.md +154 -0
  34. data/data/skills/rails-backend/JOBS.md +132 -0
  35. data/data/skills/rails-backend/MODELS.md +213 -0
  36. data/data/skills/rails-backend/SKILL.md +169 -0
  37. data/data/skills/rails-frontend/ASSETS.md +154 -0
  38. data/data/skills/rails-frontend/COMPONENTS.md +253 -0
  39. data/data/skills/rails-frontend/SKILL.md +187 -0
  40. data/data/skills/rails-frontend/VIEWS.md +168 -0
  41. data/data/skills/rails-performance/PROFILING.md +106 -0
  42. data/data/skills/rails-performance/SKILL.md +217 -0
  43. data/data/skills/rails-security/AUDIT.md +118 -0
  44. data/data/skills/rails-security/SKILL.md +422 -0
  45. data/data/skills/rails-testing/FIXTURES.md +78 -0
  46. data/data/skills/rails-testing/SKILL.md +160 -0
  47. data/data/skills/rails-testing/SYSTEM-TESTS.md +73 -0
  48. data/lib/ariadna/installer.rb +11 -15
  49. data/lib/ariadna/tools/cli.rb +0 -12
  50. data/lib/ariadna/tools/config_manager.rb +10 -72
  51. data/lib/ariadna/tools/frontmatter.rb +23 -1
  52. data/lib/ariadna/tools/init.rb +201 -401
  53. data/lib/ariadna/tools/model_profiles.rb +6 -14
  54. data/lib/ariadna/tools/phase_manager.rb +1 -10
  55. data/lib/ariadna/tools/state_manager.rb +170 -451
  56. data/lib/ariadna/tools/template_filler.rb +4 -12
  57. data/lib/ariadna/tools/verification.rb +21 -399
  58. data/lib/ariadna/uninstaller.rb +9 -0
  59. data/lib/ariadna/version.rb +1 -1
  60. data/lib/ariadna.rb +1 -0
  61. metadata +20 -91
  62. data/data/agents/ariadna-backend-executor.md +0 -261
  63. data/data/agents/ariadna-frontend-executor.md +0 -259
  64. data/data/agents/ariadna-integration-checker.md +0 -418
  65. data/data/agents/ariadna-phase-researcher.md +0 -469
  66. data/data/agents/ariadna-plan-checker.md +0 -622
  67. data/data/agents/ariadna-project-researcher.md +0 -618
  68. data/data/agents/ariadna-research-synthesizer.md +0 -236
  69. data/data/agents/ariadna-test-executor.md +0 -266
  70. data/data/ariadna/references/checkpoints.md +0 -772
  71. data/data/ariadna/references/continuation-format.md +0 -249
  72. data/data/ariadna/references/decimal-phase-calculation.md +0 -65
  73. data/data/ariadna/references/git-integration.md +0 -248
  74. data/data/ariadna/references/git-planning-commit.md +0 -38
  75. data/data/ariadna/references/model-profile-resolution.md +0 -32
  76. data/data/ariadna/references/model-profiles.md +0 -73
  77. data/data/ariadna/references/phase-argument-parsing.md +0 -61
  78. data/data/ariadna/references/planning-config.md +0 -194
  79. data/data/ariadna/references/questioning.md +0 -153
  80. data/data/ariadna/references/rails-conventions.md +0 -416
  81. data/data/ariadna/references/tdd.md +0 -267
  82. data/data/ariadna/references/ui-brand.md +0 -160
  83. data/data/ariadna/references/verification-patterns.md +0 -853
  84. data/data/ariadna/templates/codebase/architecture.md +0 -481
  85. data/data/ariadna/templates/codebase/concerns.md +0 -380
  86. data/data/ariadna/templates/codebase/conventions.md +0 -434
  87. data/data/ariadna/templates/codebase/integrations.md +0 -328
  88. data/data/ariadna/templates/codebase/stack.md +0 -189
  89. data/data/ariadna/templates/codebase/structure.md +0 -418
  90. data/data/ariadna/templates/codebase/testing.md +0 -606
  91. data/data/ariadna/templates/context.md +0 -283
  92. data/data/ariadna/templates/continue-here.md +0 -78
  93. data/data/ariadna/templates/debug-subagent-prompt.md +0 -91
  94. data/data/ariadna/templates/phase-prompt.md +0 -609
  95. data/data/ariadna/templates/planner-subagent-prompt.md +0 -117
  96. data/data/ariadna/templates/research-project/ARCHITECTURE.md +0 -439
  97. data/data/ariadna/templates/research-project/FEATURES.md +0 -168
  98. data/data/ariadna/templates/research-project/PITFALLS.md +0 -406
  99. data/data/ariadna/templates/research-project/STACK.md +0 -251
  100. data/data/ariadna/templates/research-project/SUMMARY.md +0 -247
  101. data/data/ariadna/templates/state.md +0 -176
  102. data/data/ariadna/templates/summary-complex.md +0 -59
  103. data/data/ariadna/templates/summary-minimal.md +0 -41
  104. data/data/ariadna/templates/summary-standard.md +0 -48
  105. data/data/ariadna/templates/user-setup.md +0 -310
  106. data/data/ariadna/workflows/add-phase.md +0 -111
  107. data/data/ariadna/workflows/add-todo.md +0 -157
  108. data/data/ariadna/workflows/audit-milestone.md +0 -241
  109. data/data/ariadna/workflows/check-todos.md +0 -176
  110. data/data/ariadna/workflows/complete-milestone.md +0 -644
  111. data/data/ariadna/workflows/diagnose-issues.md +0 -219
  112. data/data/ariadna/workflows/discovery-phase.md +0 -289
  113. data/data/ariadna/workflows/discuss-phase.md +0 -408
  114. data/data/ariadna/workflows/execute-plan.md +0 -448
  115. data/data/ariadna/workflows/help.md +0 -470
  116. data/data/ariadna/workflows/insert-phase.md +0 -129
  117. data/data/ariadna/workflows/list-phase-assumptions.md +0 -178
  118. data/data/ariadna/workflows/pause-work.md +0 -122
  119. data/data/ariadna/workflows/plan-milestone-gaps.md +0 -256
  120. data/data/ariadna/workflows/remove-phase.md +0 -154
  121. data/data/ariadna/workflows/research-phase.md +0 -74
  122. data/data/ariadna/workflows/resume-project.md +0 -306
  123. data/data/ariadna/workflows/set-profile.md +0 -80
  124. data/data/ariadna/workflows/settings.md +0 -145
  125. data/data/ariadna/workflows/transition.md +0 -493
  126. data/data/ariadna/workflows/update.md +0 -212
  127. data/data/ariadna/workflows/verify-phase.md +0 -226
  128. data/data/commands/ariadna/add-todo.md +0 -42
  129. data/data/commands/ariadna/audit-milestone.md +0 -42
  130. data/data/commands/ariadna/check-todos.md +0 -41
  131. data/data/commands/ariadna/complete-milestone.md +0 -136
  132. data/data/commands/ariadna/discuss-phase.md +0 -86
  133. data/data/commands/ariadna/help.md +0 -22
  134. data/data/commands/ariadna/list-phase-assumptions.md +0 -50
  135. data/data/commands/ariadna/pause-work.md +0 -35
  136. data/data/commands/ariadna/plan-milestone-gaps.md +0 -40
  137. data/data/commands/ariadna/reapply-patches.md +0 -110
  138. data/data/commands/ariadna/research-phase.md +0 -187
  139. data/data/commands/ariadna/resume-work.md +0 -40
  140. data/data/commands/ariadna/set-profile.md +0 -34
  141. data/data/commands/ariadna/settings.md +0 -36
  142. data/data/commands/ariadna/update.md +0 -37
  143. data/data/guides/backend.md +0 -3069
  144. data/data/guides/frontend.md +0 -1479
  145. data/data/guides/performance.md +0 -1193
  146. data/data/guides/security.md +0 -1522
  147. data/data/guides/style-guide.md +0 -1091
  148. data/data/guides/testing.md +0 -504
  149. data/data/templates.md +0 -94
@@ -1,481 +0,0 @@
1
- # Architecture Template
2
-
3
- Template for `.ariadna_planning/codebase/ARCHITECTURE.md` - captures conceptual code organization.
4
-
5
- **Purpose:** Document how the code is organized at a conceptual level. Complements STRUCTURE.md (which shows physical file locations).
6
-
7
- ---
8
-
9
- ## File Template
10
-
11
- ```markdown
12
- # Architecture
13
-
14
- **Analysis Date:** [YYYY-MM-DD]
15
-
16
- ## Pattern Overview
17
-
18
- **Overall:** [Pattern name: e.g., "Rails Monolith", "Rails API-only", "Rails + Hotwire", "Rails Engine-based"]
19
-
20
- **Multi-Tenancy:** [e.g., "Path-based with CurrentAttributes", "Subdomain-based", "session based", "Single-tenant", "None"]
21
-
22
- **Key Characteristics:**
23
- - [Characteristic 1: e.g., "Server-rendered with Turbo"]
24
- - [Characteristic 2: e.g., "RESTful resource routing with nested sub-resources"]
25
- - [Characteristic 3: e.g., "Concern-composed models with rich domain APIs"]
26
-
27
- ## Layers
28
-
29
- [Describe the conceptual layers and their responsibilities]
30
-
31
- **Routing:** `config/routes.rb` — Map HTTP requests to controller actions. Resource routes, namespace scoping, constraints, member/collection routes.
32
-
33
- **Controllers:** `app/controllers/` — Handle HTTP requests, enforce auth, orchestrate responses. Shared filters, strong params, response rendering.
34
-
35
- **Models:** `app/models/` — Domain logic, data persistence, associations, validations, scopes, callbacks. Concern-composed behavior.
36
-
37
- **Views:** `app/views/` — Render responses. [ERB/ViewComponents/Turbo Streams], partials, layouts, helpers.
38
-
39
- **Services/POROs:** `app/services/` (or `app/models/` subdirectories) — [Service objects, form objects, query objects, presenters — list what's present and where they live]
40
-
41
- **Jobs:** `app/jobs/` — Asynchronous and background processing. ActiveJob classes [backed by Solid Queue / Sidekiq / GoodJob].
42
-
43
- **Mailers:** `app/mailers/` — Transactional and notification emails via ActionMailer.
44
-
45
- ## Model Architecture
46
-
47
- [How the model layer is designed — this is often where an app's distinctive patterns live]
48
-
49
- **Design Philosophy:** [e.g., "Thin controllers, rich models — business logic lives in models and model concerns, not in controllers or service objects"]
50
-
51
- **Concern Architecture:**
52
- - **Shared concerns** (`app/models/concerns/`): [List key shared concerns and naming convention, e.g., "Adjective names — `Eventable`, `Searchable`, `Notifiable`"]
53
- - **Model-specific concerns** ([e.g., `app/models/card/`, `app/models/board/`]): [List directories and naming convention, e.g., "Namespaced — `Card::Closeable`, `Board::Accessible`"]
54
- - **Composition pattern**: [How are concerns combined? e.g., "Models include 10-20 concerns via `include` — each adds a distinct capability"]
55
- - **Layering/Template method**: [Do concerns override each other? e.g., "Base `Eventable` provides `track_event` with override points; `Card::Eventable` customizes behavior via `should_track_event?` and `event_was_created`"]
56
-
57
- **Association Defaults:**
58
- - [e.g., "Lambda defaults on `belongs_to` propagate context: `belongs_to :account, default: -> { board.account }`"]
59
- - [e.g., "Creator tracking via `belongs_to :creator, default: -> { Current.user }`"]
60
-
61
- **Key Domain Models:**
62
- - [Model 1: role and key relationships]
63
- - [Model 2: role and key relationships]
64
- - [Model 3: role and key relationships]
65
-
66
- **Scoping Patterns:** [How are scopes named? e.g., "Business names not SQL names — `closed` not `with_closures`, `open` not `without_closures`. Composable: `Card.open.golden.latest`"]
67
-
68
- **Callback Philosophy:** [e.g., "Minimal callbacks — `before_create` for required data, `after_create_commit` for async jobs, `after_save` for cache invalidation. Business logic uses explicit methods, not callbacks"]
69
-
70
- ## Controller Patterns
71
-
72
- [How controllers are structured beyond basic MVC]
73
-
74
- **Philosophy:** [e.g., "Thin controllers — setup, call one model method, respond. No business logic in controllers"]
75
-
76
- **Resource Nesting:** [e.g., "Actions modeled as sub-resources: `resource :closure` (create=close, destroy=reopen) instead of `post :close`"]
77
-
78
- **Controller Concerns:** [e.g., "`CardScoped` sets `@card` and `@board` via before_action — shared across all nested card controllers. `BoardScoped` handles board loading and permission checks. `FilterScoped` instantiates presenter objects"]
79
-
80
- **Response Formats:** [e.g., "Multi-format via `respond_to` — Turbo Stream for live updates, HTML for full pages, JSON for API"]
81
-
82
- ## Data Flow
83
-
84
- [Describe the typical request/execution lifecycle]
85
-
86
- **HTTP Request (standard Rails cycle):**
87
-
88
- 1. Request hits `config/routes.rb`, matched to controller#action
89
- 2. Rack middleware stack runs (session, cookies, CSRF protection, auth)
90
- 3. Controller `before_action` filters execute (authentication, authorization, parameter setup)
91
- 4. Controller action runs — calls models/services for business logic
92
- 5. Model layer handles data access, validations, associations
93
- 6. View renders response (ERB/ViewComponent/Turbo Stream/JSON)
94
- 7. Response returned to client
95
-
96
- **Turbo/Hotwire Flow (if applicable):**
97
-
98
- 1. User interaction triggers Turbo Frame or Turbo Stream request
99
- 2. Controller responds with `turbo_stream` format or frame-scoped HTML
100
- 3. Turbo replaces/appends/removes DOM elements without full page reload
101
-
102
- **Background Job Flow:**
103
-
104
- 1. Controller or model enqueues job via `perform_later`
105
- 2. Job backend [Solid Queue/Sidekiq/GoodJob] picks up job
106
- 3. Job executes with access to full Rails environment
107
- 4. Results persisted to database or notifications sent
108
-
109
- **State Management:**
110
- - [How state is handled: e.g., "SQLite via ActiveRecord (Rails default)", "Solid Cache for caching (database-backed)", "Redis for sessions or shared state", "Kredis for structured Redis data"]
111
-
112
- ## Background Job Patterns
113
-
114
- [How background work is organized — thin jobs, naming conventions, tenant context]
115
-
116
- **Job Philosophy:** [e.g., "Ultra-thin jobs — 3-6 lines. All logic lives in model methods. Jobs are just async wrappers"]
117
-
118
- **_now/_later Pattern:** [e.g., "Every async operation has three parts: (1) synchronous method `notify_recipients`, (2) async wrapper `notify_recipients_later` that enqueues, (3) thin job class that calls the sync method. Testable at model level, callable from console/jobs/controllers"]
119
-
120
- **Multi-Tenancy in Jobs:** [e.g., "Tenant context captured automatically on job creation via `Current.account`, serialized into job payload, restored on execution. No manual account passing needed"]
121
-
122
- **Queue Organization:** [e.g., "Queues: `default`, `backend` (exports, heavy processing), `webhooks` (external deliveries). Configured in config/queue.yml (Solid Queue) / Sidekiq / GoodJob"]
123
-
124
- **Retry Strategy:** [e.g., "`retry_on` for transient failures (network, timeouts), `discard_on` for permanent failures (record not found). Configured per-job"]
125
-
126
- ## Key Abstractions
127
-
128
- [Core concepts/patterns used throughout the codebase]
129
-
130
- **ActiveRecord Models:**
131
- - Purpose: Domain entities with persistence, associations, and business rules
132
- - Examples: [e.g., `User`, `Board`, `Card`, `Event`]
133
- - Pattern: Active Record — each model wraps a database table
134
-
135
- **Concerns:**
136
- - Purpose: Compose model behavior from focused modules
137
- - **Shared** (`app/models/concerns/`): Cross-cutting behavior for multiple models [e.g., `Eventable`, `Searchable`]
138
- - **Model-specific** ([e.g., `app/models/card/`]): Domain behavior scoped to one model [e.g., `Card::Closeable`, `Card::Postponable`]
139
- - Pattern: `ActiveSupport::Concern` with `included do` block for associations/scopes, instance methods for API, template method pattern for customization points
140
-
141
- **Presenters/View Models (if present):**
142
- - Purpose: [e.g., "Plain Ruby classes that package data and display logic for views"]
143
- - Location: [e.g., "`app/models/` subdirectories (not a separate `app/presenters/`)" or "`app/presenters/`"]
144
- - Examples: [e.g., `User::Filtering` (filter UI state), `Event::Description` (event → human-readable text)]
145
- - Pattern: [e.g., "Constructor injection, memoized collections, boolean methods for conditional display, cache keys for fragment caching"]
146
-
147
- **Service Objects (if present):**
148
- - Purpose: Encapsulate multi-step operations that don't belong in a single model
149
- - Examples: [e.g., `Projects::Creator`, `Invitations::Acceptor`]
150
- - Pattern: [e.g., "Class with `.call` method returning a result"]
151
-
152
- **[Additional Abstraction — e.g., Policies, Form Objects, Query Objects]:**
153
- - Purpose: [What it represents]
154
- - Examples: [Concrete examples]
155
- - Pattern: [Pattern used]
156
-
157
- ## Multi-Tenancy & Current Context
158
-
159
- [How tenant isolation works — omit this section if the app is single-tenant]
160
-
161
- **Approach:** [e.g., "Path-based with CurrentAttributes — account ID extracted from URL by middleware, sets `Current.account` for the request"]
162
-
163
- **Current Context:** [e.g., "`Current` holds `session`, `user`, `identity`, `account`. Cascade: setting `session` → resolves `identity` → resolves `user` for current account"]
164
-
165
- **Scoping:** [e.g., "Lambda defaults on `belongs_to :account` ensure all records created within a request are scoped to the tenant. Queries scope through `Current.user.boards`, `Current.user.accessible_cards`"]
166
-
167
- **Async Context:** [e.g., "Jobs automatically capture/restore `Current.account` via ApplicationJob extensions — no manual passing needed"]
168
-
169
- ## Entry Points
170
-
171
- [Where execution begins]
172
-
173
- **Web Requests:**
174
- - Location: `config/routes.rb` → `app/controllers/`
175
- - Triggers: HTTP requests from browser or API clients
176
- - Responsibilities: Route matching, middleware execution, controller dispatch
177
-
178
- **Background Jobs:**
179
- - Location: `app/jobs/`
180
- - Triggers: Enqueued from application code, scheduled via cron/clockwork
181
- - Responsibilities: Async processing — emails, imports, cleanup, notifications
182
-
183
- **Rake Tasks:**
184
- - Location: `lib/tasks/*.rake`
185
- - Triggers: Manual invocation (`rails db:migrate`, custom tasks)
186
- - Responsibilities: Data migrations, maintenance, one-off operations
187
-
188
- **Configuration & Boot:**
189
- - Location: `config/application.rb`, `config/environments/`, `config/initializers/`
190
- - Triggers: Application startup
191
- - Responsibilities: Framework configuration, gem initialization, middleware setup
192
-
193
- ## Error Handling
194
-
195
- **Strategy:** [How errors are handled: e.g., "`rescue_from` in ApplicationController", "Custom error pages in `app/views/errors/`", "Exception tracking via Sentry/Honeybadger"]
196
-
197
- **Patterns:**
198
- - [Pattern: e.g., "`rescue_from ActiveRecord::RecordNotFound` renders 404"]
199
- - [Pattern: e.g., "Model validation errors re-render form with error messages"]
200
- - [Pattern: e.g., "Service objects return Result/Response objects instead of raising"]
201
- - [Pattern: e.g., "Background jobs use `retry_on` / `discard_on` for failure handling"]
202
-
203
- ## Cross-Cutting Concerns
204
-
205
- [Aspects that affect multiple layers]
206
-
207
- **Logging:**
208
- - [Approach: e.g., "`Rails.logger` with tagged logging", "Lograge for structured request logs"]
209
-
210
- **Validation:**
211
- - [Approach: e.g., "ActiveModel validations in models", "Strong parameters in controllers", "Form objects for complex input"]
212
-
213
- **Authentication:**
214
- - [Approach: e.g., "Rails authentication generator with `Authentication` concern", "has_secure_password with custom auth", "OmniAuth for OAuth"]
215
-
216
- **Authorization:**
217
- - [Approach: e.g., "Custom `before_action` checks with `Current` context", "Pundit policies (if explicitly chosen)", "CanCanCan abilities (if explicitly chosen)"]
218
-
219
- **Caching:**
220
- - [Approach: e.g., "Fragment caching in views", "Russian doll caching", "Rails.cache with Solid Cache/Redis"]
221
-
222
- ---
223
-
224
- *Architecture analysis: [date]*
225
- *Update when major patterns change*
226
- ```
227
-
228
- <good_examples>
229
- ```markdown
230
- # Architecture
231
-
232
- **Analysis Date:** 2025-01-20
233
-
234
- ## Pattern Overview
235
-
236
- **Overall:** Rails Monolith with Hotwire
237
-
238
- **Multi-Tenancy:** Path-based with CurrentAttributes
239
-
240
- **Key Characteristics:**
241
- - Server-rendered HTML with Turbo for SPA-like interactions
242
- - RESTful resource routing with actions modeled as sub-resources
243
- - Concern-composed models with rich domain APIs
244
- - Thin controllers, thin jobs — business logic lives in models
245
-
246
- ## Layers
247
-
248
- **Routing:** `config/routes.rb` — RESTful resource routes with nested singular resources for state changes (`resource :closure`, `resource :goldness`). Namespace scoping for admin. Constraints for account slug extraction.
249
-
250
- **Controllers:** `app/controllers/` — Thin controllers using shared concerns (`CardScoped`, `BoardScoped`, `FilterScoped`). `before_action` for auth and resource loading. Multi-format responses (Turbo Stream, HTML, JSON).
251
-
252
- **Models:** `app/models/` — Rich domain models composed of 10-20 concerns each. Business logic, associations, scopes, validations. Model-specific concerns in subdirectories (`app/models/card/`, `app/models/board/`).
253
-
254
- **Views:** `app/views/` — ERB templates with Turbo Frame tags and Turbo Stream actions. Partials for reusable components. Layouts with Stimulus controller integration (`app/javascript/controllers/`).
255
-
256
- **Presenters:** `app/models/` subdirectories — Plain Ruby classes for complex view logic (`User::Filtering`, `Event::Description`, `User::DayTimeline`). No separate `app/presenters/` directory.
257
-
258
- **Jobs:** `app/jobs/` — Ultra-thin ActiveJob classes backed by Solid Queue. 3-6 lines each — delegate to model methods via `_now/_later` pattern.
259
-
260
- **Mailers:** `app/mailers/` — ActionMailer classes for invitations, notifications, digests.
261
-
262
- ## Model Architecture
263
-
264
- **Design Philosophy:** Thin controllers, rich models. All business logic lives in models and model concerns. Controllers do setup → call one model method → respond. Service objects are rare — behavior composes via concerns.
265
-
266
- **Concern Architecture:**
267
- - **Shared concerns** (`app/models/concerns/`): Adjective names for cross-cutting behavior — `Eventable` (audit trail), `Notifiable` (notifications), `Searchable` (full-text search), `Attachments` (file uploads), `Mentions` (@-mentions), `Storage::Tracked` (storage accounting)
268
- - **Model-specific concerns** (`app/models/card/`, `app/models/board/`): Namespaced names for domain behavior — `Card::Closeable` (close/reopen), `Card::Golden` (mark as important), `Card::Postponable` (defer to "not now"), `Card::Entropic` (auto-decay stale cards), `Board::Accessible` (access control)
269
- - **Composition pattern**: Card model includes 20+ concerns via `include Assignable, Closeable, Eventable, Golden, Postponable, ...`. Each adds associations, scopes, and instance methods
270
- - **Layering/Template method**: Base `Eventable` provides `track_event` with override points (`should_track_event?`, `event_was_created`, `eventable_prefix`). `Card::Eventable` includes `::Eventable` and overrides: only tracks events for published cards, creates system comments on event creation
271
-
272
- **Association Defaults:**
273
- - Multi-tenancy: `belongs_to :account, default: -> { board.account }` — account derived from parent
274
- - Creator tracking: `belongs_to :creator, class_name: "User", default: -> { Current.user }`
275
- - Declaration order matters: declare `belongs_to :board` before using `board` in a default lambda
276
-
277
- **Key Domain Models:**
278
- - `Account` — Tenant root. All data scoped to an account
279
- - `Board` — Project workspace containing cards, columns, and access rules
280
- - `Card` — Primary work item. Most concern-composed model (20+ concerns).
281
- - `Event` — Audit trail record. Polymorphic `eventable`, JSON `particulars` for action-specific data
282
- - `User` — Account member with role-based permissions. Resolved from `Current.session` → `identity` → `user`
283
-
284
- **Scoping Patterns:** Business names, not SQL names. `closed` (not `with_closures`), `open` (not `without_closures`), `golden`, `postponed`. Composable: `Card.open.golden.latest`. Conditional UI scopes: `indexed_by("stalled")`, `sorted_by("newest")`. Preloading scopes: `Card.preloaded` eager-loads all associations.
285
-
286
- **Callback Philosophy:** Minimal. `before_create` for required data (sequential numbers). `after_create_commit` for async jobs (notifications, storage tracking). `after_save` with lambda for simple one-liners (`-> { board.touch }`). Conditional via `if: :saved_change_to_board_id?`. Business logic uses explicit methods (`close`, `gild`), not callbacks.
287
-
288
- ## Controller Patterns
289
-
290
- **Philosophy:** Thin controllers — setup, call one model method, respond. A typical action is 3-5 lines. `Cards::GoldnessesController#create` is just `@card.gild` + respond.
291
-
292
- **Resource Nesting:** Actions modeled as singular sub-resources under the parent. `resource :closure` (create=close, destroy=reopen), `resource :goldness` (create=gild, destroy=ungild), `resource :pin`, `resource :watch`. Scoped via `scope module: :cards`. Standard CRUD verbs, no custom actions.
293
-
294
- **Controller Concerns:** `CardScoped` — sets `@card` (found by number) and `@board` via before_action, provides `render_card_replacement` for Turbo Stream responses. Used by all nested card controllers. `BoardScoped` — sets `@board`, provides permission checks. `FilterScoped` — instantiates `User::Filtering` presenter.
295
-
296
- **Response Formats:** `respond_to` blocks with Turbo Stream (partial replacement via morph), HTML (full page), JSON (`head :no_content` for API). Turbo Stream responses use `turbo_stream.replace` with morphing.
297
-
298
- ## Data Flow
299
-
300
- **HTTP Request (standard Rails cycle):**
301
-
302
- 1. Request hits `config/routes.rb`, account slug extracted by middleware → `Current.account`
303
- 2. Rack middleware runs (session, CSRF, auth)
304
- 3. `before_action :authenticate_user!` verifies session → `Current.session` → cascade to `Current.user`
305
- 4. Controller concern sets resource (`CardScoped` loads `@card` by number)
306
- 5. Action calls single model method (`@card.close`)
307
- 6. Model method runs in transaction — state change + event tracking
308
- 7. Turbo Stream response replaces partial in-place
309
-
310
- **Turbo Stream Flow (card state change):**
311
-
312
- 1. User clicks action button (Turbo-enabled form)
313
- 2. POST/DELETE to nested resource (e.g., `POST /cards/123/closure`)
314
- 3. Controller calls model method, responds with `turbo_stream.replace`
315
- 4. Turbo morphs DOM element — no full page reload
316
-
317
- **Background Job Flow (notifications):**
318
-
319
- 1. Record created → `after_create_commit :notify_recipients_later`
320
- 2. `_later` method enqueues `NotifyRecipientsJob` (account captured automatically)
321
- 3. Solid Queue picks up job, restores `Current.account`
322
- 4. Job calls `record.notify_recipients` (synchronous model method)
323
- 5. Model method handles all logic — notification creation, delivery
324
-
325
- **State Management:**
326
- - SQLite for all persistent data via ActiveRecord (upgrade to PostgreSQL for high-concurrency production)
327
- - Solid Cache (database-backed) for fragment caching and Rails.cache
328
- - Turbo maintains UI state client-side (no server-side view state)
329
-
330
- ## Background Job Patterns
331
-
332
- **Job Philosophy:** Ultra-thin jobs — 3-6 lines. All logic in model methods. Jobs are async wrappers, nothing more.
333
-
334
- **_now/_later Pattern:** Every async operation has three parts: (1) synchronous method on model (`notify_recipients`), (2) `_later` wrapper that enqueues (`notify_recipients_later`), (3) thin job class that calls the sync method (`NotifyRecipientsJob#perform → notifiable.notify_recipients`). Logic tested via synchronous method. Callable from console, jobs, controllers.
335
-
336
- **Multi-Tenancy in Jobs:** `ApplicationJob` extensions automatically capture `Current.account` on job creation, serialize it into the job payload via GlobalID, and restore it with `Current.with_account` on execution. No manual account passing. Queries in jobs "just work."
337
-
338
- **Queue Organization:** `default` (general), `backend` (exports, heavy processing), `webhooks` (external deliveries). Configured via `queue_as :backend`.
339
-
340
- **Retry Strategy:** `retry_on` for transient failures (network, timeouts). `discard_on ActiveRecord::RecordNotFound` for permanent failures. Configured per-job.
341
-
342
- ## Key Abstractions
343
-
344
- **ActiveRecord Models:**
345
- - Purpose: Domain entities with persistence, associations, and business rules
346
- - Examples: `Account`, `Board`, `Card`, `Event`, `User`, `Closure`, `Goldness`
347
- - Pattern: Active Record — each model wraps a database table. State-change models (`Closure`, `Goldness`) represent boolean states as presence/absence of a record
348
-
349
- **Concerns:**
350
- - Purpose: Compose model behavior from focused, testable modules
351
- - **Shared** (`app/models/concerns/`): `Eventable`, `Notifiable`, `Searchable`, `Attachments`, `Mentions`, `Storage::Tracked`
352
- - **Model-specific** (`app/models/card/`, `app/models/board/`): `Card::Closeable`, `Card::Golden`, `Card::Postponable`, `Card::Entropic`, `Board::Accessible`
353
- - Pattern: `ActiveSupport::Concern` — `included do` block for associations/scopes/callbacks, public instance methods for API, template method pattern for customization points. Concerns can layer: `Card::Eventable` includes `::Eventable` and overrides hooks
354
-
355
- **Presenters:**
356
- - Purpose: Plain Ruby classes that package data and display logic for views
357
- - Location: `app/models/` subdirectories — `User::Filtering`, `Event::Description`, `User::DayTimeline`
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
-
360
- ## Multi-Tenancy & Current Context
361
-
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.
363
-
364
- **Current Context:** `Current` (ActiveSupport::CurrentAttributes) holds `session`, `user`, `identity`, `account`, plus request metadata. Cascade: setting `Current.session` → extracts `identity` → finds `user` for current `account`. In tests: `Current.session = sessions(:david)` sets everything.
365
-
366
- **Scoping:** Lambda defaults on `belongs_to :account, default: -> { board.account }` ensure all records are tenant-scoped at creation. Queries scope through user: `Current.user.boards`, `Current.user.accessible_cards.find_by!(number: params[:id])`.
367
-
368
- **Async Context:** `ApplicationJob` extensions capture `Current.account` on creation, serialize via GlobalID, restore with `Current.with_account(account)` on execution. Transparent to job authors.
369
-
370
- ## Entry Points
371
-
372
- **Web Requests:**
373
- - Location: `config/routes.rb` → `app/controllers/`
374
- - Triggers: Browser requests, Turbo navigations, API calls
375
- - Responsibilities: Auth, routing, rendering
376
-
377
- **Background Jobs:**
378
- - Location: `app/jobs/`
379
- - Triggers: `perform_later` from app code, recurring tasks via Solid Queue's config/recurring.yml
380
- - Responsibilities: Emails, imports, cleanup, notifications
381
-
382
- **Rake Tasks:**
383
- - Location: `lib/tasks/`
384
- - Triggers: Manual or cron (`rails projects:archive_stale`, `rails data:backfill_slugs`)
385
- - Responsibilities: Data migrations, maintenance
386
-
387
- **Configuration & Boot:**
388
- - Location: `config/application.rb`, `config/initializers/`
389
- - Triggers: Server start, console, job worker boot
390
- - Responsibilities: Gem config, middleware, service connections
391
-
392
- ## Error Handling
393
-
394
- **Strategy:** `rescue_from` in `ApplicationController`, custom error pages, Sentry for tracking
395
-
396
- **Patterns:**
397
- - `rescue_from ActiveRecord::RecordNotFound` → 404 page
398
- - `rescue_from NotAuthorizedError` → 403 or redirect with flash
399
- - Model validation errors re-render form with `@model.errors`
400
- - Service objects return `Result` structs (success/failure) instead of raising
401
- - Jobs use `retry_on` for transient failures, `discard_on` for permanent ones
402
-
403
- ## Cross-Cutting Concerns
404
-
405
- **Logging:**
406
- - `Rails.logger` with tagged logging (request ID, user ID)
407
- - Lograge for single-line structured request logs
408
-
409
- **Validation:**
410
- - ActiveModel validations in models (presence, uniqueness, format)
411
- - Strong parameters in controllers
412
- - Custom validators in `app/validators/`
413
-
414
- **Authentication:**
415
- - Rails authentication generator with `Authentication` concern and database-tracked sessions
416
- - `require_authentication` filter on all non-public controllers
417
-
418
- **Authorization:**
419
- - `authorize` calls in controller actions
420
- - Scoped queries via `policy_scope`
421
-
422
- **Caching:**
423
- - Fragment caching on project dashboard partials
424
- - Russian doll caching for nested task lists
425
- - `Rails.cache` backed by Solid Cache for expensive queries
426
-
427
- ---
428
-
429
- *Architecture analysis: 2025-01-20*
430
- *Update when major patterns change*
431
- ```
432
- </good_examples>
433
-
434
- <guidelines>
435
- **What belongs in ARCHITECTURE.md:**
436
- - Overall Rails pattern (monolith, API-only, engine-based, modular monolith)
437
- - Multi-tenancy approach (if any) and Current context setup
438
- - Model design philosophy — where business logic lives (thin controller/rich model vs service-heavy)
439
- - Concern architecture — shared vs model-specific, naming conventions, composition depth, template method pattern
440
- - Controller patterns — resource nesting, controller concerns, response formats
441
- - Association defaults and context propagation (lambda defaults)
442
- - Background job patterns — _now/_later convention, thin jobs, tenant context in async
443
- - Data flow including Turbo/Hotwire and background job lifecycle
444
- - Presenter/view model patterns (if present) — where they live, how they're instantiated
445
- - Entry points, error handling, and cross-cutting concerns
446
-
447
- **What does NOT belong here:**
448
- - Exhaustive file listings (that's STRUCTURE.md)
449
- - Technology choices and gem versions (that's STACK.md)
450
- - Line-by-line code walkthrough (defer to code reading)
451
- - Database schema details (defer to `db/schema.rb`)
452
- - Individual route listings (defer to `config/routes.rb`)
453
-
454
- **File paths ARE welcome:**
455
- Include file paths as concrete examples of abstractions. Use backtick formatting: `app/models/card/closeable.rb`. This makes the architecture document actionable for Claude when planning.
456
-
457
- **When filling this template:**
458
- - Read `config/routes.rb` to understand resource structure, nesting, and whether actions use sub-resources or custom routes
459
- - Check `app/models/concerns/` for shared concerns — note naming conventions and how many exist
460
- - Check for model-specific concern directories (`app/models/card/`, `app/models/board/`) — these reveal concern composition depth
461
- - Read 2-3 model files to understand concern composition — count how many concerns a core model includes
462
- - Read a model-specific concern to understand anatomy: `included do` block, public API, override points
463
- - Read `app/controllers/application_controller.rb` and controller concerns (`app/controllers/concerns/`) for shared patterns
464
- - Read a nested controller (e.g., `cards/closures_controller.rb`) to identify resource nesting vs custom actions
465
- - Check if `Current` model exists (`app/models/current.rb`) and what attributes it holds
466
- - Look for lambda defaults on `belongs_to` associations — these reveal context propagation patterns
467
- - Read a job file to identify thin-job vs logic-in-job pattern, and check for `_now/_later` naming
468
- - Check `config/initializers/` for ActiveJob extensions that capture tenant context
469
- - Look for presenter/PORO classes in `app/models/` subdirectories or `app/presenters/`
470
- - Trace a full request: route → controller concern → controller action → model method → view
471
- - Keep descriptions conceptual, not mechanical
472
-
473
- **Useful for phase planning when:**
474
- - Adding new features (which layer handles it? controller + model concern + view + job?)
475
- - Adding a new model capability (follow the concern pattern — concern + scopes + API methods + event tracking)
476
- - Adding a new action (model it as a sub-resource? create concern + controller + route)
477
- - Refactoring fat models or controllers (extract to concern? follow existing naming conventions)
478
- - Understanding how multi-tenancy propagates through the stack (Current → lambda defaults → job serialization)
479
- - Adding background processing (follow _now/_later pattern, tenant context is automatic)
480
- - Debugging request flow (what middleware and filters run? what does Current hold?)
481
- </guidelines>