name the LLM-default constructs this project forbids in explicit before/after tables. catching the trap by pattern match is more reliable than expecting a general rule to be applied at write time. backend table covers PHP traps (arrow fns, inline FQCNs, default params, stored refs, em dashes, short names); frontend table covers JS/template/ cypress traps.
64 lines
3 KiB
Markdown
64 lines
3 KiB
Markdown
# Backend context
|
|
|
|
> Read `ai/shared.md` first. This file only covers backend-specific rules.
|
|
|
|
## Project Context
|
|
|
|
**Stack:** PHP 8.5, Slim 4, PHP-DI/Slim-Bridge, PHPUnit 13, Composer.
|
|
Persistence is JSON-file based (see `Json*Repository` classes); no ORM.
|
|
**Architecture:** Domain-Driven Design. Code is organized by domain entity
|
|
under `app/` (Auth, Node, Plan, ScheduledNode, Text, User, View,
|
|
ValueObjects) into Entities, DTOs, Repositories, Use Cases, and Fakes
|
|
(in-memory repos for tests).
|
|
|
|
## Code patterns
|
|
|
|
- Look at similar entities (e.g. `Node`, `Text`) for reference
|
|
- Entities: constructor with properties, getters
|
|
- DTOs: simple data containers for creation (e.g. `CreateTextDto`)
|
|
- Repositories: interfaces that define data access
|
|
- Do not write unit tests for concrete repository implementations
|
|
(e.g. `JsonNodeRepository`). They are exercised by e2e tests. Use
|
|
cases are tested with fake repositories.
|
|
- Use cases: business logic with Request objects
|
|
- When throwing exceptions, add `@throws` docblock
|
|
- Fakes: in-memory implementations for testing
|
|
- Look at `tests/Fakes/` for examples
|
|
- Find/lookup methods must return a new instance of the entity, not the
|
|
stored reference
|
|
- Tests: follow existing patterns in `tests/Unit/[Entity]/UseCases/`
|
|
- In `setUp`, only use fake repositories for entities under test - construct
|
|
dependency objects directly with `new` (e.g.
|
|
`new Text(...)`) instead of creating them through their fake
|
|
repositories
|
|
|
|
## 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 `php-cs-fixer fix` on worked-on directories before committing (uses the
|
|
existing `.php-cs-fixer.dist.php` config).
|
|
|
|
## LLM anti-patterns
|
|
|
|
Constructs LLMs default to that this project forbids. Name the trap
|
|
explicitly so you catch yourself before writing it.
|
|
|
|
| Anti-pattern | Forbidden | Required |
|
|
|---|---|---|
|
|
| Arrow function | `fn ($x) => $x->getId()` | `function ($x) { return $x->getId(); }` |
|
|
| Inline FQCN type | `function f(): \Psr\Http\Message\ResponseInterface` | `use Psr\Http\Message\ResponseInterface;` then `function f(): ResponseInterface` |
|
|
| Inline `::class` | `Container::get(\App\Foo\Bar::class)` | `use App\Foo\Bar;` then `Container::get(Bar::class)` |
|
|
| Default param | `function f(int $count = 10)` | `function f(int $count)` |
|
|
| Default in fake | `public function create(Dto $dto, bool $strict = true)` | no default; every caller passes a value |
|
|
| Lookup returns stored ref | `return $this->items[$id] ?? null;` | rebuild a new instance with the stored fields |
|
|
| Short variable name | `$t`, `$n`, `$res`, `$req`, `$e` | `$text`, `$node`, `$response`, `$request`, `$exception` |
|
|
| Em dash | `// fetches user — by email` | `// fetches user - by email` |
|
|
|
|
When generating code, scan the diff for these patterns before writing it
|
|
to disk. If you catch one mid-write, rewrite that line.
|