Files
mareike/.ai/conventions.md

82 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Projektkonventionen
## Architektur: Actions (Request-Command-Response)
Jede fachliche Operation wird in eine eigene Action ausgelagert, die aus drei Klassen besteht.
Pfad: `app/Domains/{Domain}/Actions/{ActionName}/`
### Struktur
{ActionName}Request.php → Eingabedaten (Konstruktor oder Factory-Methoden) {ActionName}Command.php → Logik, ruft execute(): {ActionName}Response auf {ActionName}Response.php → Rückgabedaten (public Properties)
### Regeln
- Der Controller enthält **keine** fachliche Logik nur Absicherung, Action-Aufruf und HTTP-Response
- Commands sind nicht statisch und werden immer instanziiert
- Hat ein Request mehrere Varianten, werden **Factory-Methoden** (`forX()`) statt mehrerer Konstruktoren verwendet
- Aufrufreihenfolge im Controller: `new Request → new Command(request) → command->execute() → Response verwenden`
---
## Controller
- Alle Controller erben von `App\Scopes\CommonController`
- `CommonController` stellt folgende Repositories bereit (keine eigene Instanziierung nötig):
- `$this->eventParticipants``EventParticipantRepository`
- `$this->events``EventRepository`
- `$this->invoices``InvoiceRepository`
- `$this->costUnits``CostUnitRepository`
- `$this->users``UserRepository`
- `$this->tenant` → aktueller `Tenant`
- Die Controller besitzen ausschließlich eine __invoke() - Funktion
- Für die Speichern-Actions werden separate Controller-Klassen erstellt (z. B. `StoreEventParticipantController`)
---
## Repositories
- Datenbankzugriffe gehören **immer** ins Repository, nie direkt in Controller oder Actions
- Sicherheitschecks (z. B. „gehört diese Teilnahme dem eingeloggten User?") werden als eigene Repository-Methoden gekapselt
- Tenant-Filter: `app('tenant')->slug`
- Eingeloggter User: `auth()->user()`
---
## Models / Ressourcen
- Models erben von `App\Scopes\InstancedModel` (mit globalem `SiteScope`)
- `$model->toResource()->toArray($request)` liefert das aufbereitete Array über die zugehörige Resource-Klasse
- Resource-Klassen liegen in `app/Resources/{ModelName}Resource.php`
---
## Tenant
- Der aktuelle Tenant ist per `app('tenant')` verfügbar (gesetzt durch `IdentifyTenant`-Middleware)
- Tenant-Slug: `app('tenant')->slug`
- Jede tenant-spezifische DB-Abfrage filtert auf `['tenant' => app('tenant')->slug]`
---
## Routing
- API-Routen liegen in `app/Domains/{Domain}/Routes/api.php`
- Alle Routen sind in `IdentifyTenant::class`-Middleware gewrappt
- Authentifizierte Routen zusätzlich in `['auth']`-Middleware
---
## Mails
- Mails erben von `Illuminate\Mail\Mailable`
- Attachments werden über `Attachment::fromData(fn () => $content, $filename)->withMime(...)` angehängt
- Werden Daten sowohl in `content()` als auch in `attachments()` benötigt, wird eine **private Hilfsmethode mit Lazy-Caching** verwendet (einmaliges Berechnen, Ergebnis in private Property speichern)
- Blade-Templates referenzieren Mail-Attachments per `cid:`-Link: `<a href="cid:{{ $filename }}">...</a>`
## Actions
- Die Actions sind in `app/Domains/{Domain}/Actions/{ActionName}/`-Verzeichnissen organisiert
- Jede Action besitzt einen Request, einen Command und einen Response
- Der Request besitzt auschließlich einen Konstruktor, der die notwendigen Parameter annimmt
- Die Response-Klasse enthält ausschließlich die notwendigen Daten für die Antwort
- Die Action-Klasse enthält die Logik für die Verarbeitung der Anfrage und die Generierung der Antwort
- Die Logik wird in einer execute() - Funktion innerhalb des Commands impplementiert. Private Funktionen, für ausgelagerte Prozesse sind zulässig, wenn der Code damit lesbarer wird.