Skip to content
Skill · Windsurf.windsurfrulesCoding

Windsurf Rules for Laravel Projects

Laravel conventions that keep controllers thin: Form Requests for all validation, no Eloquent queries outside models and actions, queued jobs for anything slow, Pest for tests.

Use when: Use in a Laravel 11+ application when you want Windsurf to follow framework idioms instead of writing raw queries in controllers or validating inline.

@libraryNewcomer
0 upvotes0 forks0 comments

The skill file

Windsurf · .windsurfrules
.windsurfrules2654 chars
# Laravel Project Rules ## Eloquent discipline - No Eloquent or query-builder calls in controllers, commands, or Blade views. Queries belong in the model (scopes), a dedicated Action class, or a query class under `app/Queries/`. - Always eager-load relations you iterate over. If a loop touches `$model->relation`, the calling query needs `with()`. Treat any new N+1 as a bug, and keep `Model::preventLazyLoading()` enabled in `AppServiceProvider`. - `$fillable` is required on every model; never use `$guarded = []`. - Use database transactions (`DB::transaction`) around any action that writes to more than one table. - Casts go in the `casts()` method; never store JSON in a string column without an `array`/`AsCollection` cast. - Never call `Model::all()` on user-facing paths — paginate or chunk. ## HTTP layer - Every POST/PUT/PATCH/DELETE endpoint validates via a Form Request class. Inline `$request->validate()` is forbidden. - Authorization lives in the Form Request's `authorize()` or a Policy — never `if ($user->id !== ...)` checks in controllers. - Controllers contain at most: resolve input, call one action, return a response. If a controller method exceeds ~15 lines, extract an Action. - API responses go through `JsonResource` classes; never return raw models from API controllers. ## Jobs and queues - Anything that sends mail, calls an external API, or takes longer than ~100ms goes in a queued job — never inline in the request cycle. - Every job declares explicit `$tries` and `$backoff`, and implements `failed()` to log context. - Jobs must be idempotent: guard with `WithoutOverlapping` or a unique key, and assume the queue may deliver twice. - Pass model IDs to jobs, then refetch inside `handle()` — never serialize whole loaded relations. - New jobs are dispatched via `dispatch()` from an Action, not from controllers directly. ## Pest tests - All new tests use Pest syntax (`it(...)`, `expect(...)`), not PHPUnit classes. - Feature tests hit real routes with `RefreshDatabase`; do not mock Eloquent. - Every Form Request gets a test for one valid payload and each validation rule that can fail. - Use factories for all test data; never insert via raw arrays or seeders inside tests. - Queued side effects are asserted with `Queue::fake()` / `Mail::fake()`, not by running the job inline. ## Workflow - Run `./vendor/bin/pint` and `php artisan test` before suggesting a commit. - New migrations are additive in production paths — never edit a migration that has already been merged; add a new one. - Config values are read via `config()` from a config file backed by `env()`; never call `env()` outside `config/`.

Install

drop into your repo

Save this to your project or home directory so Windsurf can load it.

path./.windsurfrules
Discussion

What people are saying

Forks

0 forks of this skill
Loading forks…