Rabbi_Gerzi/ai/backend-context.md

3.5 KiB

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. CreateSetDto)
  • 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

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.