align ai workflow rules

This commit is contained in:
Yisroel Baum 2026-08-03 19:59:36 +03:00
parent 4241f5ba29
commit efb932903b
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
3 changed files with 205 additions and 220 deletions

View file

@ -8,57 +8,76 @@ Read `ai/shared.md` first. This file covers backend-specific rules.
**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.
The backend follows a domain-oriented structure. Existing areas use entities,
DTOs, repository interfaces, Eloquent implementations, use cases, and test
fakes. Extend those patterns when adding behavior to an established area. Do
not add speculative layers or interfaces that the requested behavior does not
need.
## Laravel patterns
The Vue application remains 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`.
- 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.
## Code patterns
- Inspect similar domain code before adding a new entity, DTO, repository,
use case, controller action, or fake.
- Entities own domain state and behavior and expose descriptive methods.
- DTOs are explicit data containers for creation or transfer between seams.
- Repository interfaces define domain-facing persistence operations. Keep
Eloquent details in their implementations and register bindings in the
application provider.
- Put reusable business behavior in a use case. Give a use case a request DTO
when it accepts a payload; call `execute()` directly when it has no input.
- Document use-case exceptions with `@throws` when callers are expected to
handle them.
- Keep controllers thin. Translate HTTP input to use-case input and domain
output to the response contract.
- Catch only documented, expected exceptions at the controller boundary. Let
unexpected exceptions reach Laravel's exception handler.
- Fake repositories are in-memory implementations used by unit tests. Return
a new entity instance from create and lookup methods rather than exposing a
stored reference.
- 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
## Unit tests
- Follow the existing PHPUnit organization under `tests/Unit/` and
`tests/Feature/`.
- Prefer `PHPUnit\Framework\TestCase` when a test only exercises plain PHP.
- Extend `Tests\TestCase` only when the test needs Laravel's container,
facades, database, routing, or HTTP kernel.
- HTTP feature tests extend `Tests\TestCase`.
- Use `RefreshDatabase` when 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.
- Follow the existing organization under `tests/Unit/<Area>/`.
- Use fake repositories and fake collaborators for the behavior under test.
Construct unrelated dependency entities directly instead of routing them
through additional repositories.
- Test use-case branches at the use-case seam. Do not repeat every branch in
controller or HTTP tests.
- Plain entities, value objects, use cases, middleware, and controller units
should extend `PHPUnit\Framework\TestCase` when they do not need Laravel.
- Extend `Tests\TestCase` only when a test needs Laravel's container, facades,
database, routing, or HTTP kernel.
- Reserve direct Eloquent repository feature tests for persistence mapping,
query behavior, or database constraints that cannot be proven through a
plain unit test.
## Test database
## Feature tests
- Feature tests exercise the HTTP seam: routing, middleware, real Eloquent
bindings, cookies, persistence, validation, and response shape.
- Feature tests are additive to unit tests. Prefer a happy path and the
relevant authorization guard instead of duplicating all business branches.
- Place endpoint tests under `tests/Feature/<Area>/`, extend
`Tests\TestCase`, and use `RefreshDatabase` when database state is involved.
- Development and runtime use PostgreSQL through the local Unix socket.
- PHPUnit intentionally uses SQLite `:memory:` as configured in
`phpunit.xml`.
- Feature tests are self-contained and do not require the process-compose
PostgreSQL service.
PHPUnit uses SQLite `:memory:` as configured in `phpunit.xml`, so feature
tests are self-contained and do not need the worktree stack.
- Never point `RefreshDatabase` tests at the development PostgreSQL database.
- Keep mail set to the PHPUnit `array` transport unless a test explicitly
exercises a real mail integration.
- Keep mail on PHPUnit's `array` transport unless a test explicitly exercises
a real mail integration.
- Authentication uses a custom database-session cookie, not a Laravel guard.
`actingAs()` does not apply. Credentialed requests use
`withCredentials()` and `withUnencryptedCookie()` because API middleware
reads the raw cookie.
- Read an unencrypted response cookie with
`$response->getCookie($name, false)`.
## PHP rules
@ -80,7 +99,7 @@ pattern.
- 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
records only makes sense together, keep it in one seeder and retain local
references.
## Migrations
@ -99,15 +118,12 @@ pattern.
- Once a production database exists, replace this policy with additive,
forward-only migrations.
## Before completing backend work
## Backend workflow
- Run the focused test during development.
- Run the full test suite before completion:
```sh
direnv exec "$(git rev-parse --show-toplevel)" php artisan test
```
- Run the Composer static-analysis scripts.
- Run the focused PHPUnit test while developing.
- Use `just backend-types-check` for Larastan and `just backend-test` for the
full PHPUnit suite during iteration.
- Fix failures caused by the change. Report unrelated baseline failures
precisely rather than hiding them or expanding scope without authorization.
precisely rather than expanding scope silently.
- The shared `just test-all` command is the required completion gate. Focused
backend recipes never replace it.