|
| 1 | +<laravel-boost-guidelines> |
| 2 | +=== boost rules === |
| 3 | + |
| 4 | +## Laravel Boost |
| 5 | +- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them. |
| 6 | + |
| 7 | +## Artisan |
| 8 | +- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters. |
| 9 | + |
| 10 | +## URLs |
| 11 | +- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port. |
| 12 | + |
| 13 | +## Tinker / Debugging |
| 14 | +- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly. |
| 15 | +- Use the `database-query` tool when you only need to read from the database. |
| 16 | + |
| 17 | +## Reading Browser Logs With the `browser-logs` Tool |
| 18 | +- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost. |
| 19 | +- Only recent browser logs will be useful - ignore old logs. |
| 20 | + |
| 21 | +## Searching Documentation (Critically Important) |
| 22 | +- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages. |
| 23 | +- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc. |
| 24 | +- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches. |
| 25 | +- Search the documentation before making code changes to ensure we are taking the correct approach. |
| 26 | +- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`. |
| 27 | + |
| 28 | +### Available Search Syntax |
| 29 | +- You can and should pass multiple queries at once. The most relevant results will be returned first. |
| 30 | + |
| 31 | +1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth' |
| 32 | +2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit" |
| 33 | +3. Quoted Phrases (Exact Position) - query="infinite scroll - Words must be adjacent and in that order |
| 34 | +4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit" |
| 35 | +5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms |
| 36 | + |
| 37 | +=== inertia-laravel/core rules === |
| 38 | + |
| 39 | +## Inertia Core |
| 40 | + |
| 41 | +- Inertia.js components should be placed in the `resources/js/Pages` directory unless specified differently in the JS bundler (vite.config.js). |
| 42 | +- Use `Inertia::render()` for server-side routing instead of traditional Blade views. |
| 43 | + |
| 44 | +<code-snippet lang="php" name="Inertia::render Example"> |
| 45 | +// routes/web.php example |
| 46 | +Route::get('/users', function () { |
| 47 | + return Inertia::render('Users/Index', [ |
| 48 | + 'users' => User::all() |
| 49 | + ]); |
| 50 | +}); |
| 51 | +</code-snippet> |
| 52 | + |
| 53 | +=== inertia-laravel/v2 rules === |
| 54 | + |
| 55 | +## Inertia v2 |
| 56 | + |
| 57 | +- Make use of all Inertia features from v1 & v2. Check the documentation before making any changes to ensure we are taking the correct approach. |
| 58 | + |
| 59 | +### Inertia v2 New Features |
| 60 | +- Polling |
| 61 | +- Prefetching |
| 62 | +- Deferred props |
| 63 | +- Infinite scrolling using merging props and `WhenVisible` |
| 64 | +- Lazy loading data on scroll |
| 65 | + |
| 66 | +### Deferred Props & Empty States |
| 67 | +- When using deferred props on the frontend, you should add a nice empty state with pulsing / animated skeleton. |
| 68 | + |
| 69 | +=== laravel/core rules === |
| 70 | + |
| 71 | +## Do Things the Laravel Way |
| 72 | + |
| 73 | +- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool. |
| 74 | +- If you're creating a generic PHP class, use `artisan make:class`. |
| 75 | +- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior. |
| 76 | + |
| 77 | +### Database |
| 78 | +- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins. |
| 79 | +- Use Eloquent models and relationships before suggesting raw database queries |
| 80 | +- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them. |
| 81 | +- Generate code that prevents N+1 query problems by using eager loading. |
| 82 | +- Use Laravel's query builder for very complex database operations. |
| 83 | + |
| 84 | +### Model Creation |
| 85 | +- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`. |
| 86 | + |
| 87 | +### APIs & Eloquent Resources |
| 88 | +- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention. |
| 89 | + |
| 90 | +### Controllers & Validation |
| 91 | +- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages. |
| 92 | +- Check sibling Form Requests to see if the application uses array or string based validation rules. |
| 93 | + |
| 94 | +### Queues |
| 95 | +- Use queued jobs for time-consuming operations with the `ShouldQueue` interface. |
| 96 | + |
| 97 | +### Authentication & Authorization |
| 98 | +- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.). |
| 99 | + |
| 100 | +### URL Generation |
| 101 | +- When generating links to other pages, prefer named routes and the `route()` function. |
| 102 | + |
| 103 | +### Configuration |
| 104 | +- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`. |
| 105 | + |
| 106 | +### Testing |
| 107 | +- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model. |
| 108 | +- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`. |
| 109 | +- When creating tests, make use of `php artisan make:test [options] <name>` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests. |
| 110 | + |
| 111 | +### Vite Error |
| 112 | +- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`. |
| 113 | + |
| 114 | +=== laravel/v12 rules === |
| 115 | + |
| 116 | +## Laravel 12 |
| 117 | + |
| 118 | +- Use the `search-docs` tool to get version specific documentation. |
| 119 | +- Since Laravel 11, Laravel has a new streamlined file structure which this project uses. |
| 120 | + |
| 121 | +### Laravel 12 Structure |
| 122 | +- No middleware files in `app/Http/Middleware/`. |
| 123 | +- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files. |
| 124 | +- `bootstrap/providers.php` contains application specific service providers. |
| 125 | +- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration. |
| 126 | +- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration. |
| 127 | + |
| 128 | +### Database |
| 129 | +- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost. |
| 130 | +- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`. |
| 131 | + |
| 132 | +### Models |
| 133 | +- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models. |
| 134 | + |
| 135 | +=== pint/core rules === |
| 136 | + |
| 137 | +## Laravel Pint Code Formatter |
| 138 | + |
| 139 | +- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style. |
| 140 | +- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues. |
| 141 | + |
| 142 | +=== pest/core rules === |
| 143 | + |
| 144 | +## Pest |
| 145 | + |
| 146 | +### Testing |
| 147 | +- If you need to verify a feature is working, write or update a Unit / Feature test. |
| 148 | + |
| 149 | +### Pest Tests |
| 150 | +- All tests must be written using Pest. Use `php artisan make:test --pest <name>`. |
| 151 | +- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application. |
| 152 | +- Tests should test all of the happy paths, failure paths, and weird paths. |
| 153 | +- Tests live in the `tests/Feature` and `tests/Unit` directories. |
| 154 | +- Pest tests look and behave like this: |
| 155 | +<code-snippet name="Basic Pest Test Example" lang="php"> |
| 156 | +it('is true', function () { |
| 157 | + expect(true)->toBeTrue(); |
| 158 | +}); |
| 159 | +</code-snippet> |
| 160 | + |
| 161 | +### Running Tests |
| 162 | +- Run the minimal number of tests using an appropriate filter before finalizing code edits. |
| 163 | +- To run all tests: `php artisan test`. |
| 164 | +- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`. |
| 165 | +- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file). |
| 166 | +- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing. |
| 167 | + |
| 168 | +### Pest Assertions |
| 169 | +- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.: |
| 170 | +<code-snippet name="Pest Example Asserting postJson Response" lang="php"> |
| 171 | +it('returns all', function () { |
| 172 | + $response = $this->postJson('/api/docs', []); |
| 173 | + |
| 174 | + $response->assertSuccessful(); |
| 175 | +}); |
| 176 | +</code-snippet> |
| 177 | + |
| 178 | +### Mocking |
| 179 | +- Mocking can be very helpful when appropriate. |
| 180 | +- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do. |
| 181 | +- You can also create partial mocks using the same import or self method. |
| 182 | + |
| 183 | +### Datasets |
| 184 | +- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solutionwhen writing tests for validation rules. |
| 185 | + |
| 186 | +<code-snippet name="Pest Dataset Example" lang="php"> |
| 187 | +it('has emails', function (string $email) { |
| 188 | + expect($email)->not->toBeEmpty(); |
| 189 | +})->with([ |
| 190 | + 'james' => 'james@laravel.com', |
| 191 | + 'taylor' => 'taylor@laravel.com', |
| 192 | +]); |
| 193 | +</code-snippet> |
| 194 | + |
| 195 | +=== inertia-vue/core rules === |
| 196 | + |
| 197 | +## Inertia + Vue |
| 198 | + |
| 199 | +- Vue components must have a single root element. |
| 200 | +- Use `router.visit()` or `<Link>` for navigation instead of traditional links. |
| 201 | + |
| 202 | +<code-snippet lang="vue" name="Inertia Client Navigation"> |
| 203 | + import { Link } from '@inertiajs/vue3' |
| 204 | + |
| 205 | + <Link href="/">Home</Link> |
| 206 | +</code-snippet> |
| 207 | + |
| 208 | +- For form handling, use `router.post` and related methods. Do not use regular forms. |
| 209 | + |
| 210 | +<code-snippet lang="vue" name="Inertia Vue Form Example"> |
| 211 | + <script setup> |
| 212 | + import { reactive } from 'vue' |
| 213 | + import { router } from '@inertiajs/vue3' |
| 214 | + import { usePage } from '@inertiajs/vue3' |
| 215 | + |
| 216 | + const page = usePage() |
| 217 | + |
| 218 | + const form = reactive({ |
| 219 | + first_name: null, |
| 220 | + last_name: null, |
| 221 | + email: null, |
| 222 | + }) |
| 223 | + |
| 224 | + function submit() { |
| 225 | + router.post('/users', form) |
| 226 | + } |
| 227 | + </script> |
| 228 | + |
| 229 | + <template> |
| 230 | + <h1>Create {{ page.modelName }}</h1> |
| 231 | + <form @submit.prevent="submit"> |
| 232 | + <label for="first_name">First name:</label> |
| 233 | + <input id="first_name" v-model="form.first_name" /> |
| 234 | + <label for="last_name">Last name:</label> |
| 235 | + <input id="last_name" v-model="form.last_name" /> |
| 236 | + <label for="email">Email:</label> |
| 237 | + <input id="email" v-model="form.email" /> |
| 238 | + <button type="submit">Submit</button> |
| 239 | + </form> |
| 240 | + </template> |
| 241 | +</code-snippet> |
| 242 | +</laravel-boost-guidelines> |
0 commit comments