# System-Optimierung Analyse Stand: 18.06.2026 ## Ziel Analyse des aktuellen Entwicklungsstands mit Fokus auf Controller, Views, Livewire/Volt-Komponenten und wiederverwendbare Code-Strukturen. Schwerpunkt: Code-Dopplungen, tote/alte Strukturen, Query-Wiederholungen und Refactoring-Potenzial. ## Kurzfazit Das System hat bereits gute fachliche Bausteine wie Services, Policies, Model-Scopes, Eloquent Resources und einzelne Livewire-Concerns. Das groesste Optimierungspotenzial liegt nicht in den klassischen Controllern, sondern in: - sehr grosser Route-/Page-Logik in `routes/web.php` - sehr grossen Volt-Dateien mit wiederholter Formular-, Scheduling- und Query-Logik - alten Admin-Wrapper-Views neben den aktiven Volt-Routen - einzelnen Demo-/Prototyp-Komponenten, die noch erreichbar sind - mehrfach eingebetteten API-Zugriffsqueries ## Priorisierte Findings ### 1. Erreichbarer Prototyp: `admin/users/table` **Dateien** - `routes/admin.php` - `resources/views/livewire/admin/users/table.blade.php` `routes/admin.php` routet noch `admin/users/table` auf die Volt-Komponente `admin.users.table`. Diese Komponente wirkt wie ein frueher Flux-Prototyp: - filtert auf `users.status`, obwohl die Tabelle laut Schema kein `status`-Feld hat - sortiert Demo-Spalten wie `date`, `status`, `amount` - liest `$user->role`, obwohl Rollen ueber Spatie-Relationen laufen - enthaelt englische Demo-Menupunkte wie `New post`, `Draft`, `Published`, `Archived` **Risiko** Die Route ist erreichbar und kann zu SQL-Fehlern oder fachlich falscher UI fuehren. **Empfehlung** Route und Komponente entfernen, falls sie nicht mehr gebraucht werden. Falls eine separate User-Tabelle geplant ist, sollte sie auf Basis der produktiven `admin.users`-Komponente neu aufgebaut werden. **Prioritaet:** Hoch ### 2. Alte Admin-Wrapper-Views neben direkten Volt-Routen **Dateien** - `resources/views/admin/*` - `routes/admin.php` - `app/Http/Controllers/Admin/DashboardController.php` Die aktiven Admin-Seiten laufen groesstenteils direkt ueber `Volt::route(...)`. Gleichzeitig existieren alte Wrapper-Views unter `resources/views/admin/*`, die Livewire-Komponenten manuell mounten, z. B.: - `resources/views/admin/companies/show.blade.php` - `resources/views/admin/press-releases/show.blade.php` - `resources/views/admin/roles/edit.blade.php` Ein Suchlauf hat nur einen produktiven `view('admin.*')`-Aufruf ergeben: - `DashboardController` rendert `admin.dashboard` Viele Wrapper sind dadurch wahrscheinlich tot. Einige verwenden zudem alte Routennamen oder alte Route-Parameter, z. B. `request()->route('pressRelease')`, waehrend die aktuelle Volt-Route `{id}` nutzt. **Risiko** Verwirrung bei Wartung, falsche Wiederverwendung, alte Parameter-Konventionen, unklare Quelle der Wahrheit. **Empfehlung** - `admin.dashboard` behalten, solange der DashboardController sie nutzt - ungenutzte Admin-Wrapper entfernen oder in einen klaren Legacy-/Dokumentationsbereich verschieben - `resources/views/admin/*.md` separat bewerten, da diese eher Dokumentation/Status darstellen **Prioritaet:** Hoch ### 3. `routes/web.php` enthaelt zu viel Controller- und Query-Logik **Datei** - `routes/web.php` `routes/web.php` hat aktuell ueber 1100 Zeilen und enthaelt komplette Datenaufbereitung fuer: - Home-Daten (`$webHomeData`) - Kategorie-/Branchenseite (`$categoryPage`) - Pressemitteilungs-Detailseite (`$releaseDetailPage`) - Veroeffentlichen-Seite (`$veroeffentlichenPage`) - Suche (`$suchePage`) - Newsrooms-Index (`$newsroomsIndex`) - Newsroom-Detail (`$newsroomDetail`) - Preise (`$preisePage`) - Legacy-Redirects Die Datei wiederholt mehrfach: - Domain-/Portal-Erkennung - `portal/status/language/published_at`-Filter - Eager-Load-Sets fuer `company`, `category.translations`, `images` - Most-read Queries - Newsroom Count Queries - Statistikfenster wie 7/14/30 Tage **Risiko** Schwer testbar, schwer zu optimieren, hohe Aenderungskosten, Query-Regeln koennen auseinanderlaufen. **Empfehlung** In mehreren kleinen Schritten extrahieren: 1. `WebPortalContext` oder aehnlicher Service fuer DomainKey, Portal, PortalValues, Language und Theme-Konfiguration. 2. `PublishedReleaseQuery` oder lokale Scopes am Model fuer veroeffentlichte Pressemitteilungen. 3. Page-Data-Klassen wie `HomePageData`, `CategoryPageData`, `NewsroomPageData`. 4. Danach Routen auf schlanke Controller oder Invokable Controller umstellen. **Prioritaet:** Hoch ### 4. Wiederholte Published-Release-Bedingungen **Dateien** - `routes/web.php` - `app/Models/PressRelease.php` Die gleiche fachliche Bedingung fuer oeffentlich sichtbare Pressemitteilungen taucht mehrfach auf: - Portal muss aktuelles Portal oder `both` sein - Status ist `published` - Sprache passt - `published_at` ist gesetzt - `published_at <= now()` Teilweise wird `withoutGlobalScope(PortalScope::class)` verwendet, teilweise nicht. Das ist fachlich nachvollziehbar, aber die Logik sollte zentraler formuliert werden. **Empfehlung** Moegliche Scopes: ```php public function scopePublished(Builder $query): Builder public function scopeForPortalValues(Builder $query, array $portalValues): Builder public function scopeForLanguage(Builder $query, string $language): Builder public function scopeVisibleInArchive(Builder $query, array $portalValues, string $language): Builder ``` Alternativ ein Query-Objekt, wenn die Kombination mit `withoutGlobalScope(PortalScope::class)` bewusst kontrolliert werden soll. **Prioritaet:** Hoch ### 5. Grosse PM-Editoren mit duplizierter Formular- und Scheduling-Logik **Dateien** - `resources/views/livewire/admin/press-releases/create.blade.php` - `resources/views/livewire/admin/press-releases/edit.blade.php` - `resources/views/livewire/customer/press-releases/create.blade.php` - `resources/views/livewire/customer/press-releases/edit.blade.php` - `app/Livewire/Concerns/InteractsWithPressReleaseTags.php` Die vier PM-Editoren sind sehr gross und wiederholen viele Muster: - Properties fuer Portal, Sprache, Firma, Kategorie, Kontakt, Titel, Text, Keywords - `updatedPublishMode` - `updatedScheduledDate` - `updatedScheduledTime` - `syncScheduledAt` - `resolveScheduledAt` - `validateScheduledAtWhenReady` - grosse `formRules` - Teile der Speicher- und Submit-Logik Positiv: Fuer Customer-Editoren existiert bereits `InteractsWithPressReleaseTags`. Admin-Editoren duplizieren die Tag-Logik aber noch lokal. **Empfehlung** In kleinen, risikoarmen Schritten: 1. Admin-PM-Editoren ebenfalls `InteractsWithPressReleaseTags` nutzen lassen. 2. `InteractsWithPressReleaseScheduling` einfuehren fuer Scheduling-Hooks und Validierung. 3. Gemeinsame Rule-Fragmente in einen Service oder Trait auslagern, z. B. `PressReleaseFormRules`. 4. Wiederkehrende Formularabschnitte als Blade-Komponenten oder partials extrahieren. **Prioritaet:** Hoch ### 6. API-Zugriffsqueries mehrfach eingebettet **Dateien** - `app/Http/Controllers/Api/V1/PressReleaseController.php` - `app/Http/Controllers/Api/V1/PressReleaseImageController.php` - `app/Http/Controllers/Api/V1/CompanyController.php` - `app/Models/PressRelease.php` - `app/Models/Company.php` Mehrere Controller enthalten fast gleiche Ownership-/Access-Queries: - `findOwnedPressRelease` in `PressReleaseController` - `findOwnedPressRelease` in `PressReleaseImageController` - Company-Zugriff ueber `owner_user_id` oder `users`-Pivot in `CompanyController` - dieselbe Company-Zugriffslogik nochmals in `PressReleaseController` Es gibt bereits `PressRelease::accessibleBy(User $user)`, allerdings nutzt die API aktuell eine engere `user_id`-Logik. Das kann fachlich korrekt sein, sollte aber explizit zentralisiert werden. **Empfehlung** - `Company::accessibleBy(User $user)` als Scope einfuehren - API-spezifischen PressRelease-Scope definieren, z. B. `ownedByApiUser(User $user)`, falls API-Zugriff bewusst nur Autor-Ownership meint - alternativ Policies konsequenter nutzen **Prioritaet:** Mittel bis hoch ### 7. Wiederholte API-Resource-Eager-Loads **Datei** - `app/Http/Controllers/Api/V1/PressReleaseController.php` Die gleiche Relation-Liste wird mehrfach geladen: - `company:id,name,portal,legacy_portal,legacy_id` - `category.translations` - `images` **Empfehlung** Eine private Methode oder ein Query-Scope: ```php private function resourceRelations(): array ``` oder: ```php PressRelease::query()->withApiResourceRelations() ``` **Prioritaet:** Mittel ### 8. Grosse Volt-Dateien als langfristiges Wartungsrisiko **Beispiele** - `resources/views/livewire/admin/press-releases/edit.blade.php` mit ca. 1394 Zeilen - `resources/views/livewire/customer/press-releases/create.blade.php` mit ca. 1371 Zeilen - `resources/views/livewire/customer/press-releases/edit.blade.php` mit ca. 1331 Zeilen - `resources/views/livewire/admin/users/edit.blade.php` mit ca. 1241 Zeilen - `resources/views/livewire/admin/press-releases/index.blade.php` mit ca. 1093 Zeilen Volt Single-File-Komponenten sind hier legitim, aber bei dieser Groesse vermischen sich Zustand, Query, Validierung, Aktionen und Markup stark. **Empfehlung** Nicht pauschal auf klassische Livewire-Klassen migrieren, sondern gezielt extrahieren: - Concerns fuer wiederkehrende Interaktionen - Service-Klassen fuer fachliche Aktionen - kleine Blade-Komponenten fuer wiederkehrende UI-Abschnitte - Query-Methoden/Scopes fuer Tabellenfilter **Prioritaet:** Mittel ## Positive Muster, die beibehalten werden sollten - `PressRelease::accessibleBy(User $user)` ist ein guter Single-Source-Ansatz fuer Kundenzugriff. - `PortalScope` kapselt Portalfilterung zentral. - `HasUniqueSlug` reduziert Slug-Duplikate. - API nutzt Form Requests und Eloquent Resources. - Dashboard nutzt bereits `AdminPerformanceCache`. - Es gibt viele Feature-Tests fuer Admin, API, Customer und Web. - Erste Concerns wie `InteractsWithPressReleaseTags` zeigen die richtige Richtung. ## Vorgeschlagene Refactoring-Pakete ### Paket A: Aufraeumen ohne Fachlogik-Aenderung 1. `admin/users/table` Route entfernen. 2. `resources/views/livewire/admin/users/table.blade.php` entfernen. 3. Ungenutzte `resources/views/admin/*` Wrapper entfernen oder eindeutig als Legacy markieren. 4. Tests fuer fehlende/entfernte Route anpassen oder ergaenzen. **Nutzen:** Weniger Altlasten, weniger Risiko durch erreichbare Demo-Komponente. ### Paket B: Gemeinsame PM-Editor-Concerns 1. Admin-PM-Editoren auf `InteractsWithPressReleaseTags` umstellen. 2. `InteractsWithPressReleaseScheduling` extrahieren. 3. Gemeinsame Rule-Fragmente zentralisieren. 4. Bestehende PM-Editor-Tests gezielt laufen lassen. **Nutzen:** Weniger Dopplung in vier grossen Dateien, geringere Fehlerwahrscheinlichkeit bei Scheduling. ### Paket C: Web-Routen entflechten 1. Portal-/Domain-Kontext extrahieren. 2. Published-Release-Query zentralisieren. 3. Home/Kategorie/Newsroom-Daten in Services verschieben. 4. Routen schrittweise auf kleine Controller umstellen. **Nutzen:** Bessere Testbarkeit, klarere Verantwortlichkeiten, zentraleres Performance-Tuning. ### Paket D: API-Zugriff zentralisieren 1. `Company::accessibleBy(User $user)` einfuehren. 2. API-PressRelease-Zugriff zentral benennen. 3. Eager-Load-Sets fuer API Resources zentralisieren. 4. API-Feature-Tests laufen lassen. **Nutzen:** Weniger Query-Duplikate, klarere Zugriffspolitik. ## Pruefung / Verifikation Die Analyse basiert auf statischer Codepruefung, Laravel-Boost-Projektinformationen, versionierter Dokumentationssuche und Schema-Inspektion. Eine Artisan-Routentabelle konnte nicht ausgefuehrt werden, weil Sail gemeldet hat: ```text Docker or Podman is not running. ``` ## Hinweis zum aktuellen Worktree Zum Analysezeitpunkt gab es bereits eine nicht von mir angelegte Aenderung: - `resources/views/components/layouts/app/sidebar.blade.php` Diese Datei wurde fuer die Analyse nicht veraendert.