Konsolidierter Entwicklungsplan aus den zwei Analyse-Dokumenten plus
Umsetzung der Phase-0-Massnahmen (Korrektheit/Security, je mit Tests):
0.1 BasicAuth: timing-sicherer Vergleich (hash_equals, beide Felder ohne
Short-Circuit); Enabled-Check zur Laufzeit via config('auth.basic.*')
statt env() im Bootstrap-Closure (greift jetzt unter config:cache);
Config-Block + .env.example. Fund: auth.basic.* war nie als Config
definiert, Gate war faktisch unkonfigurierbar.
0.2 Legacy-Invoice-"latest"-Abfrage zentralisiert (LegacyInvoice::
scopeLatestFirst + User::latestLegacyInvoice); beide Consumer N+1-frei
umgestellt; unterschiedliches null-Verhalten bewusst erhalten.
0.3 Payment-Option-Eligibility vereinheitlicht (period-aware, strikt):
UserPaymentOption::scopeActiveNow/grandfatheredNow + User::
hasActivePaymentOption; hasActiveBooking/hasUnlimitedPressReleaseQuota
und ApiAccessEligibilityService darauf umgestellt; $hasGrandfathered-
Mislabel behoben.
0.4 Theme->Portal-Vokabular: totes, projektfremdes ThemeMiddleware
geloescht; Mapping in Portal::fromTheme() zentralisiert; fremden
b2in-Default im ThemeServiceProvider auf Portal-Default korrigiert.
0.5 InvoiceNumberGenerator: Erst-Insert race-sicher via insertOrIgnore
(Unique-Index auf circle existiert bereits). CreditWalletService war
bereits abgesichert (Unique-Index + createOrFirst).
Tests: 4 neue Dateien, 5 bestehende auf gueltiges grandfathered_until
angepasst. Volle Suite gruen (793 passed, 1 skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
12 KiB
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.phpresources/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 keinstatus-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.phpapp/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.phpresources/views/admin/press-releases/show.blade.phpresources/views/admin/roles/edit.blade.php
Ein Suchlauf hat nur einen produktiven view('admin.*')-Aufruf ergeben:
DashboardControllerrendertadmin.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.dashboardbehalten, solange der DashboardController sie nutzt- ungenutzte Admin-Wrapper entfernen oder in einen klaren Legacy-/Dokumentationsbereich verschieben
resources/views/admin/*.mdseparat 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:
WebPortalContextoder aehnlicher Service fuer DomainKey, Portal, PortalValues, Language und Theme-Konfiguration.PublishedReleaseQueryoder lokale Scopes am Model fuer veroeffentlichte Pressemitteilungen.- Page-Data-Klassen wie
HomePageData,CategoryPageData,NewsroomPageData. - Danach Routen auf schlanke Controller oder Invokable Controller umstellen.
Prioritaet: Hoch
4. Wiederholte Published-Release-Bedingungen
Dateien
routes/web.phpapp/Models/PressRelease.php
Die gleiche fachliche Bedingung fuer oeffentlich sichtbare Pressemitteilungen taucht mehrfach auf:
- Portal muss aktuelles Portal oder
bothsein - Status ist
published - Sprache passt
published_atist gesetztpublished_at <= now()
Teilweise wird withoutGlobalScope(PortalScope::class) verwendet, teilweise nicht. Das ist fachlich nachvollziehbar, aber die Logik sollte zentraler formuliert werden.
Empfehlung
Moegliche Scopes:
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.phpresources/views/livewire/admin/press-releases/edit.blade.phpresources/views/livewire/customer/press-releases/create.blade.phpresources/views/livewire/customer/press-releases/edit.blade.phpapp/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
updatedPublishModeupdatedScheduledDateupdatedScheduledTimesyncScheduledAtresolveScheduledAtvalidateScheduledAtWhenReady- 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:
- Admin-PM-Editoren ebenfalls
InteractsWithPressReleaseTagsnutzen lassen. InteractsWithPressReleaseSchedulingeinfuehren fuer Scheduling-Hooks und Validierung.- Gemeinsame Rule-Fragmente in einen Service oder Trait auslagern, z. B.
PressReleaseFormRules. - Wiederkehrende Formularabschnitte als Blade-Komponenten oder partials extrahieren.
Prioritaet: Hoch
6. API-Zugriffsqueries mehrfach eingebettet
Dateien
app/Http/Controllers/Api/V1/PressReleaseController.phpapp/Http/Controllers/Api/V1/PressReleaseImageController.phpapp/Http/Controllers/Api/V1/CompanyController.phpapp/Models/PressRelease.phpapp/Models/Company.php
Mehrere Controller enthalten fast gleiche Ownership-/Access-Queries:
findOwnedPressReleaseinPressReleaseControllerfindOwnedPressReleaseinPressReleaseImageController- Company-Zugriff ueber
owner_user_idoderusers-Pivot inCompanyController - 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_idcategory.translationsimages
Empfehlung
Eine private Methode oder ein Query-Scope:
private function resourceRelations(): array
oder:
PressRelease::query()->withApiResourceRelations()
Prioritaet: Mittel
8. Grosse Volt-Dateien als langfristiges Wartungsrisiko
Beispiele
resources/views/livewire/admin/press-releases/edit.blade.phpmit ca. 1394 Zeilenresources/views/livewire/customer/press-releases/create.blade.phpmit ca. 1371 Zeilenresources/views/livewire/customer/press-releases/edit.blade.phpmit ca. 1331 Zeilenresources/views/livewire/admin/users/edit.blade.phpmit ca. 1241 Zeilenresources/views/livewire/admin/press-releases/index.blade.phpmit 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.PortalScopekapselt Portalfilterung zentral.HasUniqueSlugreduziert 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
InteractsWithPressReleaseTagszeigen die richtige Richtung.
Vorgeschlagene Refactoring-Pakete
Paket A: Aufraeumen ohne Fachlogik-Aenderung
admin/users/tableRoute entfernen.resources/views/livewire/admin/users/table.blade.phpentfernen.- Ungenutzte
resources/views/admin/*Wrapper entfernen oder eindeutig als Legacy markieren. - Tests fuer fehlende/entfernte Route anpassen oder ergaenzen.
Nutzen: Weniger Altlasten, weniger Risiko durch erreichbare Demo-Komponente.
Paket B: Gemeinsame PM-Editor-Concerns
- Admin-PM-Editoren auf
InteractsWithPressReleaseTagsumstellen. InteractsWithPressReleaseSchedulingextrahieren.- Gemeinsame Rule-Fragmente zentralisieren.
- Bestehende PM-Editor-Tests gezielt laufen lassen.
Nutzen: Weniger Dopplung in vier grossen Dateien, geringere Fehlerwahrscheinlichkeit bei Scheduling.
Paket C: Web-Routen entflechten
- Portal-/Domain-Kontext extrahieren.
- Published-Release-Query zentralisieren.
- Home/Kategorie/Newsroom-Daten in Services verschieben.
- Routen schrittweise auf kleine Controller umstellen.
Nutzen: Bessere Testbarkeit, klarere Verantwortlichkeiten, zentraleres Performance-Tuning.
Paket D: API-Zugriff zentralisieren
Company::accessibleBy(User $user)einfuehren.- API-PressRelease-Zugriff zentral benennen.
- Eager-Load-Sets fuer API Resources zentralisieren.
- 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:
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.