presseportale/dev/archive/optimize/system-optimierung-analyse-codex.md
Kevin Adametz 6a4c4d8837 docs: dev-Doku für den Live-Betrieb neu sortiert — Archiv + Betrieb + Roadmap
Das System ist seit 20.07.2026 live; die dev-Doku spiegelt jetzt den
Betriebszustand statt der Release-Vorbereitung:

- dev/betrieb/: Deploy-Runbook (neu: §10 Betrieb nach Go-Live mit
  SFTP-Deploy-Checkliste inkl. queue:restart-Pflicht und den
  Betriebs-Erkenntnissen der Go-Live-Woche), Legacy-API-Parität, Umami.
- dev/roadmap.md: offene Nachlauf-Punkte (Go-Live-Mails, Merge nach main,
  Stripe-Test-Artefakte, Key-Rotation, Alt-System-Abschaltung) und
  Ideen-Backlog.
- dev/archive/: abgeschlossene Phasen — Migration-2026-Planung,
  Cutover-Runbook (mit Erledigt-Vermerk), Release-Plan/QA-Checkliste,
  Optimierungsphasen, Frontend-Konzepte + Responsive-Audits vom 16.07.,
  Altsystem-Reste.
- dev/README.md als Wegweiser; gitignore-Pfad der SQL-Dumps mitgezogen
  (dev/archive/migration-2026/sql/ bleibt untracked, ebenso dev/migration/
  und dev/api/).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 07:52:38 +00:00

326 lines
12 KiB
Markdown

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