# {{app_name}} {{app_purpose}} Stack: PHP {{php_version}}, Laravel {{laravel_version}}, frontend: {{frontend_stack}}. Tests use {{test_runner}}. ## Commands - Install: `composer install` and `npm ci` - Run tests: `php artisan test` (single file: `php artisan test tests/Feature/ExampleTest.php`; filter: `php artisan test --filter=name`) - Format PHP: `./vendor/bin/pint` (check only: `./vendor/bin/pint --test`) - Static analysis (if Larastan is installed): `./vendor/bin/phpstan analyse` - Frontend dev / build: `npm run dev` / `npm run build` - New migration: `php artisan make:migration ` - Run migrations locally: `php artisan migrate` - List routes: `php artisan route:list` Before saying a task is done: run Pint, the tests related to the change, and static analysis if configured. ## Code conventions - Controllers stay thin. Business logic goes in actions or service classes under `app/Actions` or `app/Services` (follow whichever the project already uses). - Validation goes in Form Request classes (`php artisan make:request`), not inline in controllers. - Authorization uses policies or gates. Call `$this->authorize()`/`Gate::authorize()` or use the `can` middleware. Never rely on hiding UI elements for access control. - Scope queries to the current user or tenant where the model is tenant-owned. Do not fetch by ID alone from request input. - Eager load relationships used in loops (`with()`, `load()`). Watch for N+1 queries in lists and API resources. - Use API Resources for JSON responses instead of returning models directly. - Mass assignment: define `$fillable` explicitly. Never add `role`, `is_admin` or ownership columns to `$fillable` unless the request already authorizes them. - Use `config('key')` in application code. Call `env()` only inside `config/*.php`; after `php artisan config:cache`, `env()` calls elsewhere return null. - Dates: use Carbon via `now()`/`today()`; store UTC. - Queue jobs must be safe to retry: check state before acting, use unique jobs or idempotency keys where duplicates matter. ## Database - Never edit a migration that has been merged to the main branch. Create a new migration. - Every migration has a working `down()` method, or a comment explaining why it is irreversible. - Separate schema changes from large data backfills. - Add indexes for columns used in `where`, `orderBy` and foreign keys on large tables. - Tests use factories (`Model::factory()`) and the `RefreshDatabase` trait. Do not depend on seeded data in tests. ## Tests - Feature tests for HTTP endpoints (status, JSON shape, authorization failures), unit tests for pure logic. - Every bug fix gets a test that fails without the fix. - Fake external services: `Http::fake()`, `Mail::fake()`, `Queue::fake()`, `Storage::fake()`, `Event::fake()`. ## Do not do without asking - `php artisan migrate:fresh`, `migrate:reset`, `db:wipe`, or any command that drops data. - Anything against a non-local environment. - Adding Composer or npm packages. - Editing `.env` (edit `.env.example` for new variables and tell me). - Changing files in `config/` that affect auth, session or CORS.