Rabbi_Gerzi/ai/backend-context.md

94 lines
3.8 KiB
Markdown

# Backend context
> Read `ai/shared.md` first. This file only covers backend-specific rules.
## Project Context
**Stack:** PHP 8.x, Slim 4, PHP-DI/Slim-Bridge, PHPUnit (dev), Composer.
Persistence: PostgreSQL.
**Architecture:** Domain-Driven Design. Code is organized by domain entity
under `backend/app/` (PSR-4 `App\\`) into Entities, DTOs, Repositories,
Use Cases, and Fakes (in-memory repos for tests). The entity list is
intentionally omitted here - update this section as entities land.
## Code patterns
- Look at similar entities for reference before writing anything new
- Entities: constructor with properties, getters
- DTOs: simple data containers for creation (e.g. `CreateElementDto`)
- Repositories: interfaces that define data access
- Do not write unit tests for concrete repository implementations
(e.g. `Postgres*Repository`). They are exercised by e2e tests.
Use cases are tested with fake repositories.
- Repository methods that find records by a foreign key should accept
the related entity, not a raw id (e.g. `findBySet(Set $set)`, not
`findBySetId(int $setId)`).
- Use cases: business logic with Request objects
- When throwing exceptions, add `@throws` docblock
- Fakes: in-memory implementations for testing
- Live under `tests/Fakes/`
- Find/lookup methods must return a new instance of the entity, not
the stored reference
- Tests: follow `tests/Unit/[Entity]/UseCases/` layout
- In `setUp`, only use fake repositories for entities under test -
construct dependency objects directly with `new` (e.g.
`new Set(...)`) instead of creating them through their fake
repositories
## Migrations
- This project is not in production. By default, schema changes should update
the relevant create-table migration so migrations describe the current desired
schema from scratch.
- Do not add alter-table or data-backfill migrations unless the user explicitly
asks for production-style migration safety.
- Put seed data in seeders, not migrations.
## PHP rules
- Imports: always put `use` statements at the top of the file, never use
inline imports (e.g. `\App\Foo\Bar::class`)
- Closures: never use arrow functions (`fn () =>`) - always use regular
anonymous functions (`function () { return ...; }`)
## Pre-commit
Run `phpcs` on worked-on directories before committing (phpcs ruleset
to be added to the repo; the Nix flake already provides
`php-codesniffer`). Run `./vendor/bin/phpunit tests` and confirm green.
## LLM anti-patterns
Constructs LLMs default to that this project forbids. Name the trap
explicitly so you catch yourself before writing it.
- Arrow function:
- Forbidden: `fn ($node) => $node->getId()`
- Required: `function ($node) { return $node->getId(); }`
- Inline FQCN type:
- Forbidden: `function f(): \Psr\Http\Message\ResponseInterface`
- Required: import `ResponseInterface`, then return `ResponseInterface`
- Inline `::class`:
- Forbidden: `Container::get(\App\Foo\Bar::class)`
- Required: import `Bar`, then call `Container::get(Bar::class)`
- Default param:
- Forbidden: `function f(int $count = 10)`
- Required: `function f(int $count)`
- Default in fake:
- Forbidden: `public function create(Dto $dto, bool $strict = true)`
- Required: no default; every caller passes a value
- Lookup returns stored ref:
- Forbidden: `return $this->items[$id] ?? null;`
- Required: rebuild a new instance with the stored fields
- FK lookup by id:
- Forbidden: `findBySetId(int $setId)`
- Required: `findBySet(Set $set)`
- Short variable name:
- Forbidden: one-letter or abbreviated names (`$t`, `$n`, `$res`)
- Required: explicit names (`$text`, `$node`, `$response`)
- Em dash:
- Forbidden: comment or docblock containing an em dash character
- Required: use `-`
When generating code, scan the diff for these patterns before writing it
to disk. If you catch one mid-write, rewrite that line.