# 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: `...` ## 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.