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.
- checksums.yaml +4 -4
- data/ariadna.gemspec +0 -1
- data/data/agents/ariadna-codebase-mapper.md +34 -722
- data/data/agents/ariadna-debugger.md +44 -1139
- data/data/agents/ariadna-executor.md +75 -396
- data/data/agents/ariadna-planner.md +78 -1215
- data/data/agents/ariadna-roadmapper.md +55 -582
- data/data/agents/ariadna-verifier.md +60 -702
- data/data/ariadna/templates/config.json +8 -33
- data/data/ariadna/workflows/debug.md +28 -0
- data/data/ariadna/workflows/execute-phase.md +31 -513
- data/data/ariadna/workflows/map-codebase.md +20 -319
- data/data/ariadna/workflows/new-milestone.md +20 -365
- data/data/ariadna/workflows/new-project.md +19 -880
- data/data/ariadna/workflows/plan-phase.md +24 -443
- data/data/ariadna/workflows/progress.md +20 -376
- data/data/ariadna/workflows/quick.md +19 -221
- data/data/ariadna/workflows/roadmap-ops.md +28 -0
- data/data/ariadna/workflows/verify-work.md +23 -560
- data/data/commands/ariadna/add-phase.md +11 -22
- data/data/commands/ariadna/debug.md +11 -143
- data/data/commands/ariadna/execute-phase.md +12 -30
- data/data/commands/ariadna/insert-phase.md +7 -14
- data/data/commands/ariadna/map-codebase.md +16 -49
- data/data/commands/ariadna/new-milestone.md +12 -25
- data/data/commands/ariadna/new-project.md +22 -26
- data/data/commands/ariadna/plan-phase.md +13 -22
- data/data/commands/ariadna/progress.md +16 -6
- data/data/commands/ariadna/quick.md +9 -11
- data/data/commands/ariadna/remove-phase.md +9 -12
- data/data/commands/ariadna/verify-work.md +14 -19
- data/data/skills/rails-backend/API.md +138 -0
- data/data/skills/rails-backend/CONTROLLERS.md +154 -0
- data/data/skills/rails-backend/JOBS.md +132 -0
- data/data/skills/rails-backend/MODELS.md +213 -0
- data/data/skills/rails-backend/SKILL.md +169 -0
- data/data/skills/rails-frontend/ASSETS.md +154 -0
- data/data/skills/rails-frontend/COMPONENTS.md +253 -0
- data/data/skills/rails-frontend/SKILL.md +187 -0
- data/data/skills/rails-frontend/VIEWS.md +168 -0
- data/data/skills/rails-performance/PROFILING.md +106 -0
- data/data/skills/rails-performance/SKILL.md +217 -0
- data/data/skills/rails-security/AUDIT.md +118 -0
- data/data/skills/rails-security/SKILL.md +422 -0
- data/data/skills/rails-testing/FIXTURES.md +78 -0
- data/data/skills/rails-testing/SKILL.md +160 -0
- data/data/skills/rails-testing/SYSTEM-TESTS.md +73 -0
- data/lib/ariadna/installer.rb +11 -15
- data/lib/ariadna/tools/cli.rb +0 -12
- data/lib/ariadna/tools/config_manager.rb +10 -72
- data/lib/ariadna/tools/frontmatter.rb +23 -1
- data/lib/ariadna/tools/init.rb +201 -401
- data/lib/ariadna/tools/model_profiles.rb +6 -14
- data/lib/ariadna/tools/phase_manager.rb +1 -10
- data/lib/ariadna/tools/state_manager.rb +170 -451
- data/lib/ariadna/tools/template_filler.rb +4 -12
- data/lib/ariadna/tools/verification.rb +21 -399
- data/lib/ariadna/uninstaller.rb +9 -0
- data/lib/ariadna/version.rb +1 -1
- data/lib/ariadna.rb +1 -0
- metadata +20 -91
- data/data/agents/ariadna-backend-executor.md +0 -261
- data/data/agents/ariadna-frontend-executor.md +0 -259
- data/data/agents/ariadna-integration-checker.md +0 -418
- data/data/agents/ariadna-phase-researcher.md +0 -469
- data/data/agents/ariadna-plan-checker.md +0 -622
- data/data/agents/ariadna-project-researcher.md +0 -618
- data/data/agents/ariadna-research-synthesizer.md +0 -236
- data/data/agents/ariadna-test-executor.md +0 -266
- data/data/ariadna/references/checkpoints.md +0 -772
- data/data/ariadna/references/continuation-format.md +0 -249
- data/data/ariadna/references/decimal-phase-calculation.md +0 -65
- data/data/ariadna/references/git-integration.md +0 -248
- data/data/ariadna/references/git-planning-commit.md +0 -38
- data/data/ariadna/references/model-profile-resolution.md +0 -32
- data/data/ariadna/references/model-profiles.md +0 -73
- data/data/ariadna/references/phase-argument-parsing.md +0 -61
- data/data/ariadna/references/planning-config.md +0 -194
- data/data/ariadna/references/questioning.md +0 -153
- data/data/ariadna/references/rails-conventions.md +0 -416
- data/data/ariadna/references/tdd.md +0 -267
- data/data/ariadna/references/ui-brand.md +0 -160
- data/data/ariadna/references/verification-patterns.md +0 -853
- data/data/ariadna/templates/codebase/architecture.md +0 -481
- data/data/ariadna/templates/codebase/concerns.md +0 -380
- data/data/ariadna/templates/codebase/conventions.md +0 -434
- data/data/ariadna/templates/codebase/integrations.md +0 -328
- data/data/ariadna/templates/codebase/stack.md +0 -189
- data/data/ariadna/templates/codebase/structure.md +0 -418
- data/data/ariadna/templates/codebase/testing.md +0 -606
- data/data/ariadna/templates/context.md +0 -283
- data/data/ariadna/templates/continue-here.md +0 -78
- data/data/ariadna/templates/debug-subagent-prompt.md +0 -91
- data/data/ariadna/templates/phase-prompt.md +0 -609
- data/data/ariadna/templates/planner-subagent-prompt.md +0 -117
- data/data/ariadna/templates/research-project/ARCHITECTURE.md +0 -439
- data/data/ariadna/templates/research-project/FEATURES.md +0 -168
- data/data/ariadna/templates/research-project/PITFALLS.md +0 -406
- data/data/ariadna/templates/research-project/STACK.md +0 -251
- data/data/ariadna/templates/research-project/SUMMARY.md +0 -247
- data/data/ariadna/templates/state.md +0 -176
- data/data/ariadna/templates/summary-complex.md +0 -59
- data/data/ariadna/templates/summary-minimal.md +0 -41
- data/data/ariadna/templates/summary-standard.md +0 -48
- data/data/ariadna/templates/user-setup.md +0 -310
- data/data/ariadna/workflows/add-phase.md +0 -111
- data/data/ariadna/workflows/add-todo.md +0 -157
- data/data/ariadna/workflows/audit-milestone.md +0 -241
- data/data/ariadna/workflows/check-todos.md +0 -176
- data/data/ariadna/workflows/complete-milestone.md +0 -644
- data/data/ariadna/workflows/diagnose-issues.md +0 -219
- data/data/ariadna/workflows/discovery-phase.md +0 -289
- data/data/ariadna/workflows/discuss-phase.md +0 -408
- data/data/ariadna/workflows/execute-plan.md +0 -448
- data/data/ariadna/workflows/help.md +0 -470
- data/data/ariadna/workflows/insert-phase.md +0 -129
- data/data/ariadna/workflows/list-phase-assumptions.md +0 -178
- data/data/ariadna/workflows/pause-work.md +0 -122
- data/data/ariadna/workflows/plan-milestone-gaps.md +0 -256
- data/data/ariadna/workflows/remove-phase.md +0 -154
- data/data/ariadna/workflows/research-phase.md +0 -74
- data/data/ariadna/workflows/resume-project.md +0 -306
- data/data/ariadna/workflows/set-profile.md +0 -80
- data/data/ariadna/workflows/settings.md +0 -145
- data/data/ariadna/workflows/transition.md +0 -493
- data/data/ariadna/workflows/update.md +0 -212
- data/data/ariadna/workflows/verify-phase.md +0 -226
- data/data/commands/ariadna/add-todo.md +0 -42
- data/data/commands/ariadna/audit-milestone.md +0 -42
- data/data/commands/ariadna/check-todos.md +0 -41
- data/data/commands/ariadna/complete-milestone.md +0 -136
- data/data/commands/ariadna/discuss-phase.md +0 -86
- data/data/commands/ariadna/help.md +0 -22
- data/data/commands/ariadna/list-phase-assumptions.md +0 -50
- data/data/commands/ariadna/pause-work.md +0 -35
- data/data/commands/ariadna/plan-milestone-gaps.md +0 -40
- data/data/commands/ariadna/reapply-patches.md +0 -110
- data/data/commands/ariadna/research-phase.md +0 -187
- data/data/commands/ariadna/resume-work.md +0 -40
- data/data/commands/ariadna/set-profile.md +0 -34
- data/data/commands/ariadna/settings.md +0 -36
- data/data/commands/ariadna/update.md +0 -37
- data/data/guides/backend.md +0 -3069
- data/data/guides/frontend.md +0 -1479
- data/data/guides/performance.md +0 -1193
- data/data/guides/security.md +0 -1522
- data/data/guides/style-guide.md +0 -1091
- data/data/guides/testing.md +0 -504
- 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>
|