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>
326 lines
12 KiB
Markdown
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.
|