4.4 KiB
Backend context
Read ai/shared.md first. This file covers backend-specific rules.
Project context
Stack: PHP 8.4, Laravel 13, PHPUnit, Larastan, Composer.
Location: backend/.
The application is still close to the Laravel starter structure. Do not introduce a domain architecture, repository layer, service layer, or other abstraction before the codebase and requested behavior justify it. Match existing Laravel conventions and inspect similar code before adding a new pattern.
Laravel patterns
- Keep controllers thin. Put reusable business behavior in an appropriately named application or domain class once the behavior warrants extraction.
- Use dedicated request validation rather than validating substantial payloads inline in controllers.
- Let unexpected exceptions reach Laravel's exception handler. Catch only exceptions that can be handled meaningfully at the current boundary.
- Use Eloquent relationships and query scopes consistently rather than duplicating query fragments.
- Avoid speculative interfaces and abstractions with only one trivial implementation.
- The Vue application is a separate project under
frontend/website/. - Keep frontend source, dependencies, builds, and delivery out of the backend unless the user explicitly asks to integrate them.
- The backend root route is intentionally unclaimed. The built-in health
endpoint is
/up.
Tests
- Follow the existing PHPUnit organization under
tests/Unit/andtests/Feature/. - Prefer
PHPUnit\Framework\TestCasewhen a test only exercises plain PHP. - Extend
Tests\TestCaseonly when the test needs Laravel's container, facades, database, routing, or HTTP kernel. - HTTP feature tests extend
Tests\TestCase. - Use
RefreshDatabasewhen a test reads or writes database state. - Assert behavior at the appropriate seam:
- Unit tests cover isolated business behavior and edge cases.
- Feature tests cover routing, middleware, validation, persistence, and response shape.
- Do not duplicate every business branch through the HTTP layer when unit coverage already proves it. Feature tests should focus on wiring and the public contract.
Test database
- Development and runtime use PostgreSQL through the local Unix socket.
- PHPUnit intentionally uses SQLite
:memory:as configured inphpunit.xml. - Feature tests are self-contained and do not require the process-compose PostgreSQL service.
- Never point
RefreshDatabasetests at the development PostgreSQL database. - Keep mail set to the PHPUnit
arraytransport unless a test explicitly exercises a real mail integration.
PHP rules
- Put imports at the top of the file. Do not use inline fully qualified class
names when a normal
usestatement is clearer. - Do not use arrow functions. Use regular anonymous functions.
- Do not add default values to function or constructor parameters. Pass every argument explicitly, including nullable arguments.
- Use descriptive names for classes, methods, parameters, and local variables.
- Document exceptions with
@throwswhen a caller is expected to handle them.
Seeders
- Keep
DatabaseSeederas the orchestrator. - Split substantial seed data into one seeder per domain concept and invoke them in dependency order.
- Do not add production repository or model APIs solely to make seeding convenient.
- Use existing lookup methods for cross-seeder relationships. When a group of records only makes sense together, keep them in one seeder and retain local references.
Migrations
-
Attainly is not in production yet.
-
While no production database exists, edit the original
create_*migration when changing a table instead of accumulating follow-up alter migrations. -
Keep one migration file per table during this pre-production phase.
-
Rebuild the development database with:
direnv exec "$(git rev-parse --show-toplevel)" \ php artisan migrate:fresh --seed -
Once a production database exists, replace this policy with additive, forward-only migrations.
Before completing backend work
-
Run the focused test during development.
-
Run the full test suite before completion:
direnv exec "$(git rev-parse --show-toplevel)" php artisan test -
Run the Composer static-analysis scripts.
-
Fix failures caused by the change. Report unrelated baseline failures precisely rather than hiding them or expanding scope without authorization.