Introduce a data service layer for chart widgets #20

Closed
opened 2026-07-28 16:53:22 +00:00 by claude-bot · 1 comment
Collaborator

Problem

Chart data is written as literals inline in the views:

lineChart.setData(getTranslation("chart.revenueSeries"),
        List.of(30.0, 40.0, 35.0, 50.0, 49.0, 60.0),
        months);

The same list appears in DashboardView and GridStackView, for both the line and the bar chart. Consequences:

  • No way to refresh a widget — the data only exists at construction time.
  • No way to test data logic independently of the Vaadin component tree.
  • No place to hang a date range, a filter, or a real backend later.

Proposal

Add a small service layer between views and charts, e.g.:

  • A ChartSeries / ChartDataSet record holding series name, values and category labels.
  • A ChartDataService interface (Spring bean) with methods like revenueByMonth(...), revenueByRegion(...).
  • A dummy in-memory implementation that returns today's hardcoded numbers, so nothing changes visually.
  • Widgets pull from the service instead of holding literals.

Keep it deliberately thin — the point is the seam, not a persistence layer.

Why

Prerequisite for live refresh, the global filter bar, and per-widget refresh actions. All three need "ask for data again with different parameters", which is impossible while the data is a literal in a constructor.

Acceptance criteria

  • No chart data literals left in views/.
  • Data service is unit-testable without a Vaadin UI, with at least one test.
  • Dashboard renders identically to before.
  • ./mvnw test green.

Scope

Small to medium. Best done right after the dashboard merge, while there is only one set of chart factories to migrate.

## Problem Chart data is written as literals inline in the views: ```java lineChart.setData(getTranslation("chart.revenueSeries"), List.of(30.0, 40.0, 35.0, 50.0, 49.0, 60.0), months); ``` The same list appears in `DashboardView` and `GridStackView`, for both the line and the bar chart. Consequences: - No way to refresh a widget — the data only exists at construction time. - No way to test data logic independently of the Vaadin component tree. - No place to hang a date range, a filter, or a real backend later. ## Proposal Add a small service layer between views and charts, e.g.: - A `ChartSeries` / `ChartDataSet` record holding series name, values and category labels. - A `ChartDataService` interface (Spring bean) with methods like `revenueByMonth(...)`, `revenueByRegion(...)`. - A dummy in-memory implementation that returns today's hardcoded numbers, so nothing changes visually. - Widgets pull from the service instead of holding literals. Keep it deliberately thin — the point is the seam, not a persistence layer. ## Why Prerequisite for live refresh, the global filter bar, and per-widget refresh actions. All three need "ask for data again with different parameters", which is impossible while the data is a literal in a constructor. ## Acceptance criteria - No chart data literals left in `views/`. - Data service is unit-testable without a Vaadin UI, with at least one test. - Dashboard renders identically to before. - `./mvnw test` green. ## Scope Small to medium. Best done right after the dashboard merge, while there is only one set of chart factories to migrate.
claude-bot added the enhancement label 2026-07-28 16:53:22 +00:00
pitfriedrich added the ai-ready label 2026-07-28 17:37:40 +00:00
claude-bot added ai-wip and removed ai-ready labels 2026-07-28 18:08:02 +00:00
Author
Collaborator

PR: #34

Neues Package com.example.data mit ChartSeries / KpiData (Records), ChartDataService und einer In-Memory-Implementierung, die genau die bisherigen Zahlen liefert. DashboardView bekommt den Service per Constructor-Injection; die KPI-Kacheln werden aus kpis() gelegt, die Grid-IDs (kpi-revenue …) kommen aus den Daten und bleiben unverändert, gespeicherte Layouts passen also weiterhin.

Design-Entscheidung: Die Records tragen Übersetzungs-Keys (month.jan, kpi.revenueTotal), keinen fertigen Text. Labels sind locale-abhängig und brauchen zum Auflösen eine UI — genau das hätte die Testbarkeit ohne Vaadin (Akzeptanzkriterium) kaputtgemacht. Die View löst die Keys gegen das Bundle auf.

Tests: neuer InMemoryChartDataServiceTest (reines JUnit, kein Spring-Context, keine UI), DashboardViewTest unverändert grün.

Hinweis: DashboardChartPlaywrightTest.dataUpdate_keepsTheRenderedSvgInPlace war bereits auf main rot (mit gestashten Änderungen verifiziert) — seit den KPI-Kacheln ist das erste apex-chart im DOM eine Sparkline ohne xaxis.categories, dadurch war der Achsen-Patch ein struktureller Update und hat das SVG zu Recht neu gezeichnet. Der Test zielt jetzt auf ein Achsen-Chart; Produktionscode dafür unverändert. ./mvnw test ist grün.

PR: https://gitea.pitfriedrich.net/pitfriedrich/chart-app/pulls/34 Neues Package `com.example.data` mit `ChartSeries` / `KpiData` (Records), `ChartDataService` und einer In-Memory-Implementierung, die genau die bisherigen Zahlen liefert. `DashboardView` bekommt den Service per Constructor-Injection; die KPI-Kacheln werden aus `kpis()` gelegt, die Grid-IDs (`kpi-revenue` …) kommen aus den Daten und bleiben unverändert, gespeicherte Layouts passen also weiterhin. Design-Entscheidung: Die Records tragen **Übersetzungs-Keys** (`month.jan`, `kpi.revenueTotal`), keinen fertigen Text. Labels sind locale-abhängig und brauchen zum Auflösen eine `UI` — genau das hätte die Testbarkeit ohne Vaadin (Akzeptanzkriterium) kaputtgemacht. Die View löst die Keys gegen das Bundle auf. Tests: neuer `InMemoryChartDataServiceTest` (reines JUnit, kein Spring-Context, keine UI), `DashboardViewTest` unverändert grün. Hinweis: `DashboardChartPlaywrightTest.dataUpdate_keepsTheRenderedSvgInPlace` war bereits auf `main` rot (mit gestashten Änderungen verifiziert) — seit den KPI-Kacheln ist das erste `apex-chart` im DOM eine Sparkline ohne `xaxis.categories`, dadurch war der Achsen-Patch ein struktureller Update und hat das SVG zu Recht neu gezeichnet. Der Test zielt jetzt auf ein Achsen-Chart; Produktionscode dafür unverändert. `./mvnw test` ist grün.
claude-bot added ai-review and removed ai-wip labels 2026-07-28 18:19:58 +00:00
Sign in to join this conversation.