mivita/dev/2026-07-22/deploy-2026-09-14.md
Kevin 44637d06a7 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

117 lines
7.2 KiB
Markdown

# Deploy 14.09.2026 — Team-Statistik = Team-Struktur, Laufstand-Fix
Das Paket zu K11 aus dem [Entwicklungsplan zum September-Protokoll](../_tickets/entwicklungsplan-protokoll-september-2026.md)
(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. |
```bash
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.