Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a configurable “widgets” system for the statistics dashboard, including persistence for widget layout/configuration, a materialized-view-backed statistics aggregation layer, and a set of widget data providers exposed via new REST endpoints.
Changes:
- Adds
widgetpersistence (Liquibase changelog + JPA entity/repository/service/controller) and layout validation. - Adds
mv_daily_category_statmaterialized view + refresh function/triggers to pre-aggregate daily stats. - Implements multiple widget data providers and supporting DTO/projection payload types.
Reviewed changes
Copilot reviewed 99 out of 99 changed files in this pull request and generated 21 comments.
Show a summary per file
| File | Description |
|---|---|
| backend/exence/src/main/resources/db/changelog/v1.1.0/sql/create-trigger-on-transaction.sql | Trigger to refresh MV on transaction changes |
| backend/exence/src/main/resources/db/changelog/v1.1.0/sql/create-trigger-on-category.sql | Trigger to refresh MV on category updates |
| backend/exence/src/main/resources/db/changelog/v1.1.0/sql/create-refresh-function.sql | PL/pgSQL refresh function for MV |
| backend/exence/src/main/resources/db/changelog/v1.1.0/sql/create-mv-daily-category-stat.sql | Defines the daily category stats MV |
| backend/exence/src/main/resources/db/changelog/v1.1.0/create-widget-table.yaml | Liquibase widget table + sequence + FK/index |
| backend/exence/src/main/resources/db/changelog/v1.1.0/create-mv-refresh-trigger.yaml | Liquibase to install MV refresh function + triggers |
| backend/exence/src/main/resources/db/changelog/v1.1.0/create-mv-daily-category-stat.yaml | Liquibase to create MV + required indexes |
| backend/exence/src/main/resources/db/changelog/v1.1.0/changelog-v1.1.0.yaml | Includes new widget + MV changelogs |
| backend/exence/src/main/java/com/exence/finance/modules/transaction/repository/TransactionRepository.java | Adds scatter + boxplot chart queries |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/validators/WidgetLayoutValidator.java | Validates widget layout fields by widget type |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/validators/AtLeastOneNotEmptyValidator.java | Validates update-layout request has content |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/YearlySlopeProvider.java | Provider for yearly slope widget payload |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/WidgetDataProvider.java | Sealed provider SPI for widget data |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/WealthGrowthComboProvider.java | Provider for wealth growth combo series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/TransactionScatterProvider.java | Provider for transaction scatter series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/TransactionCountExpenseComboProvider.java | Provider for expense+count combo series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/StatCardProvider.java | (Placeholder) provider for stat card widgets |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/SpendingRadarProvider.java | Provider for spending radar distribution |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/SpendingHeatmapProvider.java | Provider for spending heatmap series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/SavingsGaugeProvider.java | Provider for savings-rate gauge payload |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/SankeyProvider.java | Provider for category sankey payload |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/ProviderHelper.java | Shared helpers for provider computations/mapping |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/MonthlyPeakPolarProvider.java | Provider for monthly peak polar distribution |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/MonthlyCategoryRadarProvider.java | Provider for monthly category radar series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/MonthlyBoxplotProvider.java | Provider for monthly expense boxplot |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/MonthlyBalanceColumnProvider.java | Provider for monthly balance column series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/IncomeTrendProvider.java | Provider for income daily trend series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/IncomePieProvider.java | Provider for income pie distribution |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/IncomeExpenseColumnProvider.java | Provider for income vs expense columns |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/IncomeCategoryTrendProvider.java | Provider for income category trend series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/ExpenseTrendProvider.java | Provider for expense daily trend series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/ExpenseSavingsComboProvider.java | Provider for expense + savings rate combo |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/ExpensePieProvider.java | Provider for expense pie distribution |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/ExpenseCategoryTrendProvider.java | Provider for expense category trend series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/ExpenseCategoryColumnProvider.java | Provider for expense category column series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/CategoryTreemapProvider.java | Provider for income/expense treemap |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/CategoryBubbleProvider.java | Provider for category bubble payload |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/CategoryBoxplotProvider.java | Provider for category boxplot payload |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/CategoryAvgPolarProvider.java | Provider for category average polar distribution |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/BalanceYearComparisonProvider.java | Provider for balance year comparison series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/provider/BalanceTrendProvider.java | Provider for cumulative balance trend series |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/impl/WidgetServiceImpl.java | Widget layout CRUD + data dispatch to providers |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/service/WidgetService.java | Widget service interface |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/repository/WidgetRepository.java | Widget repository queries |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/repository/StatisticsRepository.java | MV-backed statistics queries + projections |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/mapper/WidgetMapper.java | MapStruct mapping between entity/DTOs |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/entity/Widget.java | Widget JPA entity with JSON settings |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/entity/DailyCategoryStatId.java | Composite id for MV entity |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/entity/DailyCategoryStat.java | Read-only MV entity mapping |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/response/WidgetLayoutResponse.java | API response for widget layout |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/response/WidgetDataResponse.java | API response for widget data |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/response/StatCardWidgetDTO.java | API DTO for stat card widget layout |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/response/ChartWidgetDTO.java | API DTO for chart widget layout |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/base/MonthlyProjection.java | Base projection for month bucketing |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/base/CategoryProjection.java | Base projection for category name/color |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/YearlyCategoryProjection.java | Projection for yearly totals by category |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/TypeAmountProjection.java | Projection for sums by transaction type |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/ScatterProjection.java | Projection for scatter chart points |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/MonthlyTrendProjection.java | Projection for monthly type trends |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/MonthlyIncomeExpenseProjection.java | Projection for monthly income/expense(+count) |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/MonthlyCategoryProjection.java | Projection for monthly category totals |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/MonthlyBalanceProjection.java | Projection for monthly balance totals |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/HeatmapProjection.java | Projection for heatmap day/week totals |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/DailyTrendProjection.java | Projection for daily totals |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/CategoryStatsProjection.java | Projection for amount/count/avg by category |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/CategoryFlowProjection.java | Projection for totals by type+category |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/CategoryAverageProjection.java | Projection for avg by category |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/projection/CategoryAmountProjection.java | Projection for totals by category |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/WidgetDataPayload.java | Sealed payload supertype |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/Trend.java | Trend enum for stat card payload |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/StatCardPayload.java | Stat card payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/SlopePayload.java | Slope chart payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/SlopeItem.java | Slope chart item structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/SeriesPayload.java | Series payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/SeriesItem.java | Series item structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/SankeyPayload.java | Sankey payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/SankeyLink.java | Sankey link structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/GaugePayload.java | Gauge payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/DistributionPayload.java | Distribution payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/DistributionItem.java | Distribution item structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/DataPoint.java | Generic chart datapoint structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/BubbleSeries.java | Bubble series structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/BubblePoint.java | Bubble point structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/BubblePayload.java | Bubble payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/BoxplotPoint.java | Boxplot point structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/payload/BoxplotPayload.java | Boxplot payload structure |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/WidgetType.java | Enumerates widget types and grouping helpers |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/WidgetSetting.java | JSON-mapped widget settings keys |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/WidgetRequest.java | Provider request inputs (dates/settings) |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/WidgetDTO.java | Widget create DTO + layout validation hook |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/UpdateLayoutRequest.java | Layout update request DTO |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/Timeframe.java | Timeframe handling for widget queries |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/StatCardLayoutItem.java | Layout item DTO for stat cards |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/dto/ChartLayoutItem.java | Layout item DTO for charts |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/controller/impl/WidgetControllerImpl.java | REST endpoints for widgets |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/controller/WidgetController.java | Widget controller interface |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/annotations/ValidWidgetLayout.java | Bean validation annotation for widget DTO |
| backend/exence/src/main/java/com/exence/finance/modules/statistics/annotations/AtLeastOneNotEmpty.java | Bean validation annotation for update layout |
| backend/exence/src/main/java/com/exence/finance/common/util/DateUtils.java | Date helpers for chart bucketing/labels |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...ence/src/main/java/com/exence/finance/modules/statistics/dto/response/StatCardWidgetDTO.java
Outdated
Show resolved
Hide resolved
|
|
||
| return new SeriesPayload(List.of( | ||
| new SeriesItem("Income", "column", "todo: zold kene ide", incomePoints), | ||
| new SeriesItem("Expense", "column", "todo: piros kene ide", expensePoints))); | ||
| } |
There was a problem hiding this comment.
This provider returns placeholder strings ("todo: ...") in the color field for series items. If the API contract expects a valid color, this will break clients; return null or a valid color before merging.
...ava/com/exence/finance/modules/statistics/service/provider/ExpenseCategoryTrendProvider.java
Show resolved
Hide resolved
backend/exence/src/main/resources/db/changelog/v1.1.0/sql/create-refresh-function.sql
Outdated
Show resolved
Hide resolved
...ence/src/main/java/com/exence/finance/modules/statistics/service/impl/WidgetServiceImpl.java
Show resolved
Hide resolved
| public class DailyCategoryStatId implements Serializable { | ||
| private Long userId; | ||
| private Instant statDate; | ||
| private Long categoryId; | ||
| private TransactionType type; |
There was a problem hiding this comment.
@IdClass requires the id-class to expose key fields as public/protected fields or JavaBean properties. This class currently has only private fields and no accessors, which can break JPA provider mapping. Consider making fields public/protected, adding getters/setters (e.g., Lombok @DaTa), or switching to @Embeddable + @EmbeddedId.
| for (ChartLayoutItem item : request.charts()) { | ||
| Widget widget = existingWidgets.get(item.id()); | ||
| if (widget == null) { | ||
| throw new EntityNotFoundException("Widget not found: " + item.id()); | ||
| } |
There was a problem hiding this comment.
Similarly, the charts loop updates x/y without verifying the widget is actually a graph widget. Validate widget.getType().isGraph() before applying x/y to prevent invalid persisted layouts.
| @PathVariable Long widgetId, @RequestParam(required = false) Timeframe timeframe) { | ||
| return ResponseFactory.ok(widgetService.getWidgetData(widgetId, timeframe)); |
There was a problem hiding this comment.
The timeframe request param is bound directly to the Timeframe enum, so Spring will only accept values like ONE_WEEK, not the short codes (1W, YTD, etc.). If the API is meant to accept the codes, accept a String here and parse via Timeframe.fromCode(...), or register a Converter<String, Timeframe>.
| @PathVariable Long widgetId, @RequestParam(required = false) Timeframe timeframe) { | |
| return ResponseFactory.ok(widgetService.getWidgetData(widgetId, timeframe)); | |
| @PathVariable Long widgetId, @RequestParam(required = false) String timeframe) { | |
| Timeframe parsedTimeframe = timeframe != null ? Timeframe.fromCode(timeframe) : null; | |
| return ResponseFactory.ok(widgetService.getWidgetData(widgetId, parsedTimeframe)); |
|
|
||
| return new SeriesPayload(List.of( | ||
| new SeriesItem("Expense", "column", "todo: piros szin", expensePoints), | ||
| new SeriesItem("Savings Rate", "line", null, savingsRatePoints))); | ||
| } |
There was a problem hiding this comment.
This provider returns a placeholder string ("todo: ...") in the color field for a series item. If clients expect a real color value, this will break rendering; return null or a valid color.
| @Override | ||
| public StatCardPayload getData(WidgetRequest request) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
StatCardProvider#getData currently returns null, which will produce a null payload in the API response (or NPEs in callers/serializers) for EXAMPLE_STATCARD. Either implement a minimal payload or fail fast with an explicit exception until the stat card provider is implemented.
2979a27 to
fef8e64
Compare
dcb648f to
7e261b3
Compare
No description provided.