diff --git a/CLAUDE.md b/CLAUDE.md index 08775c0..e8f477e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -298,12 +298,12 @@ Serverseitige Logik: `ReportController` ermittelt via `TimeEntryRepository::find ## Statistiken -Arbeitszeit-Statistik als gestapeltes Balkendiagramm (Chart.js), erreichbar über den Statistik-Button im Report-Header. Tab-Navigation zwischen „Zeiten" und „Statistiken". +Arbeitszeit-Statistik als gestapeltes Balkendiagramm (Chart.js) + drei Donut-Charts (Kunden, Projekte, Leistungen), erreichbar über den Statistik-Button im Report-Header. Tab-Navigation zwischen „Zeiten" und „Statistiken". ### Architektur - **Backend**: `ReportController::statistics()` (Seite) + `ReportController::statisticsData()` (API) -- **Frontend**: `assets/scripts/statistics.js` (eigener Webpack-Entry), nutzt Chart.js (tree-shaked: nur `BarController`, `BarElement`, `CategoryScale`, `LinearScale`, `Tooltip`) +- **Frontend**: `assets/scripts/statistics.js` (eigener Webpack-Entry), nutzt Chart.js (tree-shaked: `BarController`, `BarElement`, `DoughnutController`, `ArcElement`, `CategoryScale`, `LinearScale`, `Tooltip`) - **Styles**: `assets/styles/sections/_statistics.scss` - **Template**: `templates/report/statistics.html.twig` @@ -313,23 +313,30 @@ Arbeitszeit-Statistik als gestapeltes Balkendiagramm (Chart.js), erreichbar übe |--------------------|--------|-------------------------------------------------------| | `/api/statistics` | GET | Aggregierte Zeitdaten: `?range={12months|6months|4weeks}&userId={id}` | +Rückgabe enthält zwei Bereiche: +- **Balkendiagramm**: `labels`, `billable`, `nonBillable`, `billableRevenue`, `nonBillableRevenue`, `groupBy` +- **Verteilung**: `distribution.clients`, `distribution.projects`, `distribution.services` — jeweils Arrays mit `{name, hours, revenue}` + ### Daten-Aggregation -`TimeEntryRepository::getStatisticsData()` aggregiert Zeiteinträge in Buckets: +**Balkendiagramm** — `TimeEntryRepository::getStatisticsData()` aggregiert Zeiteinträge in Buckets: - **12months**: Monats-Buckets (`Y-m`), letztes Jahr - **6months**: Wochen-Buckets (`o-W`), letztes halbes Jahr - **4weeks**: Tages-Buckets (`Y-m-d`), letzte 4 Wochen -Rückgabe: `labels`, `billable`, `nonBillable`, `billableRevenue`, `nonBillableRevenue`, `groupBy`. Billable/Non-Billable Trennung via `Service.billable`. Revenue-Berechnung nutzt die Stundensatz-Kaskade. +Billable/Non-Billable Trennung via `Service.billable`. Revenue-Berechnung nutzt die Stundensatz-Kaskade. + +**Donut-Charts** — `TimeEntryRepository::getDistributionData()` aggregiert für denselben Zeitraum/User nach Kunden, Projekten und Leistungen (jeweils `SUM(duration)` und `SUM(rate * duration / 60)`). Einträge < 5% werden clientseitig zu „Rest" zusammengefasst. ### Frontend-Features -- **Metrik-Umschalter**: Stunden oder Umsatz (clientseitig, kein neuer API-Call) +- **Metrik-Umschalter**: Stunden oder Umsatz — gilt für Bar-Chart und Donuts (clientseitig, kein neuer API-Call) - **User-Filter**: Admins/Members können nach einzelnem User filtern oder alle sehen (Account-Name als „Alle") - **Tracker**: sieht nur eigene Daten (serverseitig erzwungen) - **Tages-Ansicht**: Alternierende Wochen-Bänder als visuelle Hilfe (Custom Chart.js Plugin `weekBands`) - **Tooltip**: Zeigt formatierte Stunden (`h:mm`) oder Umsatz (`€`) je nach Metrik - **Brand-Farbe**: Billable-Balken nutzen `--color-primary`, Non-Billable grau +- **Donut-Charts**: Drei nebeneinander (3-Spalten-Grid, responsive 1-Spalte), eigene Legende mit Farb-Dot, Name, Wert und Prozent. 8-Farben-Palette, „Rest" in Grau ## TenantConnectionMiddleware