mivita/dev/subdomain-optimization-gemini/README.md
2025-10-20 17:42:08 +02:00

5.7 KiB

Optimierung des Domain-Routings und Session-Handlings

Dieses Dokument beschreibt eine vorgeschlagene Optimierung für die bestehende Domain-Routing- und Session-Verwaltungslogik.

1. Analyse der aktuellen Architektur

Die Anwendung nutzt eine komplexe, aber leistungsstarke Multi-Domain-Architektur, um verschiedene Anwendungsbereiche (Hauptseite, CRM, Partner-Portal, Checkout, User-Shops) voneinander zu trennen.

  • Konfiguration: Die Domain-Struktur wird zentral in config/domains.php definiert.
  • Service Provider (DomainServiceProvider):
    • Registriert den DomainService (zuständig für Domain-Analyse und UserShop-Logik).
    • Registriert den DomainContext als Singleton, der pro Request Informationen über die aktuelle Domain enthält (Typ, Host, Subdomain, UserShop-Objekt).
    • Wichtig: Er registriert die DomainResolver-Middleware und fügt sie an den Anfang der web-Middleware-Gruppe hinzu.
  • Middleware (DomainResolver):
    • Nutzt den DomainContext, um die Anfrage zu validieren.
    • Leitet ungültige Domains auf die Hauptdomain um.
    • Prüft den Status von User-Shops (aktiv, Zahlung etc.).
    • Problembereich: Schreibt UserShop-Daten aktiv in die Session (Session::put, Session::save).
  • Routing (RouteServiceProvider): Lädt die passenden Routen-Dateien basierend auf dem type im DomainContext.

2. Identifiziertes Problem: Konflikte bei der Session-Erstellung

Das Kernproblem liegt in der Reihenfolge, in der die Middleware ausgeführt wird.

  1. Der DomainServiceProvider registriert die DomainResolver-Middleware mit prependMiddlewareToGroup('web', ...).
  2. Dadurch wird DomainResolver vor der Standard-Laravel-Middleware StartSession ausgeführt, die ebenfalls Teil der web-Gruppe ist.
  3. Die DomainResolver-Middleware versucht, auf die Session zuzugreifen und sie zu modifizieren (Session::put, Session::save). Da die StartSession-Middleware noch nicht gelaufen ist, wird hier möglicherweise eine "provisorische" Session gestartet.
  4. Anschließend läuft die StartSession-Middleware, die die "offizielle" Session aus dem Cookie lädt.
  5. Dies kann zu einem Konflikt führen, bei dem zwei verschiedene Session-Instanzen pro Anfrage existieren oder die in DomainResolver gespeicherten Daten nicht in der finalen Session-Response an den Client gesendet werden. Das Resultat ist, dass der UserShop-Kontext beim Wechsel zwischen Domains (z.B. vom Shop zum in.-Portal) verloren geht.

3. Vorgeschlagene Lösung: Saubere Trennung und korrekte Reihenfolge

Die vorgeschlagene Lösung zielt darauf ab, die Logik zu entzerren und die Middleware in der korrekten, von Laravel vorgesehenen Reihenfolge auszuführen.

Schritt 1: Korrektur der Middleware-Reihenfolge

Die DomainResolver-Middleware darf nicht mehr per prependMiddlewareToGroup im Service Provider registriert werden. Stattdessen sollte sie im app/Http/Kernel.php innerhalb der web-Gruppe nach der \Illuminate\Session\Middleware\StartSession-Middleware platziert werden.

Dadurch wird sichergestellt, dass die Session immer korrekt initialisiert ist, bevor unsere anwendungsspezifische Logik darauf zugreift.

Schritt 2: Aufteilung der Middleware-Verantwortlichkeiten

Die DomainResolver-Middleware hat aktuell zu viele Aufgaben. Eine Aufteilung verbessert die Lesbarkeit, Wartbarkeit und Einhaltung des Single-Responsibility-Prinzips.

Vorschlag für neue Middleware-Struktur:

  1. InitializeDomainContext (Neue Middleware):

    • Diese Middleware läuft sehr früh (kann global oder am Anfang der web-Gruppe stehen).
    • Ihre einzige Aufgabe ist es, den DomainContext zu initialisieren, indem sie app(DomainContext::class) aufruft. Sie führt keine Session-Operationen oder Umleitungen durch. Dies stellt sicher, dass der Kontext für alle nachfolgenden Teile der Anwendung (auch andere Middleware) verfügbar ist.
  2. HandleDomainLogic (Umbenannter DomainResolver):

    • Diese Middleware läuft nach StartSession.
    • Sie nutzt den bereits initialisierten DomainContext.
    • Aufgaben:
      • Umleitung bei isUnknown().
      • Validierung des UserShop (aktiv, bezahlt etc.).
      • Persistierung des UserShop-Kontexts in der Session. Die Logik hierfür wird verfeinert, um den Shop-Kontext über Domain-Grenzen hinweg intelligent zu erhalten. Zum Beispiel wird der user_shop nicht mehr gelöscht, nur weil man die main-Domain besucht. Er wird nur überschrieben, wenn ein neuer Shop-Kontext explizit gesetzt wird.

Schritt 3: Vereinfachung des Session-Handlings

Die setupLegacyContext-Methode wird überarbeitet. Das Ziel ist ein klares und vorhersehbares Verhalten:

  • Auf einer User-Shop-Domain: Der UserShop wird in die Session geschrieben.
  • Auf einer Nicht-Shop-Domain (crm, portal, checkout, main): Die Session wird nicht angerührt. Der bestehende UserShop aus der Session bleibt erhalten, sodass eine Rückkehr zum Shop jederzeit möglich ist.
  • Wechsel zu einem anderen User-Shop: Der neue UserShop überschreibt den alten Wert in der Session.

4. Vorteile der neuen Architektur

  • Stabilität: Das Session-Problem wird an der Wurzel behoben, indem die Middleware-Reihenfolge korrigiert wird.
  • Klarheit: Die Verantwortlichkeiten sind sauber getrennt. Eine Middleware für die Kontext-Initialisierung, eine für die Domain-Logik.
  • Wartbarkeit: Einfacher zu verstehen und zu erweitern. Das TECH-DEBT in setupLegacyContext wird reduziert.
  • Performance: Die Logik zur Domain-Analyse im DomainServiceProvider wird nur einmal ausgeführt, wenn der Kontext das erste Mal benötigt wird (lazy-loading), was beibehalten wird.

Die folgenden Dateien in diesem Ordner enthalten eine beispielhafte Implementierung dieses Vorschlags.