mivita/dev/2026-07-22/deploy-2026-09-14.md
Kevin de62a4291b Team-Statistik: Neu-Badge-Link kannte $selectedTree nicht (ViewException auf Produktion)
Die Closure fuer den Link des gruenen "+N"-Badges band die neue Variable nicht per use ein;
sobald eine Linie neue Abos zaehlte, brach die Uebersicht mit "Undefined variable $selectedTree" ab.
Regressionstest rendert die Uebersicht mit einem neuen Teamabo und prueft den Badge-Link.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 15:40:22 +00:00

7.2 KiB

Deploy 14.09.2026 — Team-Statistik = Team-Struktur, Laufstand-Fix

Das Paket zu K11 aus dem Entwicklungsplan zum September-Protokoll (Tickets C1 und C2) ist auf Produktion. Upload per SFTP, anschließend Migration, Snapshot-Neuaufbau, Laufstand-Reparatur und Cache-Leerung im Terminal. Die Zahlen von Team-Statistik und Team-Struktur stimmen seitdem überein (Rückmeldung Kevin, 14.09.).

Was live gegangen ist

Ticket Inhalt
C1 Die Team-Statistik rechnet standardmäßig mit dem Provisionsbaum und den Provisionspunkten — denselben Mitgliedern und Punkten wie die Team-Struktur. Die bisherige Sicht (gesamte Downline) bleibt per Umschalter erreichbar. Für abgeschlossene Monate kommen die Mitglieder je Linie aus dem gespeicherten Provisionslauf.
C2 Laufstand-Race in user_sales_volumes behoben: sperrendes Lesen bei der Neuberechnung, Deadlock-Wiederholung in beiden Zahlungs-Webhooks, tägliches Sicherheitsnetz um 02:45 vor dem Provisionslauf.
php artisan migrate
php artisan backoffice:store-statistics-snapshots --force
php artisan sales:repair-running-totals
php artisan config:clear && php artisan view:clear && php artisan cache:clear

Stolperstein beim Migrieren. Der erste migrate-Lauf brach mit „Undefined constant BackofficeDashboardService::TREE_COMMISSION" ab: die Migration hatte die Baum-Namen aus der Service-Klasse gelesen, und der PHP-Prozess auf dem Server hielt noch die alte Klasse (Opcache). Es wurde nichts halb angewendet — der Fehler fiel beim Aufbau des Blueprints, vor jedem SQL. Die Migration trägt die Werte jetzt als Literale; Regel für die Zukunft: Migrationen dürfen nicht vom Anwendungscode abhängen. Nach Pull, optimize:clear und PHP-FPM-Reload lief sie sauber durch.

Was sich in den Daten geändert hat

Migrationen.

  • backoffice_statistics_snapshots bekommt die Spalte tree (commission / downline); bestehende Snapshots werden als downline gekennzeichnet, der Unique-Index läuft jetzt über (user_id, year, month, tree).
  • user_sales_volumes bekommt den Index (user_id, year, month), damit die sperrende Lesart nur den Monatsbereich des Beraters sperrt. Keine vorhandene Zeile wurde verändert.

Snapshot-Neuaufbau. backoffice_statistics_snapshots wurde für alle abgeschlossenen Monate und beide Baum-Definitionen neu geschrieben (Payload-Version 3). Die Provisionsbaum-Variante nimmt die Mitglieder je Linie aus user_businesses des jeweiligen Provisionslaufs.

Laufstand-Reparatur September. sales:repair-running-totals hat die Laufstände von 2 Usern (848 und 1543, zusammen 216 Punkte) neu gerechnet. Nur die kumulativen Spalten der letzten Zeile wurden korrigiert; die Einzelbuchungen waren vollständig. Der laufende Monat rechnet in der Struktur live, die Provision für September wird damit richtig.

Nicht angefasst: Juni und August. Beide Monate hatten je einen User mit Laufstand-Drift (66 bzw. 82 Punkte) und sind so abgerechnet worden. Entscheid 14.09.: keine Nachzahlung, keine Nachberechnung. Die Laufstände bleiben, wie sie in die Provision eingegangen sind; der Nachtlauf fasst abgeschlossene Monate nicht an (manuell nur mit --force).

Nicht angefasst: Provisionen (user_businesses), Gutschriften, Rechnungen, Marketingplan.

Was das für die Zahlen bedeutet

