Abo-Uebersichten: Team-Ansicht konsolidiert, Monatsfilter, Wachstum & Dashboard-KPIs

- /user/abos/ot: Filter nach Eingangsmonat (start_date) ueber neuen UserAbo-Scope
- Konsolidierte Team-Abo-Ansicht nach Ebenen/Linien (Bestand, neue Abos im Monat,
  Eigen-/Kundenabos, Punkte je Ebene + Summen) via TeamAboOverviewService
- team/customers leitet auf konsolidierte Ansicht um; Navigation bereinigt
- Mitglieder-Detail-Modal mit Abo-Zusammenfassung (Eigen-Abo, Kundenabos,
  Punkte, Beginn, naechste Ausfuehrung, Ausfuehrungen)
- Wachstums-Tabelle (Jahr x Monate) + Liniendiagramm (neue Eigen-/Kundenabos)
- Dashboard-KPI-Kachel (Gesamtabos, Kundenabos, 1000-Punkte-Shops)
- i18n de/en/es/fr, Tests (Filter, Overview, Wachstum, Modal, Redirect)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin 2026-06-23 14:07:29 +00:00
parent 65b867f8ee
commit 4135726772
15 changed files with 967 additions and 174 deletions

View file

@ -0,0 +1,320 @@
# Entwicklungsplan: Abo-Übersichten erweitern (eigene Kundenabos, Team-Abos, Dashboard)
> **Status:** In Planung · **Erstellt:** 2026-06-23 · **Briefing:** Kundenanfrage + `docs/salescenter/Todos Backoffice.md`
## Dokumentations-Hinweis (verbindlich)
Dieser Plan wird **Schritt für Schritt** abgearbeitet. Für **jede Phase** gilt:
- Der **Umsetzungsstatus** in diesem Dokument wird nach Abschluss eines Schritts auf `ERLEDIGT` gesetzt (mit Datum, betroffenen Dateien, Zeilenangaben und kurzer Begründung).
- **Alle Phasen, Hinweise und getroffenen Detail-Entscheidungen** werden sauber dokumentiert – auch Abweichungen vom Plan und Verworfenes (mit Begründung).
- Jede Änderung wird **programmatisch getestet** (Pest), bevor die Phase als erledigt gilt.
- Nach Code-Änderungen läuft `./vendor/bin/pint --dirty`.
---
## 1. Ziel & Briefing-Zusammenfassung
Die Darstellung/Auflistung der Abos im Sales Center (`my.mivita.care`) soll erweitert werden. Vier Bausteine:
1. **Eigene Kundenabos** (`/user/abos/ot`): Filter nach **Monat & Jahr**, in dem das Abo hinzugekommen ist (Eingangsmonat).
2. **Team-Abo-Ansichten zusammenführen** (`/user/abos/team/show` + `/user/abos/team/customers`): Beide Seiten überschneiden sich stark und sollen zu **einer** Ansicht „Abos im Team" verschmelzen. Inhalt:
- Wer im Team hat wie viele **Kundenabos** abgeschlossen?
- **Sortierung nach Monaten:** Wer im Team hat diesen Monat (Monatsfilter) wie viele **neue** Abos (Kunden- und Eigen-Abos) abgeschlossen?
- Wer im Team hat **selbst** ein Abo abgeschlossen?
- **Gesamtübersicht:** Wie viele Abos haben Team-Mitglieder insgesamt?
- **Sortierung nach Ebenen (Linien):** Wichtigste Ebene ist die **1. Ebene** (Wer hat dort ein Abo, wer nicht?), optional ausbaubar auf den gesamten Baum.
3. **Dashboard ergänzen:** Anzahl der **„1000-Punkte-Shops"** und **Gesamtabos im Team**.
---
## 2. Ist-Zustand (Analyse-Ergebnis)
### 2.1 Eigene Kundenabos `/user/abos/ot`
| Bereich | Status heute | Schlüsseldateien |
| ------- | ------------ | ---------------- |
| Controller | `AboController@index($view='ot')` lädt `UserAbo` (`member_id = Auth`, `is_for=ot`, `status>=1`), liefert bereits `chartData` (Jahresfilter) | `app/Http/Controllers/User/AboController.php:62-83` |
| View | Card-Liste pro Abo, oben Monats-Chart (`_abo_chart`) mit **Jahres**-Umschaltung | `resources/views/user/abo/index.blade.php`, `resources/views/user/abo/_abo_chart.blade.php` |
| Monatszählung | `AboHelper::getMonthlyAboCounts()` (Snapshot vergangener Monate + Live aktueller Monat) | `app/Services/AboHelper.php:514-565` |
| Filter | **Nur Jahr** (Chart). Keine Filterung der Card-Liste nach Eingangsmonat. | – |
**Fazit:** Jahresfilter existiert über den Chart. Es fehlt ein **Monat+Jahr-Filter auf die Liste** (Abos, deren `start_date` im gewählten Monat liegt).
### 2.2 Team-Abos `/user/abos/team/show` & `/user/abos/team/customers`
| Route | Methode | Inhalt heute |
| ----- | ------- | ------------ |
| `user_abos_team_show` | `TeamController@showAbos` | Flache Card-Liste **aller eigenen Team-Abos** (`is_for=me`, `user_id ∈ Team`), Jahres-Chart `team_abos`. Eine Card pro Abo. |
| `user_abos_team_customers` | `TeamController@showTeamCustomerAbos` | Kundenabos im Team (`is_for=ot`, `member_id ∈ Team`), **gruppiert pro Team-Mitglied** (collapsible), anonymisiert, Jahres-Chart `team_cust_abos`. |
- Beide nutzen `AboHelper::getTeamUserIds($userId)` (rekursive Downline über `m_sponsor`, **flach**, ohne Linien-Information).
- Beide nutzen denselben `_abo_chart`-Partial (nur Jahr).
- **Überschneidung:** Beide listen Team-Abos, nur unterschiedlich (eigene Abos vs. Kundenabos) und unterschiedlich gruppiert. Keine Ebenen-/Linien-Sortierung, keine „neue Abos diesen Monat"-Aggregation pro Person.
- Detailseite: `TeamController@detailAbo` (`user_abos_team_detail`).
### 2.3 Dashboard
| Bereich | Status heute | Datei |
| ------- | ------------ | ----- |
| Dashboard-Home | Karten-Grid; Abo-Bezug nur: Einmalprodukt-Card (`_abo_onetime`) | `resources/views/home.blade.php`, `app/Http/Controllers/HomeController.php:45-92` |
| Team-/Abo-KPIs | **Nicht vorhanden** auf dem Dashboard | – |
### 2.4 Bereits vorhandenes Backoffice-Statistik-Modul (WICHTIG – Wiederverwendung!)
Es existiert ein **VIP-only** Modul, das den Großteil der gewünschten Team-Logik bereits abbildet:
| Komponente | Datei | Liefert |
| ---------- | ----- | ------- |
| Controller | `app/Http/Controllers/User/BackofficeStatisticsController.php` | Übersicht / Drilldown / CSV-Export, Monat+Jahr-Filter (Session-persistiert), nur `isVIP()` |
| Dashboard-Service | `app/Services/Backoffice/BackofficeDashboardService.php` | **`lineBuckets($rootUserId)`** = Downline gruppiert nach **Linien/Ebenen** (1..n); pro Linie: Berater-Zahl, Neupartner, **Teamabos** (`team_partner_abos`), **neue Teamabos** (`team_partner_abos_new`), **Teamkundenabos** (`team_customer_abos`), **neue** (`team_customer_abos_new`), Punkte-Aufschlüsselung, **`shop_1000`** (1000-Punkte-Shop-Zähler), Umsatz; plus **`totals`**-Zeile. Snapshots für abgeschlossene Monate. |
| Drilldown-Service | `app/Services/Backoffice/BackofficeDrilldownService.php` | Personenlisten je Linie+Metrik (Namen, Punkte, Status, Besteht-seit, nächste Ausführung). |
| Snapshot-Modell | `app/Models/BackofficeStatisticsSnapshot.php` | Eingefrorene Monatswerte pro User. |
> **Schlüssel-Erkenntnis:** Die in der Kundenanfrage gewünschte Ebenen-/Monats-/Gesamtlogik **existiert technisch schon** in `BackofficeDashboardService`. Wir bauen **nicht neu**, sondern (a) machen diese Datenquelle für die Abo-Ansicht wiederverwendbar und (b) liefern eine schlankere, für **alle Berater** zugängliche Abo-fokussierte Ansicht + Dashboard-Widgets.
Definition **„1000-Punkte-Shop"** (laut Briefing, bereits im Service implementiert): Teampartner, die **mind. 1000 Punkte Kundenumsatz** im gewählten Monat erzielen (`shop1000Count()`).
---
## 3. Offene Fragen / Annahmen
| # | Thema | Annahme (sofern nicht anders entschieden) |
| - | ----- | ----------------------------------------- |
| A1 | „Eingangsmonat" eines Abos | = `start_date` (Anlage-/Aktivierungsdatum). Filter zeigt Abos mit `start_date` im gewählten Monat/Jahr. | JA
| A2 | Zugänglichkeit der neuen Team-Ansicht | Für **alle aktiven Berater** (nicht nur VIP), da rein abo-bezogen und über die eigene Downline. Das umfangreiche Punkte-/Umsatz-Backoffice bleibt VIP-only. | JA
| A3 | Umfang Ebenen | **1. Ebene zwingend** als Default sichtbar; weitere Linien aufklappbar; „gesamter Baum" als Summenzeile/optionaler Modus. | JA
| A4 | „selbst ein Abo abgeschlossen" | Eigen-Abo = `UserAbo is_for=me` des Team-Mitglieds (Spalte/Badge pro Person: ja/nein + Punkte). | JA
| A5 | Zusammenführen der zwei Routen | Neue konsolidierte Seite unter `user_abos_team_show`; `team/customers` wird Weiterleitung/Tab oder entfällt aus der Navigation (Route bleibt vorerst als Redirect). | Redirect
| A6 | Dashboard-Widgets-Zielgruppe | Alle aktiven Berater sehen „Gesamtabos im Team" + „1000-Punkte-Shops"; klickbar → neue Team-Abo-Ansicht. | JA
> **Diese Annahmen bitte vor Umsetzungsbeginn bestätigen oder korrigieren.**
---
## 4. Lösungsvorschlag (Architektur)
### 4.1 Gemeinsame Datenquelle: `TeamAboOverviewService` (neu)
Neuer Service `app/Services/Abo/TeamAboOverviewService.php`, der die Linien-/Monats-/Gesamtlogik **abo-fokussiert** kapselt und intern `BackofficeDashboardService::lineBuckets()` (oder eine extrahierte, gemeinsam genutzte Helper-Methode) wiederverwendet.
Liefert je Linie:
- `line` (1..n), `consultants` (Anzahl Berater dieser Ebene)
- `members_with_own_abo` / `members_total` (wer hat selbst ein Abo)
- `team_partner_abos` (Summe Eigen-Abos der Ebene) + `_new` (neu im Monat)
- `team_customer_abos` (Summe Kundenabos der Ebene) + `_new`
- pro Person (für Drilldown/aufgeklappte Ebene): Name, Karriere-Level, Eigen-Abo (ja/Punkte), #Kundenabos + Punkte, #Teamabos darunter
- `totals`-Zeile über alle Linien
Vorteil: Eine zentrale, getestete Datenquelle für **Team-Ansicht** und **Dashboard-Widgets**. Refactoring-Hinweis: Falls `lineBuckets()`/`newAboCount()`/`shop1000Count()` aus `BackofficeDashboardService` extrahiert werden, in einen gemeinsamen `Trait`/Helper auslagern, um Duplikate zu vermeiden.
### 4.2 Phase-Übersicht
| Phase | Inhalt | Aufwand |
| ----- | ------ | ------- |
| **P1** | `/user/abos/ot`: Monat+Jahr-Filter auf die Liste | klein |
| **P2** | `TeamAboOverviewService` (Datenquelle + Tests) | mittel |
| **P3** | Konsolidierte Team-Abo-Ansicht (Linien/Ebenen, Monatsfilter, neue Abos, Eigen-Abo-Spalte, Summen) | mittel-groß |
| **P4** | Zusammenführung `team/customers` → Redirect/Tab, Navigation anpassen | klein |
| **P5** | Dashboard-Widgets „Gesamtabos im Team" + „1000-Punkte-Shops" (klickbar) | klein-mittel |
| **P6** | i18n (de/en/es/fr), Pint, Gesamttest | klein |
---
## 5. Detailplanung pro Phase
### Phase 1 — `/user/abos/ot`: Monat- & Jahr-Filter
**Status:** ERLEDIGT (2026-06-23)
**Umsetzung:**
- `app/Models/UserAbo.php`: Query-Scope `scopeAddedInMonth($query, $year, $month)` (Filter nach `start_date`; `month=0` lässt Abfrage unverändert).
- `app/Http/Controllers/User/AboController.php` (`index('ot')`): wertet `month`-Param aus, nutzt `addedInMonth()`, übergibt `filterMonth`/`filterYear` an die View.
- `resources/views/user/abo/index.blade.php`: Filterleiste (Monats-Dropdown + Jahr + Filtern/Zurücksetzen) über der Card-Liste (nur `view==='ot'`).
- i18n: `abo.filter`, `abo.reset`, `abo.filter_added_period` in de/en/es/fr.
- Test: `tests/Feature/AboOtMonthFilterTest.php` (2 Tests grün).
- `AboController@index('ot')`: zusätzlich `month`-Parameter (Default „alle") auswerten.
- Liste filtern: `whereYear('start_date', $year)` + optional `whereMonth('start_date', $month)`.
- View `user/abo/index.blade.php`: Filterleiste (Monats-Dropdown + Jahr) über der Card-Liste; Chart bleibt. Wiederverwendung von `HTMLHelper::getTransMonths()` / `getYearRange()`.
- Filter-Persistenz analog zu bestehenden Mustern (Query-Param genügt; Session optional).
- **Test:** `tests/Feature` – Abos mit `start_date` in verschiedenen Monaten anlegen, Filter prüft korrekte Teilmenge.
### Phase 2 — `TeamAboOverviewService`
**Status:** ERLEDIGT (2026-06-23)
**Umsetzung:**
- `app/Models/UserAbo.php`: Scope `scopeActiveAbo()` (active=true, status ∉ {4,5,6}) – konsistent mit `BackofficeDashboardService`.
- `app/Services/Abo/TeamAboOverviewService.php`: `linesOverview(User,$month,$year)` liefert je Ebene Berateranzahl, „mit Eigen-Abo", Eigen-Abos (+Punkte +neu), Kundenabos (+Punkte +neu), pro-Mitglied-Details und eine Summenzeile. Wiederverwendung von `BackofficeDashboardService::lineBuckets()` (keine Duplizierung der Baum-Traversierung).
- i18n: `abo.team_total`, `abo.team_line` in de/en/es/fr.
- Test: `tests/Feature/TeamAboOverviewTest.php` (2 Tests, 19 Assertions grün). Hinweis: Test-Schema hat keine `products.slug`-Spalte → `beforeEach` ergänzt sie (etabliertes Muster aus `MembershipQtyProtectionTest`).
- Neuer Service mit Methoden:
- `linesOverview(User $user, int $month, int $year): array` (Linien + Totals, abo-fokussiert)
- `lineMembers(User $user, int $line, int $month, int $year): Collection` (Personen einer Ebene mit Abo-Kennzahlen)
- Wiederverwendung der vorhandenen `lineBuckets()`-Logik (gemeinsam nutzbar machen).
- „neue Abos im Monat": Logik aus `BackofficeDashboardService::newAboCount()` wiederverwenden (Definition: `start_date` im Monat, aktiver Status).
- **Test:** Unit/Feature – Downline mit mehreren Ebenen + Abos in verschiedenen Monaten; prüft Linien-Zuordnung, neue-Abo-Zähler, Eigen-Abo-Flag, Summen.
### Phase 3 — Konsolidierte Team-Abo-Ansicht
**Status:** ERLEDIGT (2026-06-23)
**Umsetzung:**
- `TeamController@showAbos` nutzt `TeamAboOverviewService` + Monat/Jahr-Filter (`selectedAboPeriod()`, Session-persistiert).
- Neue View `resources/views/user/team/abos.blade.php`: Monats-/Jahresfilter, Summen-Cards (Gesamtabos, Eigen-Abos, Kundenabos, Mitglieder mit Abo), Linien-/Ebenen-Tabelle (1. Ebene hervorgehoben + standardmäßig offen), aufklappbare Mitgliederliste je Ebene (Eigen-Abo ja/nein, #Kundenabos, Punkte), Summenzeile.
- i18n: viele neue `abo.*`-Keys (filter_period, team_total_abos, team_own_abos, team_members_with_abo, team_by_level, new_this_month, with_own_abo, consultants, level, own_abo, customer_abos_count, career_level, of, yes, no) in de/en/es/fr.
- Test: Render-Test in `tests/Feature/TeamAboOverviewTest.php` (3 Tests grün).
- `TeamController@showAbos` umstellen auf `TeamAboOverviewService` + Monat/Jahr-Filter (Session-persistiert, analog `BackofficeStatisticsController::selectedPeriod()`).
- Neue View `resources/views/user/team/abos.blade.php` (umbauen):
- **Kopf:** Monats-/Jahresfilter + Summen-Card (Gesamt-Teamabos, Gesamt-Kundenabos im Team, neue diesen Monat, #1000-Punkte-Shops).
- **Linien-Tabelle:** Zeile je Ebene (1. Linie zuerst, hervorgehoben): Berater, „mit Eigen-Abo", Eigen-Abos (Punkte), Kundenabos (Anzahl+Punkte), neue Abos (Monat). Summenzeile unten.
- **Aufklappbar pro Ebene:** Personenliste (Name, Karriere-Level, Eigen-Abo ja/nein, #Kundenabos, Punkte). 1. Ebene standardmäßig offen.
- Detail-Link je Abo → `user_abos_team_detail` bleibt erhalten.
- Wiederverwendung des `_abo_chart`-Partials für den Monatsverlauf (optional beibehalten).
- **Test:** Feature – View rendert Linien korrekt, 1. Ebene sichtbar, Summen stimmen.
### Phase 4 — Zusammenführung `team/customers`
**Status:** ERLEDIGT (2026-06-23)
**Umsetzung:**
- `TeamController@showTeamCustomerAbos` leitet dauerhaft auf `user_abos_team_show` um (Route bleibt für Altlinks). Kundenabos sind als Spalte/Drilldown in die konsolidierte Ansicht eingeflossen.
- Navigation `layout-sidenav.blade.php`: Menüpunkt „Team Kunden" entfernt; „Teamabos" markiert nun auch die `team/customers`-URL aktiv.
- `resources/views/user/team/customer_abos.blade.php` bleibt vorerst bestehen (nicht mehr verlinkt), um nichts ungewollt zu löschen.
- Test: `tests/Feature/TeamCustomerAbosRedirectTest.php` (Redirect grün).
- Kundenabos-Inhalt als **Tab/Abschnitt** in die konsolidierte Ansicht integrieren (gruppiert pro Mitglied bleibt als Drilldown erhalten).
- `user_abos_team_customers` → Redirect auf `user_abos_team_show` (Route bleibt für Bookmarks bestehen).
- Navigation `layout-sidenav.blade.php`: Punkt „Team Kunden" entfernen/zusammenführen; Label gem. Briefing „**Kundenabos im Team**" / „Teamkundenabos" verwenden (Terminologie-Korrektur).
- **Test:** Redirect-Test; Navigation-Smoke.
### Phase 5 — Dashboard-Widgets
**Status:** ERLEDIGT (2026-06-23)
**Umsetzung:**
- `BackofficeDashboardService::shop1000Count()` auf `public` gesetzt (Wiederverwendung).
- `TeamAboOverviewService::teamKpis(User,$month,$year)`: leichtgewichtige KPIs (Gesamtabos, Teamabos, Teamkundenabos, 1000-Punkte-Shops) ohne teure Punkte-/Mitglieder-Aggregation.
- `HomeController@show`: berechnet `teamAboKpis` für aktive Berater (aktueller Monat).
- Neues Partial `resources/views/dashboard/_abo_team_kpis.blade.php`: klickbare KPI-Card (→ `user_abos_team_show`), eingebunden in `home.blade.php`.
- i18n: `abo.shop_1000` in de/en/es/fr.
- Test: KPI-Test in `tests/Feature/TeamAboOverviewTest.php` (4 Tests grün).
- `HomeController@show`: für aktive Berater via `TeamAboOverviewService` (bzw. `BackofficeDashboardService::overview()`-Totals für den aktuellen Monat) zwei KPIs berechnen:
- **Gesamtabos im Team** (`team_partner_abos` + `team_customer_abos` der Totals, oder getrennt anzeigen).
- **1000-Punkte-Shops** (`shop_1000` Totals).
- Neuer Partial `resources/views/dashboard/_abo_team_kpis.blade.php`: zwei klickbare KPI-Cards → Link auf neue Team-Abo-Ansicht (bzw. Backoffice-Statistik bei VIP).
- Performance: Für das Dashboard nur **eine** Monatsberechnung; bei großen Teams ggf. Snapshot/Cache des aktuellen Monats nutzen (kein Live-Vollscan bei jedem Dashboard-Aufruf – ggf. Caching mit kurzer TTL).
- **Test:** Feature – KPIs erscheinen für aktiven Berater mit Team-Abos; Werte stimmen.
### Phase 6 — i18n & Abschluss
**Status:** ERLEDIGT (2026-06-23)
**Umsetzung:**
- i18n: alle neuen `abo.*`-Keys in de/en/es/fr gepflegt; `LocalizationSyncTest` grün (Sprachen synchron).
- Pint: `--dirty` → pass.
- Tests: 29 relevante Tests grün (Phase 1–5 + bestehende Abo-Tests), `LocalizationSyncTest` (3 Tests) grün.
- Neue Übersetzungsschlüssel in `resources/lang/{de,en,es,fr}/abo.php` + `navigation.php`/`team.php` (Filter-Labels, Spaltenköpfe, KPI-Titel, „1000-Punkte-Shop", „Kundenabos im Team", „neue Abos").
- `./vendor/bin/pint --dirty`.
- Gesamttest der betroffenen Feature-/Unit-Dateien.
---
## 6. Zu beachtende Punkte / Risiken
1. **Keine Logik-Duplikate:** `BackofficeDashboardService` ist die Referenz für Linien/neue Abos/1000-Punkte-Shop. Gemeinsame Methoden extrahieren statt kopieren.
2. **Performance:** Downline-Traversierung (`lineBuckets`) kann bei großen Teams teuer sein. Dashboard-Widgets cachen oder Snapshot des aktuellen Monats nutzen; nicht bei jedem Request live voll durchrechnen.
3. **Zugriffsrechte/Datenschutz:** Kundenabos im Team sind heute **anonymisiert** dargestellt (`customer_privacy_info`). Diese Anonymisierung beibehalten; Klarnamen nur dort, wo bisher erlaubt (Team-Mitglieder = Berater). VIP-/Datenschutz-Hinweise aus dem bestehenden Backoffice-Modul übernehmen.
4. **Status-Definition Abo aktiv:** Konsistent mit `getMonthlyAboCounts()`/`activeAboQuery()` halten (Terminal-Status 4/5 ausschließen).
5. **Snapshots:** Vergangene Monate aus `AboChartSnapshot` bzw. `BackofficeStatisticsSnapshot` lesen (nicht neu berechnen). Aktueller Monat live.
6. **Route-Kompatibilität:** `user_abos_team_customers` nicht hart entfernen (Bookmarks/Links) → Redirect.
7. **Multi-Tenant/Routing:** Änderungen liegen in `routes/domains/crm.php` (CRM-Domain). Keine Auswirkungen auf andere Domains.
---
## 7. Betroffene Dateien (Vorschau)
**Neu:**
- `app/Services/Abo/TeamAboOverviewService.php`
- `resources/views/dashboard/_abo_team_kpis.blade.php`
- `tests/Feature/TeamAboOverviewTest.php`, `tests/Feature/AboOtMonthFilterTest.php`, `tests/Feature/DashboardAboKpisTest.php`
**Geändert:**
- `app/Http/Controllers/User/AboController.php` (P1)
- `app/Http/Controllers/User/TeamController.php` (P3/P4)
- `app/Http/Controllers/HomeController.php` (P5)
- `app/Services/Backoffice/BackofficeDashboardService.php` (gemeinsame Methoden extrahieren)
- `resources/views/user/abo/index.blade.php` (P1)
- `resources/views/user/team/abos.blade.php` (P3)
- `resources/views/user/team/customer_abos.blade.php` (P4 – Integration/Redirect)
- `resources/views/home.blade.php` (P5)
- `resources/views/layouts/includes/layout-sidenav.blade.php` (P4)
- `routes/domains/crm.php` (P4 – Redirect)
- `resources/lang/{de,en,es,fr}/abo.php`, `navigation.php`, `team.php` (P6)
---
## 8. Umsetzungsreihenfolge (empfohlen)
P1 (schneller Mehrwert, isoliert) → P2 (Datenbasis) → P3 (Hauptansicht) → P4 (Konsolidierung/Navi) → P5 (Dashboard) → P6 (i18n/Abschluss).
---
## 9. Nachtrag — Mitglieder-Detail-Modal (2026-06-23)
**Status:** ERLEDIGT
Statt des generischen `business-user-show`-Modals (Sponsor/Firma) zeigt der Klick auf einen Namen in der Team-Abo-Übersicht jetzt eine abo-fokussierte Zusammenfassung.
**Umsetzung:**
- `TeamAboOverviewService::memberAboSummary(User $owner, int $memberId)`: liefert Name + E-Mail, Eigen-Abo (Punkte, Beginn, nächste Ausführung, Anzahl Ausführungen) sowie Kunden-Abos (Anzahl, Gesamtpunkte, Liste je Abo). Team-Autorisierung via `AboHelper::isUserInTeam()` → `null` (→ „nicht gefunden"-Modal), wenn Mitglied nicht in Downline.
- `ModalController@load`: neuer Branch `team-abo-member-show`.
- Neue View `resources/views/user/team/modal_member_abos.blade.php`.
- `user/team/abos.blade.php`: Namens-Link nutzt `data-action="team-abo-member-show"`.
- i18n: `abo.next_execution`, `abo.executions_count`, `abo.abo_count_points`, `abo.no_own_abo`, `abo.no_customer_abos` in de/en/es/fr.
- Tests: 2 zusätzliche Tests in `tests/Feature/TeamAboOverviewTest.php` (gesamt 6 grün).
---
## 10. Nachtrag — Zeitraum-Logik: Bestand + Wachstums-Tabelle (2026-06-23)
**Status:** ERLEDIGT
**Entscheidung (mit Kunde):** Variante **A + C** statt historischem Filter (Variante B verworfen, da „aktiv" ein Jetzt-Zustand ist und eine historische Rekonstruktion fehleranfällig/irreführend wäre).
**Umsetzung:**
- Oberer Bereich (Cards + Linien-Tabelle) zeigt immer den **aktuellen Bestand**; die „+neu"-Badges beziehen sich fest auf den **laufenden Monat** (Spaltenkopf zeigt den Monatsnamen). Der frühere, missverständliche Zeitraum-Filter wurde entfernt.
- Neue **Wachstums-Tabelle** unter der Bestandsübersicht: wählbares Jahr (GET-Param `year`), Zeilen = Monate, Spalten = neue Eigen-Abos / neue Kunden-Abos / Summe + Jahres-Summenzeile.
- `TeamAboOverviewService::monthlyGrowth(User,$year)` + privater Helfer `newAbosByMonth()` (DB-agnostisch via `toBase()->pluck('start_date')` + PHP-Gruppierung, kein `MONTH()`/`strftime`). Definition „neu" konsistent mit Badges (aktives Abo, `start_date` im Monat).
- `TeamController@showAbos` vereinfacht (kein Session-Filter mehr): Bestand = aktueller Monat, Wachstum = `year`-Param.
- i18n: `abo.team_growth`, `abo.month`, `abo.new_own_abos`, `abo.new_customer_abos`, `abo.new_total` in de/en/es/fr.
- Tests: 1 zusätzlicher Test (`monthlyGrowth`) + angepasster Render-Test (gesamt 7 grün).
---
## 11. Nachtrag — Tabellen-Feinschliff Ebenen (2026-06-23)
**Status:** ERLEDIGT
- Linien-Tabelle: redundante Spalte „Mit Eigen-Abo" entfernt (= identisch zu „Eigen-Abos", da max. 1 Eigen-Abo pro Berater).
- Neue Spalte **„Punkte"** (Gesamtpunkte je Ebene = Eigen- + Kundenabo-Punkte) inkl. Gesamtsumme im Footer (nutzt vorhandene `own_abo_points`/`customer_abo_points` aus `linesOverview`).
- Hinweis-Fußzeile unter der Wachstums-Tabelle (`abo.growth_note`) erklärt die Differenz Bestand vs. Jahres-Wachstum.
- **Klarstellung 124 vs. 123:** kein Bug. 124 = aktueller Bestand aller aktiven Eigen-Abos; 123 = davon in 2026 gestartet. 1 Eigen-Abo stammt aus einem Vorjahr und ist weiterhin aktiv.
- i18n: `abo.growth_note` in de/en/es/fr.
---
## 12. Nachtrag — Wachstums-Liniendiagramm (2026-06-23)
**Status:** ERLEDIGT
- Unter der Wachstums-Tabelle: Chart.js-**Liniendiagramm** (X = Monate, Y = Mengen) mit zwei Kurven (neue Eigen-Abos, neue Kunden-Abos) für das gewählte Jahr.
- Datenaufbereitung im Controller (`TeamController::buildGrowthChart()`) statt im Blade `@php`-Block – sauberere MVC-Trennung und umgeht ein Blade-Kompilierungsproblem mit `@php`-Block + Arrow-Funktionen in diesem Template.
- Nutzt dieselbe Chart.js-v2-Lib wie `_abo_chart.blade.php` (`/vendor/libs/chartjs/chartjs.js`), feste Canvas-ID `aboGrowthChart`.
- 2. Kachel-Dublette „Mit eigenem Abo" oben entfernt; verbleibende drei Kacheln auf `col-md-4`.
- Render-Test entsprechend erweitert (gesamt 7 grün), Pint pass.