@mohammadhprp/system-prompt 0.12.2 → 0.12.4
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.
- package/framework/commands/README.md +1 -1
- package/framework/commands/review.md +1 -1
- package/framework/mcps/README.md +0 -1
- package/framework/plugins/ponytail/README.md +0 -1
- package/framework/plugins/ponytail/capabilities.md +1 -1
- package/framework/references/standards/api.md +0 -1
- package/framework/references/standards/architecture.md +0 -1
- package/framework/references/standards/database.md +0 -1
- package/framework/references/standards/debugging.md +0 -1
- package/framework/references/standards/documentation.md +0 -1
- package/framework/references/standards/logging.md +0 -1
- package/framework/references/standards/naming.md +0 -1
- package/framework/references/standards/observability.md +0 -1
- package/framework/references/standards/performance.md +0 -1
- package/framework/references/standards/pull-requests.md +0 -1
- package/framework/references/standards/security.md +0 -1
- package/framework/references/standards/testing.md +0 -1
- package/framework/skills/README.md +16 -12
- package/framework/skills/architect/SKILL.md +83 -0
- package/framework/skills/architect/examples.md +5 -0
- package/framework/skills/architect/references/design-red-flags.md +33 -0
- package/framework/skills/architect/references/rationale-template.md +35 -0
- package/framework/skills/architect/references/runner-prompt.md +20 -0
- package/framework/skills/arena/SKILL.md +71 -0
- package/framework/skills/arena/examples.md +5 -0
- package/framework/skills/bro/SKILL.md +7 -0
- package/framework/skills/bro/examples.md +5 -0
- package/framework/skills/changelog/SKILL.md +41 -0
- package/framework/skills/changelog/examples.md +5 -0
- package/framework/skills/commit/SKILL.md +28 -0
- package/framework/skills/commit/examples.md +5 -0
- package/framework/skills/how/SKILL.md +135 -0
- package/framework/skills/how/examples.md +5 -0
- package/framework/skills/how/references/critic-prompt.md +59 -0
- package/framework/skills/how/references/critique-rubric.md +58 -0
- package/framework/skills/how/references/explainer-prompt.md +55 -0
- package/framework/skills/how/references/explorer-prompt.md +52 -0
- package/framework/skills/improve/SKILL.md +1 -3
- package/framework/skills/improve/examples.md +1 -1
- package/framework/skills/laravel-best-practices/SKILL.md +56 -216
- package/framework/skills/laravel-best-practices/references/architecture.md +1 -1
- package/framework/skills/laravel-best-practices/references/checklist.md +139 -0
- package/framework/skills/laravel-best-practices/references/eloquent.md +4 -2
- package/framework/skills/laravel-best-practices/references/infer-conventions.md +97 -0
- package/framework/skills/laravel-best-practices/references/pest-testing.md +47 -18
- package/framework/skills/laravel-best-practices/references/security.md +1 -1
- package/framework/skills/laravel-best-practices/references/style.md +1 -1
- package/framework/skills/laravel-best-practices/references/tailwindcss.md +0 -1
- package/framework/skills/merge-request/SKILL.md +40 -0
- package/framework/skills/merge-request/examples.md +5 -0
- package/framework/skills/pull-request/SKILL.md +31 -0
- package/framework/skills/pull-request/examples.md +5 -0
- package/framework/skills/release/SKILL.md +30 -0
- package/framework/skills/release/examples.md +5 -0
- package/framework/skills/review/SKILL.md +18 -0
- package/framework/skills/review/examples.md +5 -0
- package/framework/skills/tdd/SKILL.md +44 -0
- package/framework/skills/tdd/examples.md +5 -0
- package/framework/skills/unslop/SKILL.md +81 -0
- package/framework/skills/unslop/examples.md +5 -0
- package/framework/skills/why/SKILL.md +230 -0
- package/framework/skills/why/examples.md +5 -0
- package/framework/skills/why/references/epistemics.md +144 -0
- package/framework/skills/why/references/investigator-prompt.md +103 -0
- package/framework/skills/why/references/source-playbook.md +17 -0
- package/framework/skills/why/references/sources/code-archaeology.md +88 -0
- package/framework/skills/why/references/sources/databricks.md +70 -0
- package/framework/skills/why/references/sources/datadog.md +99 -0
- package/framework/skills/why/references/sources/incident-postmortem.md +15 -0
- package/framework/skills/why/references/sources/linear.md +48 -0
- package/framework/skills/why/references/sources/notion.md +55 -0
- package/framework/skills/why/references/sources/sentry.md +100 -0
- package/framework/skills/why/references/sources/slack.md +54 -0
- package/framework/skills/why/references/synthesizer-prompt.md +135 -0
- package/package.json +1 -1
- package/src/catalog.js +13 -12
- package/framework/mcps/notion-mcp/README.md +0 -57
- package/framework/mcps/notion-mcp/capabilities.md +0 -118
- package/framework/mcps/notion-mcp/configs/opencode.json +0 -9
- package/framework/mcps/notion-mcp/install.md +0 -70
- package/framework/mcps/notion-mcp/troubleshooting.md +0 -95
- package/framework/skills/brainstorming/SKILL.md +0 -159
- package/framework/skills/brainstorming/examples.md +0 -49
- package/framework/skills/brainstorming/scripts/frame-template.html +0 -213
- package/framework/skills/brainstorming/scripts/helper.js +0 -167
- package/framework/skills/brainstorming/scripts/server.cjs +0 -723
- package/framework/skills/brainstorming/scripts/start-server.sh +0 -209
- package/framework/skills/brainstorming/scripts/stop-server.sh +0 -120
- package/framework/skills/brainstorming/visual-companion.md +0 -291
- package/framework/skills/code-review/SKILL.md +0 -72
- package/framework/skills/code-review/examples.md +0 -31
- package/framework/skills/codenavi/SKILL.md +0 -306
- package/framework/skills/codenavi/examples.md +0 -33
- package/framework/skills/codenavi/references/coding-principles.md +0 -143
- package/framework/skills/codenavi/references/notebook-spec.md +0 -171
- package/framework/skills/create-adr/SKILL.md +0 -429
- package/framework/skills/create-adr/examples.md +0 -35
- package/framework/skills/design/SKILL.md +0 -399
- package/framework/skills/design/examples.md +0 -34
- package/framework/skills/great-interface/SKILL.md +0 -43
- package/framework/skills/great-interface/references/animations.md +0 -205
- package/framework/skills/great-interface/references/better-accessibility.md +0 -106
- package/framework/skills/great-interface/references/better-colors.md +0 -100
- package/framework/skills/great-interface/references/better-interface.md +0 -132
- package/framework/skills/great-interface/references/better-layout.md +0 -76
- package/framework/skills/great-interface/references/better-typography.md +0 -157
- package/framework/skills/great-interface/references/better-ui.md +0 -107
- package/framework/skills/great-interface/references/better-writing.md +0 -109
- package/framework/skills/great-interface/references/choosing-fonts.md +0 -64
- package/framework/skills/great-interface/references/color-formats.md +0 -90
- package/framework/skills/great-interface/references/color-usage.md +0 -118
- package/framework/skills/great-interface/references/contrast.md +0 -79
- package/framework/skills/great-interface/references/css-cheat-sheet.md +0 -65
- package/framework/skills/great-interface/references/details-and-accessibility.md +0 -119
- package/framework/skills/great-interface/references/enter-exit.md +0 -147
- package/framework/skills/great-interface/references/explain-interface.md +0 -126
- package/framework/skills/great-interface/references/find-the-effect.md +0 -94
- package/framework/skills/great-interface/references/focus-and-keyboard.md +0 -131
- package/framework/skills/great-interface/references/forms.md +0 -84
- package/framework/skills/great-interface/references/from-an-image.md +0 -55
- package/framework/skills/great-interface/references/grouping-and-alignment.md +0 -123
- package/framework/skills/great-interface/references/hit-areas.md +0 -94
- package/framework/skills/great-interface/references/icon-transitions.md +0 -102
- package/framework/skills/great-interface/references/icons.md +0 -110
- package/framework/skills/great-interface/references/interface-review.md +0 -148
- package/framework/skills/great-interface/references/motion-and-zoom.md +0 -79
- package/framework/skills/great-interface/references/no-browser.md +0 -73
- package/framework/skills/great-interface/references/palette-generation.md +0 -104
- package/framework/skills/great-interface/references/palette-structure.md +0 -76
- package/framework/skills/great-interface/references/performance.md +0 -88
- package/framework/skills/great-interface/references/picker.md +0 -76
- package/framework/skills/great-interface/references/read-the-system.md +0 -178
- package/framework/skills/great-interface/references/removed-signals.md +0 -38
- package/framework/skills/great-interface/references/review-format.md +0 -46
- package/framework/skills/great-interface/references/scope-resolution.md +0 -88
- package/framework/skills/great-interface/references/screen-readers.md +0 -101
- package/framework/skills/great-interface/references/semantics-and-aria.md +0 -84
- package/framework/skills/great-interface/references/spacing-and-adaptivity.md +0 -159
- package/framework/skills/great-interface/references/spacing-and-sizing.md +0 -121
- package/framework/skills/great-interface/references/surfaces.md +0 -219
- package/framework/skills/great-interface/references/token-naming.md +0 -97
- package/framework/skills/great-interface/references/variable-fonts-and-opentype.md +0 -105
- package/framework/skills/great-interface/references/variant.md +0 -104
- package/framework/skills/great-interface/references/wrapping-and-punctuation.md +0 -55
- package/framework/skills/learning-opportunities/SKILL.md +0 -140
- package/framework/skills/learning-opportunities/examples.md +0 -34
- package/framework/skills/learning-opportunities/references/PRINCIPLES.md +0 -42
- package/framework/skills/notion-mcp/SKILL.md +0 -57
- package/framework/skills/notion-mcp/examples.md +0 -31
- package/framework/skills/notion-mcp/references/comments.md +0 -112
- package/framework/skills/notion-mcp/references/databases.md +0 -193
- package/framework/skills/notion-mcp/references/pages.md +0 -235
- package/framework/skills/spec-driven-eval/SKILL.md +0 -341
- package/framework/skills/spec-driven-eval/examples.md +0 -35
- package/framework/skills/spec-driven-eval/references/quickstart.md +0 -118
- package/framework/skills/spec-driven-eval/references/reference.md +0 -295
- package/framework/skills/technical-design-doc-creator/README.md +0 -411
- package/framework/skills/technical-design-doc-creator/SKILL.md +0 -1484
- package/framework/skills/technical-design-doc-creator/examples.md +0 -35
- package/framework/skills/web-design-guidelines/SKILL.md +0 -65
- package/framework/skills/web-design-guidelines/examples.md +0 -32
- package/framework/skills/web-design-guidelines/references/guideline.md +0 -174
|
@@ -1,229 +1,69 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: laravel-best-practices
|
|
3
|
-
description: "Apply this skill whenever writing, reviewing, or refactoring Laravel PHP code."
|
|
4
|
-
|
|
3
|
+
description: "Apply this skill whenever writing, reviewing, or refactoring Laravel PHP code. This includes creating or modifying controllers, models, migrations, form requests, policies, jobs, scheduled commands, service classes, and Eloquent queries. Triggers for N+1 and query performance issues, caching strategies, authorization and security patterns, validation, error handling, queue and job configuration, route definitions, and architectural decisions. Also use for Laravel code reviews and refactoring existing Laravel code to follow best practices. Covers any task involving Laravel backend PHP code patterns."
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: laravel
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Laravel Best Practices
|
|
8
10
|
|
|
9
|
-
Best practices for Laravel,
|
|
11
|
+
Best practices for Laravel, organized as an index of reference files. Each reference file teaches what to do and why. For exact API syntax, verify with `search-docs`.
|
|
10
12
|
|
|
11
13
|
## Consistency First
|
|
12
14
|
|
|
13
|
-
Before applying any
|
|
15
|
+
Before applying any reference, check what the application already does. Laravel offers multiple valid approaches, and the best choice is the one the codebase already uses, even if another pattern would be theoretically better. Inconsistency is worse than a suboptimal pattern.
|
|
14
16
|
|
|
15
|
-
Check sibling files, related controllers, models, or tests for established patterns. If one exists, follow it
|
|
16
|
-
|
|
17
|
-
## Quick Reference
|
|
18
|
-
|
|
19
|
-
### 1. Database Performance → `references/db-performance.md`
|
|
20
|
-
|
|
21
|
-
- Eager load with `with()` to prevent N+1 queries
|
|
22
|
-
- Enable `Model::preventLazyLoading()` in development
|
|
23
|
-
- Select only needed columns, avoid `SELECT *`
|
|
24
|
-
- `chunk()` / `chunkById()` for large datasets
|
|
25
|
-
- Index columns used in `WHERE`, `ORDER BY`, `JOIN`
|
|
26
|
-
- `withCount()` instead of loading relations to count
|
|
27
|
-
- `cursor()` for memory-efficient read-only iteration
|
|
28
|
-
- Never query in Blade templates
|
|
29
|
-
|
|
30
|
-
### 2. Advanced Query Patterns → `references/advanced-queries.md`
|
|
31
|
-
|
|
32
|
-
- `addSelect()` subqueries over eager-loading entire has-many for a single value
|
|
33
|
-
- Dynamic relationships via subquery FK + `belongsTo`
|
|
34
|
-
- Conditional aggregates (`CASE WHEN` in `selectRaw`) over multiple count queries
|
|
35
|
-
- `setRelation()` to prevent circular N+1 queries
|
|
36
|
-
- `whereIn` + `pluck()` over `whereHas` for better index usage
|
|
37
|
-
- Two simple queries can beat one complex query
|
|
38
|
-
- Compound indexes matching `orderBy` column order
|
|
39
|
-
- Correlated subqueries in `orderBy` for has-many sorting (avoid joins)
|
|
40
|
-
|
|
41
|
-
### 3. Security → `references/security.md`, `references/passport.md`, `references/spatie-laravel-permission.md`
|
|
42
|
-
|
|
43
|
-
- Define `$fillable` or `$guarded` on every model, authorize every action via policies or gates
|
|
44
|
-
- No raw SQL with user input — use Eloquent or query builder
|
|
45
|
-
- `{{ }}` for output escaping, `@csrf` on all POST/PUT/DELETE forms, `throttle` on auth and API routes
|
|
46
|
-
- Validate MIME type, extension, and size for file uploads
|
|
47
|
-
- Never commit `.env`, use `config()` for secrets, `encrypted` cast for sensitive DB fields
|
|
48
|
-
|
|
49
|
-
### 4. Caching → `references/caching.md`
|
|
50
|
-
|
|
51
|
-
- `Cache::remember()` over manual get/put
|
|
52
|
-
- `Cache::flexible()` for stale-while-revalidate on high-traffic data
|
|
53
|
-
- `Cache::memo()` to avoid redundant cache hits within a request
|
|
54
|
-
- Cache tags to invalidate related groups
|
|
55
|
-
- `Cache::add()` for atomic conditional writes
|
|
56
|
-
- `once()` to memoize per-request or per-object lifetime
|
|
57
|
-
- `Cache::lock()` / `lockForUpdate()` for race conditions
|
|
58
|
-
- Failover cache stores in production
|
|
59
|
-
|
|
60
|
-
### 5. Eloquent Patterns → `references/eloquent.md`
|
|
61
|
-
|
|
62
|
-
- Correct relationship types with return type hints
|
|
63
|
-
- Local scopes for reusable query constraints
|
|
64
|
-
- Global scopes sparingly — document their existence
|
|
65
|
-
- Attribute casts in the `casts()` method
|
|
66
|
-
- Cast date columns, use Carbon instances in templates
|
|
67
|
-
- `whereBelongsTo($model)` for cleaner queries
|
|
68
|
-
- Never hardcode table names — use `(new Model)->getTable()` or Eloquent queries
|
|
69
|
-
|
|
70
|
-
### 6. Validation & Forms → `references/validation.md`
|
|
71
|
-
|
|
72
|
-
- Form Request classes, not inline validation
|
|
73
|
-
- Array notation `['required', 'email']` for new code; follow existing convention
|
|
74
|
-
- `$request->validated()` only — never `$request->all()`
|
|
75
|
-
- `Rule::when()` for conditional validation
|
|
76
|
-
- `after()` instead of `withValidator()`
|
|
77
|
-
|
|
78
|
-
### 7. Configuration → `references/config.md`
|
|
79
|
-
|
|
80
|
-
- `env()` only inside config files
|
|
81
|
-
- `App::environment()` or `app()->isProduction()`
|
|
82
|
-
- Config, lang files, and constants over hardcoded text
|
|
83
|
-
|
|
84
|
-
### 8. Testing Patterns → `references/testing.md`, `references/pest-testing.md`
|
|
85
|
-
|
|
86
|
-
- `LazilyRefreshDatabase` over `RefreshDatabase` for speed
|
|
87
|
-
- `assertModelExists()` over raw `assertDatabaseHas()`
|
|
88
|
-
- Factory states and sequences over manual overrides
|
|
89
|
-
- Use fakes (`Event::fake()`, `Exceptions::fake()`, etc.) — but always after factory setup, not before
|
|
90
|
-
- `recycle()` to share relationship instances across factories
|
|
91
|
-
|
|
92
|
-
### 9. Queue & Job Patterns → `references/queue-jobs.md`
|
|
93
|
-
|
|
94
|
-
- `retry_after` must exceed job `timeout`; use exponential backoff `[1, 5, 10]`
|
|
95
|
-
- `ShouldBeUnique` to prevent duplicates; `ShouldBeUniqueUntilProcessing` for early lock release
|
|
96
|
-
- Always implement `failed()`; with `retryUntil()`, set `$tries = 0`
|
|
97
|
-
- `RateLimited` middleware for external API calls; `Bus::batch()` for related jobs
|
|
98
|
-
- Horizon for complex multi-queue scenarios
|
|
99
|
-
|
|
100
|
-
### 10. Routing & Controllers → `references/routing.md`
|
|
101
|
-
|
|
102
|
-
- Implicit route model binding
|
|
103
|
-
- Scoped bindings for nested resources
|
|
104
|
-
- `Route::resource()` or `apiResource()`
|
|
105
|
-
- Methods under 10 lines — extract to actions/services
|
|
106
|
-
- Type-hint Form Requests for auto-validation
|
|
107
|
-
|
|
108
|
-
### 11. HTTP Client → `references/http-client.md`
|
|
109
|
-
|
|
110
|
-
- Explicit `timeout` and `connectTimeout` on every request
|
|
111
|
-
- `retry()` with exponential backoff for external APIs
|
|
112
|
-
- Check response status or use `throw()`
|
|
113
|
-
- `Http::pool()` for concurrent independent requests
|
|
114
|
-
- `Http::fake()` and `preventStrayRequests()` in tests
|
|
115
|
-
|
|
116
|
-
### 12. Events, Notifications & Mail → `references/events-notifications.md`, `references/mail.md`
|
|
117
|
-
|
|
118
|
-
- Event discovery over manual registration; `event:cache` in production
|
|
119
|
-
- `ShouldDispatchAfterCommit` / `afterCommit()` inside transactions
|
|
120
|
-
- Queue notifications and mailables with `ShouldQueue`
|
|
121
|
-
- On-demand notifications for non-user recipients
|
|
122
|
-
- `HasLocalePreference` on notifiable models
|
|
123
|
-
- `assertQueued()` not `assertSent()` for queued mailables
|
|
124
|
-
- Markdown mailables for transactional emails
|
|
125
|
-
|
|
126
|
-
### 13. Error Handling → `references/error-handling.md`
|
|
127
|
-
|
|
128
|
-
- `report()`/`render()` on exception classes or in `bootstrap/app.php` — follow existing pattern
|
|
129
|
-
- `ShouldntReport` for exceptions that should never log
|
|
130
|
-
- Throttle high-volume exceptions to protect log sinks
|
|
131
|
-
- `dontReportDuplicates()` for multi-catch scenarios
|
|
132
|
-
- Force JSON rendering for API routes
|
|
133
|
-
- Structured context via `context()` on exception classes
|
|
134
|
-
|
|
135
|
-
### 14. Task Scheduling → `references/scheduling.md`
|
|
136
|
-
|
|
137
|
-
- `withoutOverlapping()` on variable-duration tasks
|
|
138
|
-
- `onOneServer()` on multi-server deployments
|
|
139
|
-
- `runInBackground()` for concurrent long tasks
|
|
140
|
-
- `environments()` to restrict to appropriate environments
|
|
141
|
-
- `takeUntilTimeout()` for time-bounded processing
|
|
142
|
-
- Schedule groups for shared configuration
|
|
143
|
-
|
|
144
|
-
### 15. Architecture → `references/architecture.md`
|
|
145
|
-
|
|
146
|
-
- Single-purpose Action classes; dependency injection over `app()` helper
|
|
147
|
-
- Prefer official Laravel packages and follow conventions, don't override defaults
|
|
148
|
-
- Default to `ORDER BY id DESC` or `created_at DESC`; `mb_*` for UTF-8 safety
|
|
149
|
-
- `defer()` for post-response work; `Context` for request-scoped data; `Concurrency::run()` for parallel execution
|
|
150
|
-
|
|
151
|
-
### 16. Migrations → `references/migrations.md`
|
|
152
|
-
|
|
153
|
-
- Generate migrations with `php artisan make:migration`
|
|
154
|
-
- `constrained()` for foreign keys
|
|
155
|
-
- Never modify migrations that have run in production
|
|
156
|
-
- Add indexes in the migration, not as an afterthought
|
|
157
|
-
- Mirror column defaults in model `$attributes`
|
|
158
|
-
- Reversible `down()` by default; forward-fix migrations for intentionally irreversible changes
|
|
159
|
-
- One concern per migration — never mix DDL and DML
|
|
160
|
-
|
|
161
|
-
### 17. Collections → `references/collections.md`
|
|
162
|
-
|
|
163
|
-
- Higher-order messages for simple collection operations
|
|
164
|
-
- `cursor()` vs. `lazy()` — choose based on relationship needs
|
|
165
|
-
- `lazyById()` when updating records while iterating
|
|
166
|
-
- `toQuery()` for bulk operations on collections
|
|
167
|
-
|
|
168
|
-
### 18. Blade & Views → `references/blade-views.md`, `references/tailwindcss.md`
|
|
169
|
-
|
|
170
|
-
- `$attributes->merge()` in component templates
|
|
171
|
-
- Blade components over `@include`; `@pushOnce` for per-component scripts
|
|
172
|
-
- View Composers for shared view data
|
|
173
|
-
- `@aware` for deeply nested component props
|
|
174
|
-
|
|
175
|
-
### 19. Conventions & Style → `references/style.md`
|
|
176
|
-
|
|
177
|
-
- Follow Laravel naming conventions for all entities
|
|
178
|
-
- Prefer Laravel helpers (`Str`, `Arr`, `Number`, `Uri`, `Str::of()`, `$request->string()`) over raw PHP functions
|
|
179
|
-
- No JS/CSS in Blade, no HTML in PHP classes
|
|
180
|
-
- Code should be readable; comments only for config files
|
|
181
|
-
|
|
182
|
-
### 20. Feature Flags → `references/pennant.md`
|
|
183
|
-
|
|
184
|
-
- `Feature::define()` to define features with resolver callbacks
|
|
185
|
-
- `Feature::active()` / `@feature` Blade directive to check features
|
|
186
|
-
- Scope features to specific users/entities with `Feature::for()`
|
|
187
|
-
- `Feature::activate()` / `deactivate()` for runtime control
|
|
188
|
-
|
|
189
|
-
### 21. Monitoring → `references/pulse.md`
|
|
190
|
-
|
|
191
|
-
- Gate-protect the dashboard with `viewPulse` gate
|
|
192
|
-
- Configure built-in recorders in `config/pulse.php` (SlowQueries, SlowRequests, Exceptions, Queues, etc.)
|
|
193
|
-
- Redis ingest for production performance; run `pulse:work` to drain the stream
|
|
194
|
-
- Custom cards via Livewire components extending `Pulse\Card`
|
|
195
|
-
- `Pulse::filter()` to exclude entries; `Pulse::resolveAuthenticatedUserId()` for multi-model apps
|
|
196
|
-
- `pulse:check` daemon required for Servers card
|
|
197
|
-
|
|
198
|
-
### 22. Full-Text Search → `references/scout.md`
|
|
199
|
-
|
|
200
|
-
- Add `Searchable` trait to models for automatic index sync
|
|
201
|
-
- Choose engine: Database, Collection, Algolia, Meilisearch, Typesense
|
|
202
|
-
- `toSearchableArray()` to control indexed data; `searchableAs()` for custom index names
|
|
203
|
-
- `Model::search('query')->where(...)->paginate()` for search queries
|
|
204
|
-
- `scout:import` / `scout:flush` for index management; `scout:sync-index-settings` for engine config
|
|
205
|
-
- `Model::withoutSyncingToSearch()` / `SCOUT_DRIVER=null` for testing
|
|
206
|
-
|
|
207
|
-
### 23. Backup → `references/spatie-laravel-backup.md`
|
|
208
|
-
|
|
209
|
-
- Schedule `backup:run`, `backup:clean`, `backup:monitor` in console kernel
|
|
210
|
-
- Configure sources, destinations, notifications in `config/backup.php`
|
|
211
|
-
- Custom cleanup strategies extending `CleanupStrategy`
|
|
212
|
-
- Custom health checks extending `HealthCheck`
|
|
213
|
-
- Enable encryption and Gzip compression via config
|
|
214
|
-
|
|
215
|
-
### 24. Media Library → `references/spatie-medialibrary.md`
|
|
216
|
-
|
|
217
|
-
- Implement `HasMedia` interface + `InteractsWithMedia` trait on models
|
|
218
|
-
- `addMedia()` / `addMediaFromRequest()` for file uploads
|
|
219
|
-
- Media collections to organize related files per model
|
|
220
|
-
- Conversions for image processing (thumbnails, crops, etc.)
|
|
221
|
-
- Responsive images via conversion `withResponsiveImages()`
|
|
17
|
+
Check sibling files, related controllers, models, or tests for established patterns. If one exists, follow it. Don't introduce a second way. These references are defaults for when no pattern exists yet, not overrides.
|
|
222
18
|
|
|
223
19
|
## How to Apply
|
|
224
20
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
21
|
+
1. Check the changed files, nearby code, project configuration, and relevant tests for established patterns. Deviate only for a correctness or security defect, and call the deviation out.
|
|
22
|
+
2. Map every affected concern to the reference index below. Read each mapped reference file before editing. Skip unrelated reference files.
|
|
23
|
+
3. Make the smallest coherent change. Keep the application's architecture and naming instead of introducing a second pattern for the same job.
|
|
24
|
+
4. Verify version-sensitive Laravel APIs for the installed version with `search-docs`, or inspect the installed framework when it is unavailable.
|
|
25
|
+
5. Run the narrowest relevant tests first, then the project's formatting and static-analysis checks when the change warrants them.
|
|
26
|
+
6. Re-read the diff against every mapped reference before finishing.
|
|
27
|
+
|
|
28
|
+
## References Index
|
|
29
|
+
|
|
30
|
+
Cross-cutting changes often need more than one reference file.
|
|
31
|
+
|
|
32
|
+
| Concern | Read |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| Query count, eager loading, indexes, large datasets | [`references/db-performance.md`](references/db-performance.md) |
|
|
35
|
+
| Production monitoring, slow queries, exception dashboards | [`references/pulse.md`](references/pulse.md) |
|
|
36
|
+
| Subqueries, aggregates, complex ordering and query plans | [`references/advanced-queries.md`](references/advanced-queries.md) |
|
|
37
|
+
| Models, relationships, scopes, casts | [`references/eloquent.md`](references/eloquent.md) |
|
|
38
|
+
| Full-text search, indexing, searchable models | [`references/scout.md`](references/scout.md) |
|
|
39
|
+
| Authentication, authorization, input safety, secrets, uploads | [`references/security.md`](references/security.md) |
|
|
40
|
+
| OAuth2 servers, clients, token authentication | [`references/passport.md`](references/passport.md) |
|
|
41
|
+
| Roles and permissions with spatie/laravel-permission | [`references/spatie-laravel-permission.md`](references/spatie-laravel-permission.md) |
|
|
42
|
+
| Model media uploads, conversions, responsive images | [`references/spatie-medialibrary.md`](references/spatie-medialibrary.md) |
|
|
43
|
+
| Form Requests and validation references | [`references/validation.md`](references/validation.md) |
|
|
44
|
+
| Controllers, route binding, resources, middleware | [`references/routing.md`](references/routing.md) |
|
|
45
|
+
| Schema changes, columns, foreign keys, indexes | [`references/migrations.md`](references/migrations.md) |
|
|
46
|
+
| Jobs, retries, uniqueness, batches, Horizon | [`references/queue-jobs.md`](references/queue-jobs.md) |
|
|
47
|
+
| Cache lifetime, invalidation, locks, memoization | [`references/caching.md`](references/caching.md) |
|
|
48
|
+
| Outbound requests, retries, timeouts, fakes | [`references/http-client.md`](references/http-client.md) |
|
|
49
|
+
| Exceptions, reporting, rendering, log context | [`references/error-handling.md`](references/error-handling.md) |
|
|
50
|
+
| Events and notifications | [`references/events-notifications.md`](references/events-notifications.md) |
|
|
51
|
+
| Mailables and mail assertions | [`references/mail.md`](references/mail.md) |
|
|
52
|
+
| Scheduled tasks and overlap protection | [`references/scheduling.md`](references/scheduling.md) |
|
|
53
|
+
| Database backups, cleanup, monitoring, notifications | [`references/spatie-laravel-backup.md`](references/spatie-laravel-backup.md) |
|
|
54
|
+
| Collections, lazy iteration, bulk operations | [`references/collections.md`](references/collections.md) |
|
|
55
|
+
| Blade components, attributes, composers | [`references/blade-views.md`](references/blade-views.md) |
|
|
56
|
+
| Tailwind CSS classes, v4 configuration, extraction | [`references/tailwindcss.md`](references/tailwindcss.md) |
|
|
57
|
+
| Environment values and application configuration | [`references/config.md`](references/config.md) |
|
|
58
|
+
| Feature flags and per-user feature checks | [`references/pennant.md`](references/pennant.md) |
|
|
59
|
+
| Pest/PHPUnit patterns, factories, fakes | [`references/testing.md`](references/testing.md) |
|
|
60
|
+
| Pest 4 syntax, datasets, browser and architecture tests | [`references/pest-testing.md`](references/pest-testing.md) |
|
|
61
|
+
| Naming, helpers, file boundaries, PHP style | [`references/style.md`](references/style.md) |
|
|
62
|
+
| Actions, services, dependencies, application structure | [`references/architecture.md`](references/architecture.md) |
|
|
63
|
+
| Detecting and recording this app's conventions as rules | [`references/infer-conventions.md`](references/infer-conventions.md) |
|
|
64
|
+
|
|
65
|
+
## Decision rule
|
|
66
|
+
|
|
67
|
+
- Prefer framework features and existing application abstractions over new helpers or dependencies.
|
|
68
|
+
- Avoid speculative abstractions. Extract code when it creates a clear domain boundary, removes meaningful duplication, or makes behavior independently testable.
|
|
69
|
+
- Keep database access out of Blade views and prevent hidden N+1 queries across controllers, resources, jobs, and serialization.
|
|
@@ -9,7 +9,7 @@ class CreateOrderAction
|
|
|
9
9
|
{
|
|
10
10
|
public function __construct(private InventoryService $inventory) {}
|
|
11
11
|
|
|
12
|
-
public function
|
|
12
|
+
public function handle(array $data): Order
|
|
13
13
|
{
|
|
14
14
|
$order = Order::create($data);
|
|
15
15
|
$this->inventory->reserve($order);
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Detection Checklist
|
|
2
|
+
|
|
3
|
+
Every dimension here is a genuine fork: Laravel offers two or more valid approaches, the app's choice changes what the next agent writes, and no active project tool can pick for you. Left out on purpose: pure formatting (Pint owns it), any form an installed and enabled Rector rule rewrites to one canonical shape (`$casts` to `casts()`, `$fillable` to attributes, pipe-string rules to arrays, named to anonymous migrations, `$signature` to `#[Signature]`), and framework defaults any agent writes unprompted (`ShouldQueue` jobs, relation return types, `HasFactory`).
|
|
4
|
+
|
|
5
|
+
Each item gives the fork, then a hint (a grep or dir to spot which side the app takes). Hints are only a start. Read the matched files, never record on a raw count. Apply the ground rules to every verdict: a consistent choice that is a default or a tool's target form is not a pattern. Rows tagged (architecture) are the highest-signal, so record presence and deliberate absence.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## A. Validation & HTTP input
|
|
10
|
+
|
|
11
|
+
1. Validation entry point: inline `$request->validate()` vs Form Request classes vs `Validator::make()`.
|
|
12
|
+
- Hint: `ls app/Http/Requests`; grep `->validate(` / `Validator::make(` in `app/Http/Controllers`.
|
|
13
|
+
2. Custom rule location: invokable rule objects in `app/Rules` vs inline closures vs `Validator::extend()` in a provider. Rule objects are the default `make:rule` path, so record only if the app leans on closures or `Validator::extend` instead. "No rule objects" alone is just no-signal.
|
|
14
|
+
- Hint: `ls app/Rules`; grep `Validator::extend` in `app/Providers`.
|
|
15
|
+
3. Typed input retrieval: typed getters (`$request->string()`, `->integer()`, `->enum()`, `->date()`) vs raw `$request->input()` / dynamic properties.
|
|
16
|
+
- Hint: grep `->string(` / `->integer(` / `->enum(` vs `->input(` in `app/Http`.
|
|
17
|
+
4. Custom messages/attributes: `lang/*/validation.php` vs Form Request `messages()` / `attributes()` methods.
|
|
18
|
+
- Hint: `ls lang`; grep `function messages`, `function attributes` in `app/Http/Requests`.
|
|
19
|
+
|
|
20
|
+
## B. Controllers & routing
|
|
21
|
+
|
|
22
|
+
1. Controller shape: invokable single-action (`__invoke`) vs resource controllers vs plain multi-method.
|
|
23
|
+
- Hint: grep `__invoke` in controllers; `Route::resource` / `apiResource` vs verb routes.
|
|
24
|
+
2. Business-logic location (architecture): fat controllers vs delegated to Actions / Services / Jobs.
|
|
25
|
+
- Hint: read a few controller methods; `ls app/Actions app/Services`.
|
|
26
|
+
3. Route handler style: closures in `routes/*.php` vs controller classes.
|
|
27
|
+
- Hint: count `function ()` vs `::class` in `routes/web.php`, `routes/api.php`.
|
|
28
|
+
4. Middleware assignment: route/group `->middleware()` vs controller `HasMiddleware::middleware()` vs `#[Middleware]` attribute.
|
|
29
|
+
- Hint: grep `implements HasMiddleware`, `#[Middleware(` in controllers vs `->middleware(` in routes.
|
|
30
|
+
5. Route model binding: implicit (type-hinted models) vs explicit `Route::bind` vs manual `findOrFail`.
|
|
31
|
+
- Hint: typed model params in signatures vs `findOrFail(` in controllers; grep `Route::bind`.
|
|
32
|
+
6. Rate limiting: named `RateLimiter::for()` + `throttle:name` vs inline `throttle:60,1`.
|
|
33
|
+
- Hint: grep `RateLimiter::for` in providers vs `throttle:` in route files.
|
|
34
|
+
|
|
35
|
+
## C. Authorization
|
|
36
|
+
|
|
37
|
+
1. Authorization home: Gates (`Gate::define`) vs Policy classes in `app/Policies`.
|
|
38
|
+
- Hint: `ls app/Policies`; grep `Gate::define` in `app/Providers`.
|
|
39
|
+
2. Authorization call site: `$this->authorize()` / `Gate::authorize()` vs `$user->can()` vs `can` middleware vs `#[Authorize]` vs `@can` in Blade.
|
|
40
|
+
- Hint: grep `authorize(`, `->can(`, `middleware('can:`, `#[Authorize(`, `@can(`.
|
|
41
|
+
|
|
42
|
+
## D. Eloquent & models
|
|
43
|
+
|
|
44
|
+
1. Mass assignment: `$fillable` allow-list vs `$guarded` block-list.
|
|
45
|
+
- Hint: grep `protected $fillable` / `protected $guarded` in `app/Models`.
|
|
46
|
+
2. Accessors/mutators: modern `Attribute` class vs legacy `getXxxAttribute()` / `setXxxAttribute()`. Record a legacy hold, it goes against the tool's grain.
|
|
47
|
+
- Hint: grep `: Attribute` / `Attribute::make` vs `function get[A-Z].*Attribute` in `app/Models`.
|
|
48
|
+
3. Primary keys: auto-increment vs `HasUuids` vs `HasUlids`.
|
|
49
|
+
- Hint: grep `HasUuids` / `HasUlids` in `app/Models`; migration `id()` vs `uuid('id')`.
|
|
50
|
+
4. Custom casts: dedicated `CastsAttributes` classes (`app/Casts`) vs inline `Attribute` vs built-in cast strings.
|
|
51
|
+
- Hint: `ls app/Casts`; grep `Cast::class`, `AsStringable::class` in models.
|
|
52
|
+
5. Data/query layer (architecture): Eloquent directly in controllers vs repositories vs dedicated query objects (e.g. classes exposing `builder(): Builder`).
|
|
53
|
+
- Hint: `ls app/Repositories app/Queries`; see where non-trivial queries are built.
|
|
54
|
+
6. Query scopes: local `scope`/`#[Scope]` methods vs dedicated builder classes.
|
|
55
|
+
- Hint: grep `function scope` / `#[Scope]` in models; `ls app/*/Builders`.
|
|
56
|
+
7. Model events: observers (`app/Observers`, `#[ObservedBy]`) vs `booted()` closures vs event classes.
|
|
57
|
+
- Hint: `ls app/Observers`; grep `booted`, `::observe`, `#[ObservedBy]`.
|
|
58
|
+
8. Eager-load posture: explicit per-query `->with()` vs model-level `$with` defaults. Treat `preventLazyLoading()` separately as a development guard because it can complement either posture.
|
|
59
|
+
- Hint: grep `protected $with`, `->with(`, and separately `preventLazyLoading` in `app/`.
|
|
60
|
+
|
|
61
|
+
## E. Architecture & organization
|
|
62
|
+
|
|
63
|
+
1. Action/Service structure (architecture): Action classes (invoked via `handle` / `execute` / `__invoke`) vs service objects vs neither. Cross-check the Step 0 `app/` map: any `Actions`/`Services`/`Pipelines`/`Jobs`-as-actions folder is this pattern, so record how it is invoked.
|
|
64
|
+
- Hint: `ls app/` (the whole tree, not just `Actions`/`Services`); grep the invocation method in the folder you find.
|
|
65
|
+
2. DTOs (architecture): spatie/laravel-data vs plain readonly classes vs arrays everywhere.
|
|
66
|
+
- Hint: `ls app/Data`; grep `extends Data`, `readonly class` in `app/`.
|
|
67
|
+
3. Dependency acquisition: constructor/method injection vs `app()` / `resolve()` / `App::make()` service location.
|
|
68
|
+
- Hint: grep `app(` / `resolve(` / `::make(` in `app/` vs promoted constructor deps.
|
|
69
|
+
4. Decoupling: events + listeners vs direct service calls.
|
|
70
|
+
- Hint: `ls app/Events app/Listeners`; grep `event(`, `::dispatch(`.
|
|
71
|
+
5. Helper vs facade idiom: global helpers (`config()`, `auth()`, `response()`) vs facades (`Config::`, `Auth::`, `Response::`).
|
|
72
|
+
- Hint: ratio of `config(` vs `Config::` (etc.) across `app/`.
|
|
73
|
+
6. Namespace layout (architecture): default `app/` skeleton vs domain/module folders (`app/Domain/**`, modules).
|
|
74
|
+
- Hint: `ls app/`, look for `Domain/`, `Modules/`, bounded-context folders.
|
|
75
|
+
7. Enums: backed vs pure; case naming; where they live.
|
|
76
|
+
- Hint: `ls app/Enums`; grep `enum .*: string`, `enum .*: int`.
|
|
77
|
+
|
|
78
|
+
## F. Frontend & views
|
|
79
|
+
|
|
80
|
+
This app ships a frontend stack, so the items below apply.
|
|
81
|
+
|
|
82
|
+
1. Frontend stack: Blade+Livewire vs Inertia (Vue/React/Svelte) vs Blade-only / API + separate SPA.
|
|
83
|
+
- Hint: `composer.json` + `package.json`; `ls resources/js/pages`, `resources/views`.
|
|
84
|
+
2. Blade composition: class `<x-*>` components vs anonymous components (`@props`) vs `@include` partials.
|
|
85
|
+
- Hint: `ls app/View/Components`; grep `<x-`, `@include` in `resources/views`.
|
|
86
|
+
3. Livewire component format: Volt functional/class components, native Livewire 4 single-file (SFC), multi-file (MFC), view-based, or class-based components. Evaluate full-page vs nested separately because it is an independent usage choice.
|
|
87
|
+
- Hint: check the installed Livewire major and `livewire/volt`; inspect `app/Livewire`, `resources/views/livewire`, and Livewire 4 component/page directories for `@volt`, SFC, MFC, view-based, and class-based formats.
|
|
88
|
+
4. Localization: short keys (`lang/*/*.php` + `__('messages.welcome')`) vs JSON string keys (`lang/*.json` + `__('Full sentence')`).
|
|
89
|
+
- Hint: `ls lang`; grep dotted `__('` vs sentence keys.
|
|
90
|
+
|
|
91
|
+
## G. Database & migrations
|
|
92
|
+
|
|
93
|
+
1. Foreign keys: `foreignId()->constrained()` vs `foreignIdFor(Model::class)` vs manual `foreign()->references()->on()`.
|
|
94
|
+
- Hint: grep `foreignId(`, `foreignIdFor(`, `->foreign(` in `database/migrations`.
|
|
95
|
+
2. `down()` methods: real reverse logic vs omitted / one-way migrations.
|
|
96
|
+
- Hint: grep `function down` vs the migration count.
|
|
97
|
+
3. Enum storage: DB `enum()` column vs `string()` + PHP-enum cast on the model.
|
|
98
|
+
- Hint: grep `->enum(` in migrations vs string columns cast to enums.
|
|
99
|
+
4. Transactions: `DB::transaction(fn ...)` closure vs manual `beginTransaction` / `commit` / `rollBack`.
|
|
100
|
+
- Hint: grep `DB::transaction`, `beginTransaction` in `app/`.
|
|
101
|
+
5. Idempotent writes: `upsert` / `updateOrCreate` / `firstOrCreate` vs find-then-save.
|
|
102
|
+
- Hint: grep `upsert(`, `updateOrCreate(`, `firstOrCreate(` in `app/`.
|
|
103
|
+
|
|
104
|
+
## H. Testing
|
|
105
|
+
|
|
106
|
+
1. Framework: Pest (`it()` / `test()` / `expect()`) vs PHPUnit classes.
|
|
107
|
+
- Hint: `ls tests/Pest.php`; grep `it(` / `test(` vs `extends TestCase`.
|
|
108
|
+
2. DB reset: `RefreshDatabase` vs `DatabaseTruncation` vs `DatabaseMigrations`.
|
|
109
|
+
- Hint: grep those trait names in `tests/`.
|
|
110
|
+
3. Fixtures: compare how equivalent test-owned records are created, such as factories vs manual inserts. Track seeders separately for shared reference data because `$this->seed()` commonly and legitimately coexists with factories.
|
|
111
|
+
- Hint: grep `::factory(` and direct inserts in `tests/`; separately inspect `$this->seed(` calls and what those seeders provide.
|
|
112
|
+
4. Collaborator isolation: how the app doubles its own classes, Mockery `mock()` / `spy()` vs real integration. Ignore facade fakes like `Mail::fake()` here, they isolate framework services by default and are not a fork against Mockery.
|
|
113
|
+
- Hint: grep `->mock(`, `->spy(`, `Mockery::` in `tests/`.
|
|
114
|
+
5. Endpoint assertions: array `assertJson([...])` / `assertJsonFragment` vs fluent `AssertableJson`.
|
|
115
|
+
- Hint: grep `AssertableJson`, `assertJsonFragment` in `tests/`.
|
|
116
|
+
|
|
117
|
+
## I. Responses & API resources
|
|
118
|
+
|
|
119
|
+
1. Response shape: API Resource classes vs `response()->json()` vs returning models/arrays directly.
|
|
120
|
+
- Hint: `ls app/Http/Resources`; grep `JsonResource`, `->json(` in controllers.
|
|
121
|
+
2. Resource relationship inclusion: `whenLoaded()` guards vs unconditional relationship access. Do not count ordinary scalar attributes as rivals to conditional relationships, and evaluate general `when()` fields separately.
|
|
122
|
+
- Hint: compare relationship fields using `whenLoaded(` with unconditional relationship property access in `app/Http/Resources`.
|
|
123
|
+
3. Pagination contracts: within comparable endpoint categories, length-aware `paginate()` vs `simplePaginate()` vs `cursorPaginate()`. These have different totals, navigation, ordering, and performance contracts, so record only a stable path-scoped API policy, never a project-wide majority.
|
|
124
|
+
- Hint: grep those in `app/`, then group matches by endpoint type and client contract before comparing them.
|
|
125
|
+
4. Web redirects/URLs: `route('name')` vs `url('/path')` vs `action([...])`.
|
|
126
|
+
- Hint: grep `route('`, `url('/`, `action([` in `app/Http` and views.
|
|
127
|
+
|
|
128
|
+
## J. Strings, collections & dates
|
|
129
|
+
|
|
130
|
+
1. Iteration idiom: `collect()->map()->filter()` pipelines vs `array_map` / `foreach`.
|
|
131
|
+
- Hint: grep `collect(`, `->map(` vs `array_map`, `foreach` density in `app/`.
|
|
132
|
+
2. String API: fluent `Str::of()->...` (Stringable) vs static `Str::` vs native (`trim`, `strtoupper`).
|
|
133
|
+
- Hint: grep `Str::of(` vs `Str::` vs native string funcs.
|
|
134
|
+
3. Dates: compare equivalent construction call styles (`now()` / `today()` helpers vs `Carbon::`) separately from the application's mutable/immutable date policy. `Date::use(CarbonImmutable::class)` can make helpers return immutable dates, so those signals are complementary rather than conflicting.
|
|
135
|
+
- Hint: grep `now(` and `Carbon::` for call style; separately inspect `CarbonImmutable` and `Date::use` for mutability policy.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
Genuine forks only. Every row survived the "no tool can decide this, and it isn't the default" filter. Give each applicable dimension exactly one verdict: pattern, conflict, default, no-signal, tooling-owned, or already-recorded. The rows tagged (architecture) are where the highest-value rules come from.
|
|
@@ -30,7 +30,8 @@ $articles = Article::whereHas('user', function ($q) {
|
|
|
30
30
|
|
|
31
31
|
Correct:
|
|
32
32
|
```php
|
|
33
|
-
|
|
33
|
+
#[Scope]
|
|
34
|
+
protected function active(Builder $query): Builder
|
|
34
35
|
{
|
|
35
36
|
return $query->where('verified', true)->whereNotNull('activated_at');
|
|
36
37
|
}
|
|
@@ -58,7 +59,8 @@ class PublishedScope implements Scope
|
|
|
58
59
|
|
|
59
60
|
Correct (local scope you opt into):
|
|
60
61
|
```php
|
|
61
|
-
|
|
62
|
+
#[Scope]
|
|
63
|
+
protected function published(Builder $query): Builder
|
|
62
64
|
{
|
|
63
65
|
return $query->where('published', true);
|
|
64
66
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
|
|
2
|
+
# Infer Conventions
|
|
3
|
+
|
|
4
|
+
Learn how this application writes Laravel, then record what you learn as durable, path-scoped rules other agents will read. You are documenting reality, not improving it.
|
|
5
|
+
|
|
6
|
+
## Ground Rules (read before you start)
|
|
7
|
+
|
|
8
|
+
- Consistency first. The codebase's majority style is the convention. Never judge it, never propose a "better" pattern, never record what the code should do. If the app validates inline everywhere, that is the rule, even if Form Requests would be nicer.
|
|
9
|
+
- Skip what an active tool produces, keep what a tool would fight. Inspect the project's Pint and Rector configuration first; a Rector transformation is tooling-owned only when its package and relevant rule or set are installed and enabled. Active tools may rewrite code toward one canonical form: `$casts` to `casts()`, `$fillable` to attributes, magic accessors to the `Attribute` class, pipe-string rules to arrays, `$signature` to `#[Signature]`, named migrations to anonymous, and many more. When the app already sits at an active tool's target form, the tool owns it, so record nothing. But when the app deliberately holds a form an active tool would refactor away, such as legacy `getXxxAttribute()` accessors the `Attribute` class would replace, no tool can reproduce that choice and an agent defaults the other way. That against-the-grain hold is exactly what to record.
|
|
10
|
+
- Record decisions, not defaults. A consistent pattern earns a rule only when it reflects a choice: the app took one valid option where the framework or common practice offered others, or the pattern would surprise a competent agent. Framework defaults steer nothing, so skip them: anonymous migrations, `$signature` commands, `ShouldQueue` jobs, `casts()` on Laravel 11+, named routes, Rule objects in `app/Rules`, and `Mail::fake()` or `Bus::fake()` to isolate framework services. A real fork is not enough on its own. Weigh the side the app took, and record only the side an agent would not reach for by itself: inline closures everywhere, legacy accessors, a bespoke query layer. Watch for the false fork too. "No Mockery" next to facade fakes is not a choice against Mockery, because they double different things. The test for every candidate: without this rule, would the next agent plausibly write it differently? Only "yes" earns a rule.
|
|
11
|
+
- Architecture choices are the gold. Record presence and deliberate absence. The structural pattern the app commits to is the highest-signal convention and the one no tool can decide: Action classes and how they are invoked (`handle` / `execute` / `__invoke`), service objects, dedicated query objects exposing `builder()`, DTOs (spatie/laravel-data vs readonly classes), Form Request validation vs inline, an events and listeners spine vs direct calls, and domain or module folders. Also record a consistent non-pattern, such as "query Eloquent directly in controllers, no repository layer", so the next agent matches the app's altitude instead of over-engineering.
|
|
12
|
+
- Never duplicate `.ai/rules`. Read `.ai/rules/index.md` and the area files before the sweep. A dimension already covered there is marked done and skipped.
|
|
13
|
+
- Evidence or silence. A convention needs at least 3 consistent examples and no meaningful rival to become a candidate. Every Step 1 verdict applies this bar.
|
|
14
|
+
- The recorded rule states the convention, nothing else. One or two imperative lines: this project does X, so do X here. Keep detection evidence out. No counts, ratios, current usage, file lists, or example paths, because that is proof for the confirm step, not part of the rule. One short syntax fragment at most, and point to `search-docs` for API details.
|
|
15
|
+
|
|
16
|
+
## Process
|
|
17
|
+
|
|
18
|
+
Each step ends on a checkable completion criterion. Do not advance until it holds.
|
|
19
|
+
|
|
20
|
+
Fan out when you can. The sweep is embarrassingly parallel. If your environment can spawn subagents (a Task, dispatch, or equivalent tool), do Step 0 yourself, then hand each checklist group (A to J) and the architecture map to its own subagent. Each subagent runs the greps, reads a few representative files, and returns structured verdicts (dimension, verdict, evidence, proposed glob / title / note). You aggregate, dedupe, then run Steps 3 to 5. It is far faster on a real app. No subagents available? Run the steps in sequence, with the same bar and the same output.
|
|
21
|
+
|
|
22
|
+
### Step 0: Orient
|
|
23
|
+
|
|
24
|
+
Read `composer.json` (installed packages tell you which checklist groups apply), the `pint.json` / PHPStan / Rector config, `.ai/rules/index.md` if present, and most important, map the `app/` tree. List every directory under `app/` (and any `Modules/`, `src/`, `packages/`, or domain root). Every folder beyond Laravel's default skeleton (`Http`, `Models`, `Providers`, `Console`, `Exceptions`) is a structural pattern the app committed to and a high-value rule waiting to be written: `Actions`, `Services`, `Data` or DTOs, `Queries`, `Repositories`, `ViewModels`, `Pipelines`, `Support`, `Enums`, `Contracts`, `Observers`, or `Domain` and module roots. Note each one. You will confirm how it is used in Step 2.
|
|
25
|
+
|
|
26
|
+
This app ships a frontend stack, so the frontend checklist group applies. Sweep it.
|
|
27
|
+
|
|
28
|
+
Done when: you have the applicable checklist groups, the dimensions already recorded in `.ai/rules`, and a list of every non-default `app/` directory mapped to the pattern it represents.
|
|
29
|
+
|
|
30
|
+
### Step 1: Predefined sweep
|
|
31
|
+
|
|
32
|
+
Open `references/checklist.md` and work every applicable dimension using its search hints. Give each exactly one verdict:
|
|
33
|
+
|
|
34
|
+
- Pattern. Clears the bar, rival under ~20% of sites, and reflects a real choice (passes the decisions-not-defaults test). A recording candidate. Cite 2 to 3 example files.
|
|
35
|
+
- Conflict. Both styles present in meaningful numbers. Report the split with counts and example files. Never record a preferred winner while the code remains mixed, even in yolo, because that would describe an aspiration rather than reality. Record only if the user identifies a stable path or context boundary that explains both styles; otherwise defer until the code is reconciled.
|
|
36
|
+
- Default. Consistent, but a framework or common-practice default the agent already writes unprompted. Skip it as a no-op, not a convention.
|
|
37
|
+
- No signal. Under the bar: feature unused, or too few examples. Skip silently (one summary line at most).
|
|
38
|
+
- Tooling-owned or Already-recorded. Skip per the ground rules.
|
|
39
|
+
|
|
40
|
+
Done when: every applicable dimension carries exactly one of those verdicts.
|
|
41
|
+
|
|
42
|
+
### Step 2: Open-ended pass
|
|
43
|
+
|
|
44
|
+
First, close out the architecture map from Step 0. For every non-default `app/` directory you listed, confirm how the pattern is used and apply the same evidence and decisions-not-defaults tests as Step 1. Generator-standard or sparsely used directories such as `Rules`, `Observers`, `Mail`, and `Notifications` are signals to inspect, not automatic conventions. Make genuine structural patterns candidates: Action classes invoked via `handle` / `execute` / `__invoke`, Services constructor-injected, `Queries` objects exposing `builder(): Builder`, DTOs as readonly classes or spatie/laravel-data, module or domain folders as the unit of organization. Scope each qualifying pattern to its own directory glob. Also record a consistent deliberate absence, such as "no repository layer, controllers query Eloquent directly", so the next agent matches the app's altitude.
|
|
45
|
+
|
|
46
|
+
Then find what else makes this codebase itself: base or abstract classes most code extends, traits used everywhere, tenancy or authorization scoping woven through queries, naming schemes, and custom helpers. Same evidence bar, cite files. Record every genuine structural pattern, and cap the other house findings at ~5 so the pass stays high-signal.
|
|
47
|
+
|
|
48
|
+
Done when: every non-default `app/` directory from Step 0 has a verdict, and the pass has produced its cited house findings (or concluded there are none).
|
|
49
|
+
|
|
50
|
+
### Step 3: Confirm
|
|
51
|
+
|
|
52
|
+
Present every candidate in one batch. Per item: dimension, verdict, evidence (counts and files), and the exact proposed `glob` or `globs` / `title` / `note`. Conflicts are presented as questions about an existing context boundary or deferred cleanup, not as a choice of future style.
|
|
53
|
+
|
|
54
|
+
Default mode is confirm: record only what the user approves. Switch to yolo only when the invocation said so ("yolo", "don't ask", "just record them"), then record all pattern candidates without asking. Conflicts still go to the user in yolo.
|
|
55
|
+
|
|
56
|
+
Done when: every candidate is approved, rejected, or (conflicts) decided.
|
|
57
|
+
|
|
58
|
+
### Step 4: Record
|
|
59
|
+
|
|
60
|
+
Make one `record-rule` call for each glob an approved convention applies to. Choose the most specific globs that cover the cited evidence from the mapping table below; if a convention spans models and migrations, record it under both domains so agents discover it from either path. The `note` is the bare convention: strip every trace of detection (see the ground rule). If `record-rule` is unavailable (rules disabled), report the full rule text so the user can enable `BOOST_RULES_ENABLED` or add it by hand.
|
|
61
|
+
|
|
62
|
+
Record this:
|
|
63
|
+
|
|
64
|
+
> Accessors and mutators: use the legacy magic-method style (`getXxxAttribute()` / `setXxxAttribute()`), not the `Attribute` class. Match it in models.
|
|
65
|
+
|
|
66
|
+
Not this:
|
|
67
|
+
|
|
68
|
+
> Accessors/mutators use the legacy magic-method style; the `Attribute`-class style is not used anywhere (13 legacy, 0 Attribute-class), e.g. `app/Models/Post.php`. Match the legacy style in existing models.
|
|
69
|
+
|
|
70
|
+
Done when: every approved item has a successful tool response, and any failure is reported with its rule text.
|
|
71
|
+
|
|
72
|
+
### Step 5: Summarize
|
|
73
|
+
|
|
74
|
+
List recorded rules (file and title), conflicts the user deferred, notable no-signals, and remind the user to commit `.ai/rules` so their team and agents share the conventions.
|
|
75
|
+
|
|
76
|
+
## Glob mapping
|
|
77
|
+
|
|
78
|
+
Attach each rule to the most specific path that covers its evidence. Never a lazy `app/**` when a subtree fits. Match the glob to where the code actually lives, which is not the same in a default skeleton and in a modular or DDD layout. Use the Step 0 `app/` map to pick the real path.
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
|
|
82
|
+
- Models: `app/Models/**` in a default app, or `app/Modules/Blog/Models/**` / `src/Domain/Blog/**` in a modular one.
|
|
83
|
+
- Controllers, routing, validation, responses: `app/Http/**`, or `app/Modules/*/Http/**` when each module owns its HTTP layer.
|
|
84
|
+
- Actions, Services, DTOs: `app/Actions/**`, `app/Services/**`, `app/Data/**`, or the module path the app actually uses.
|
|
85
|
+
- Tests: `tests/**`.
|
|
86
|
+
- Migrations and database: `database/migrations/**`.
|
|
87
|
+
- Truly app-wide (rare, e.g. auth retrieval): `app/**`.
|
|
88
|
+
|
|
89
|
+
`record-rule` takes one glob. When a convention genuinely spans two domains (e.g. UUID keys touch models and migrations), call it once per domain with the same title and note; mentioning another path in the note does not make the rule discoverable there.
|
|
90
|
+
|
|
91
|
+
## Edge cases
|
|
92
|
+
|
|
93
|
+
- Rules disabled or `record-rule` missing: detection is read-only, so Steps 0 to 3 still run, and recording falls back to the manual path in Step 4.
|
|
94
|
+
- Tiny or fresh app: most dimensions land on no-signal. Say so honestly ("not enough code to infer conventions yet") and record nothing.
|
|
95
|
+
- Huge app: each dimension is a bounded grep plus a handful of file reads. Sample representative files, do not read everything.
|
|
96
|
+
- Re-runs: reading `.ai/rules` in Step 0 makes re-runs incremental, so only new or undecided dimensions surface.
|
|
97
|
+
- Non-standard layout (modules, DDD): the open-ended pass catches the layout itself as convention #1. Adapt the globs in the mapping table to the observed paths.
|