Die Kachel „Umsatz (Punkte)" der Team-Statistik zeigt jetzt die Provisionspunkte. Gegenüber vorher ist sie kleiner, aus drei Gründen, die alle bewusst sind:

  1. Nur Provisionsbaum. Berater ohne Mitgliedsebene oder ohne Abrechnungskonto zählen nicht, und ihr Unterbaum ebenfalls nicht — genau wie in der Provisionsberechnung. Die Ansicht zeigt, wie viele Berater der Downline deshalb außen vor sind.
  2. Reine Karrierepunkte (KP) zählen nicht (Neupartner-Einschreibung, manuelle KP-Gutschriften). Sie stehen als eigene Zahl unter der Tabelle: „Nicht enthalten: X Punkte ohne Payline-Wirkung".
  3. Negative Monatssalden werden auf 0 gekappt, wie in der Provision. Auch das steht als eigene Zahl: „Nicht abgezogen: Y Punkte aus negativen Monatssalden".

Wer die bisherige Sicht braucht, wählt oben „Gesamte Downline". Die Wahl bleibt in der Sitzung erhalten und steckt auch im CSV-Dateinamen.

Beim Messlauf vor dem Deploy lagen die VIP-Konten im Provisionsbaum bis auf die Laufstand-Drift exakt auf der Struktur. Für August ergab sich nach Umstellung auf die gespeicherte Struktur nur noch eine Differenz von 82 Punkten — genau der Drift-User dieses Monats.

Woran man merken würde, dass etwas nicht stimmt

  • Team-Statistik, Provisionsbaum, laufender Monat: Summe der Linien muss mit dem Modal „Linie / Punkte / Provision" auf der Struktur-Seite auf den Cent übereinstimmen. Prüfung: php artisan statistics:compare-trees 9 2026 (Spalte „Diff PB-Struktur" muss 0,00 sein).
  • Abgeschlossener Monat: Abzeichen „Monat abgeschlossen · Stand eingefroren" plus Hinweis, dass die Mitglieder je Linie aus dem gespeicherten Provisionslauf stammen.
  • Nachtlauf 02:45: sales:repair-running-totals schreibt bei Drift eine Warnung ins cron-Log. Über mehrere Nächte sollte dort „keine Abweichung" stehen — das ist der Nachweis, dass die Sperre auf MySQL wirkt (die Test-Suite läuft auf SQLite und kann den Race nicht nachstellen).
  • Zahlungs-Webhooks: Ein Deadlock würde die ganze Paid-Transaktion bis zu dreimal wiederholen. Erkennbar im payone- bzw. stripe-Log nur, wenn alle drei Anläufe scheitern; dann stellt der Anbieter erneut zu.

Offen

  • C2, Stufe 3 (Provision aus der Zeilensumme statt aus dem Laufstand der letzten Zeile) gehört zum Ledger-Plan dev/2026-09-10-business-plan/.
  • Rückfrage R4 (negative Monatssalden in der Provision) ist eine fachliche Entscheidung und wurde nicht angefasst.
  • Unverändert: die vorbestehenden Testfehler auf dem Branch (92 Fehlschläge in Unit-Tests ohne Datenbank-Setup, z. B. TreeCalcBotOptimizedTest, ConcurrentPaymentTest; alle mit „no such table" oder BadMethodCallException bereits im Setup). Gehören in ein eigenes Aufräumpaket.

Nicht in diesem Commit und weiterhin nicht committet: die Arbeit aus anderen Themen im selben Arbeitsbaum (DHL, DATEV, Newsletter-Listen, Berater-Übertragung, DSGVO-Löschung, shipped_at, Kundenabo-Legenden).


Nachtrag 14.09.2026 — Übersicht brach mit „Undefined variable $selectedTree" ab

Kurz nach dem Deploy meldete Produktion auf /user/backoffice/statistics eine ViewException. Die Link-Closure für das grüne „+N"-Badge (neue Abos im Monat) in index.blade.php band die neue Variable $selectedTree nicht per use ein. Der Fehler trat nur auf, wenn in einer Linie neue Abos gezählt wurden — die Tests hatten die Übersicht bis dahin nie mit gefüllten Zeilen gerendert.

Behebung: use (..., $selectedTree) an der Closure, dazu ein Regressionstest, der die Übersicht mit einem neuen Teamabo rendert und den Badge-Link samt tree=-Parameter prüft (BackofficeStatisticsDrilldownTest). Ohne den Fix schlägt er mit genau dieser Meldung fehl.

Deployment: nur resources/views/user/backoffice/statistics/index.blade.php, danach php artisan view:clear. Keine Migration, keine Daten.