Der Ordner dev/2026-07-22 ist ueber Monate gewachsen; ohne Einstieg findet man darin nichts mehr. Deshalb ein README als Wegweiser, mit dem Hinweis, dass bei Widerspruechen immer die juengere Entscheidung gilt (Beispiel: F7 wurde am 10.09. abgeloest). Die Bewertung traegt oben einen Stand-Block mit erledigten und offenen Befunden samt Sprungmarken. Ueberholte Aussagen der ersten Fassung sind markiert statt geloescht, damit der Weg nachvollziehbar bleibt. Der Monatsabschluss steht als eigenes Dokument, weil es eine dauerhafte Fachregel ist und keine Audit-Antwort: was eingefroren wird, was die Regel nicht leisten kann, und die Betriebsbefehle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.9 KiB
Abgeschlossene Monate sind eingefroren
Entscheidung der Kundin vom 10.09.2026, umgesetzt am selben Tag. Dieses Dokument hält fest, warum die Statistik so arbeitet, was genau eingefroren wird und was das nicht kann.
Es löst die August-Entscheidung F7 („Abo-Bestände tagesaktuell") ab. Der Bezug zu den Audit-Befunden A04 und A12 steht in Abschnitt 13 der Bewertung.
1. Die Regel
Am ersten Tag des Folgemonats läuft die Monatsabrechnung: Provisionen werden berechnet, Gutschriften ausgestellt, der Monat ist kaufmännisch abgeschlossen. Ab diesem Punkt ändert sich an diesem Monat nichts mehr — weder durch Stornos noch durch Änderungen an der Team-Struktur.
Die Regel gilt damit an zwei Stellen, die vorher unabhängig voneinander gedacht waren:
| Bereich | Regel |
|---|---|
| Buchungen/Stornos | Ein Storno mindert nur den Monat, in dem die Ursprungsbestellung liegt. Ist der Monat abgeschlossen, passiert nichts mehr (Details). |
| Statistik/Struktur | Ein abgeschlossener Monat wird nicht mehr aus heutigen Daten gerechnet, sondern aus dem gespeicherten Monatsstand. |
2. Warum die Struktur der eigentliche Grund ist
Die Team-Struktur ist beweglich: Teampartner kommen dazu, wechseln den Sponsor, fallen weg. Wird ein vergangener Monat weiter live gerechnet, verschiebt sich seine Auswertung mit jeder solchen Änderung.
Eine Beraterin sähe dann im Oktober für den August andere Zahlen als in der Abrechnung, die sie für den August bekommen hat — und die Ursache wäre von außen nicht erkennbar. Genau das war der Auslöser für die Entscheidung.
3. Was eingefroren wird
Der Snapshot ist der abgeschlossene Monat. Er enthält:
- Punkte und Umsätze je Linie und in Summe
- Abo-Bestände, Neupartner, „+N neu"
- Führungskräfte-, Recruiter- und Top-10-Listen
- die Mitglieder je Linie (
lines[].user_ids) - die Abos je Linie (
lines[].abo_ids, getrennt nach Team-/Kundenabos und jeweils „neu")
Die letzten beiden Punkte sind neu (Payload-Version 2). Aus ihnen baut
BackofficeDrilldownService die Detaillisten: Klickt man auf eine Zahl eines abgeschlossenen
Monats, zeigt die Liste genau die Mitglieder und Abos, aus denen diese Zahl entstanden ist — auch
wenn ein Abo inzwischen gekündigt oder gelöscht wurde (withTrashed()).
Bewusst nicht eingefroren: Stammdaten wie Name, E-Mail oder Karrierestufe. Sie werden zur Anzeigezeit gelesen. Eine Umbenennung soll rückwirkend sichtbar sein, eine Strukturänderung nicht.
4. Was das nicht kann
Für Monate, die vor dem 10.09.2026 abgeschlossen wurden, gibt es keine echte historische Struktur. Frühere Sponsor-Zuordnungen werden nirgends historisiert. Der Rebuild dieser Monate friert deshalb die Struktur des Ausführungstags ein, nicht die des damaligen Monatsendes.
Das war die bewusste Abwägung: Einheitlichkeit über alle Monate war wichtiger als die Rekonstruktion einer Struktur, die es nicht mehr gibt. Ab dem Monatsabschluss 01.10.2026 ist der eingefrorene Stand dann der tatsächliche Monatsstand.
Das Home-Dashboard friert für normale Berater nicht ein — Snapshots gibt es nur für die
VIP-Konten (admin 1–3). Wer das auch für alle Berater will, braucht Snapshots für alle Konten;
das ist eine eigene Entscheidung (Menge, Laufzeit, Speicher).
5. Betrieb
# Laeuft naechtlich; legt fehlende Snapshots fuer abgeschlossene Monate an
php artisan backoffice:store-statistics-snapshots
# Nur bei einem Schemawechsel des Payloads: baut vorhandene Snapshots neu.
# ACHTUNG: friert die Struktur des Ausfuehrungstags ein (siehe Abschnitt 4).
php artisan backoffice:store-statistics-snapshots --force
Beim Wechsel auf Payload-Version 2 wurde --force einmalig ausgeführt. Snapshots mit
Payload-Version 1 bleiben lesbar; ihre Detaillisten fallen auf die Live-Auswertung zurück, statt eine
Genauigkeit vorzutäuschen, die sie nicht haben.
6. Wo es im Code steht
| Datei | Rolle |
|---|---|
app/Services/Backoffice/BackofficeDashboardService.php |
Klassenkommentar mit der fachlichen Begründung; PAYLOAD_VERSION; buildLineRow() schreibt user_ids und abo_ids |
app/Services/Backoffice/BackofficeDrilldownService.php |
frozenLines(), frozenUserIds(), frozenAboIds(), aboScope() |
app/Console/Commands/BackofficeStoreStatisticsSnapshots.php |
Warnung zu --force |
app/Services/BusinessPlan/SalesPointsVolume.php |
dieselbe Regel auf der Buchungsseite (isStornoMonthOpen()) |
tests/Feature/BackofficeSnapshotFreezeTest.php |
Regressionen zum Einfrieren |
Die beiden Tests in BackofficeStatisticsListsTest.php, die vorher die alte Regel
(„Abo-Bestände tagesaktuell", August-Entscheidung F7) festhielten, beschreiben jetzt die neue. Sie
wurden umgeschrieben, nicht entfernt — die Szenarien bleiben abgedeckt.