mivita/dev/2026-06-23-abo/ENTWICKLUNGSPLAN-ABO-UEBERSICHTEN.md
Kevin 4135726772 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>
2026-06-23 14:07:29 +00:00

23 KiB
Raw Blame History

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.
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.
A3 Umfang Ebenen 1. Ebene zwingend als Default sichtbar; weitere Linien aufklappbar; „gesamter Baum" als Summenzeile/optionaler Modus.
A4 „selbst ein Abo abgeschlossen" Eigen-Abo = UserAbo is_for=me des Team-Mitglieds (Spalte/Badge pro Person: ja/nein + Punkte).
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).
A6 Dashboard-Widgets-Zielgruppe Alle aktiven Berater sehen „Gesamtabos im Team" + „1000-Punkte-Shops"; klickbar → neue Team-Abo-Ansicht.

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.
    1. Kachel-Dublette „Mit eigenem Abo" oben entfernt; verbleibende drei Kacheln auf col-md-4.
  • Render-Test entsprechend erweitert (gesamt 7 grün), Pint pass.