94 lines
3.8 KiB
Markdown
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.
|