feat(dashboard): add metering data overview endpoint for user dashboard

This commit is contained in:
Bernhard Müller 2026-07-23 15:02:23 +02:00
parent 5ff22e53bd
commit 765cbb0ec7
3 changed files with 90 additions and 1 deletions

View File

@ -4,12 +4,15 @@ import at.mueller.eeg.backend.common.security.CurrentUserId;
import at.mueller.eeg.backend.dashboard.api.dto.DashboardStatsDto;
import at.mueller.eeg.backend.dashboard.service.DashboardService;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.UUID;
@RestController
@ -30,4 +33,14 @@ public class DashboardController {
public ResponseEntity<DashboardStatsDto.UserStats> getUserDashboard(@CurrentUserId String userId) {
return ResponseEntity.ok(dashboardService.getUserStats(UUID.fromString(userId)));
}
@GetMapping("/user/metering-data/overview")
@PreAuthorize("hasRole('MEMBER')")
public ResponseEntity<DashboardStatsDto.MeteringDataOverview> getMeteringDataOverview(
@CurrentUserId String userId,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime from,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime to) {
return ResponseEntity.ok(dashboardService.getMeteringDataOverview(
UUID.fromString(userId), from, to));
}
}

View File

@ -1,5 +1,12 @@
package at.mueller.eeg.backend.dashboard.api.dto;
import at.mueller.eeg.backend.community.domain.PointType;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public interface DashboardStatsDto {
record AdminStats(
long totalCommunities,
@ -13,4 +20,21 @@ public interface DashboardStatsDto {
long activeMemberships,
long pendingMemberships
) {}
record MeteringDataOverview(
List<MeteringPointSummary> meteringPoints,
List<TimeSeriesEntry> timeSeries
) {}
record MeteringPointSummary(
UUID id,
String atNumber,
PointType type,
double totalKwh
) {}
record TimeSeriesEntry(
LocalDateTime timestamp,
Map<String, Double> values
) {}
}

View File

@ -1,7 +1,10 @@
package at.mueller.eeg.backend.dashboard.service;
import at.mueller.eeg.backend.community.domain.MeteringData;
import at.mueller.eeg.backend.community.domain.MeteringPoint;
import at.mueller.eeg.backend.community.domain.MembershipStatus;
import at.mueller.eeg.backend.community.repository.EnergyCommunityRepository;
import at.mueller.eeg.backend.community.repository.MeteringDataRepository;
import at.mueller.eeg.backend.community.repository.MembershipRepository;
import at.mueller.eeg.backend.community.repository.MeteringPointRepository;
import at.mueller.eeg.backend.dashboard.api.dto.DashboardStatsDto;
@ -11,7 +14,12 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@ -22,6 +30,7 @@ public class DashboardService {
private final UserRepository userRepository;
private final MembershipRepository membershipRepository;
private final MeteringPointRepository meteringPointRepository;
private final MeteringDataRepository meteringDataRepository;
public DashboardStatsDto.AdminStats getAdminStats() {
long communities = energyCommunityRepository.count();
@ -39,4 +48,47 @@ public class DashboardService {
return new DashboardStatsDto.UserStats(meteringPoints, activeMemberships, pendingMemberships);
}
public DashboardStatsDto.MeteringDataOverview getMeteringDataOverview(UUID userId, LocalDateTime from, LocalDateTime to) {
List<MeteringPoint> meteringPoints = meteringPointRepository.findAllByUserId(userId);
List<DashboardStatsDto.MeteringPointSummary> summaries = new ArrayList<>();
Map<String, Map<LocalDate, Double>> dailyData = new LinkedHashMap<>();
for (MeteringPoint mp : meteringPoints) {
List<MeteringData> data = meteringDataRepository.findByMeteringPointIdAndIntervalStartBetween(mp.getId(), from, to);
double totalKwh = data.stream().mapToDouble(MeteringData::getKwh).sum();
summaries.add(new DashboardStatsDto.MeteringPointSummary(
mp.getId(),
mp.getAtNumber(),
mp.getType(),
totalKwh
));
for (MeteringData d : data) {
LocalDate day = d.getIntervalStart().toLocalDate();
dailyData.computeIfAbsent(mp.getAtNumber(), k -> new LinkedHashMap<>())
.merge(day, d.getKwh(), Double::sum);
}
}
Set<LocalDate> allDays = dailyData.values().stream()
.flatMap(m -> m.keySet().stream())
.collect(Collectors.toCollection(TreeSet::new));
List<DashboardStatsDto.TimeSeriesEntry> timeSeries = allDays.stream()
.map(day -> {
Map<String, Double> values = new LinkedHashMap<>();
for (MeteringPoint mp : meteringPoints) {
values.put(mp.getAtNumber(),
dailyData.getOrDefault(mp.getAtNumber(), Collections.emptyMap())
.getOrDefault(day, 0.0));
}
return new DashboardStatsDto.TimeSeriesEntry(day.atStartOfDay(), values);
})
.toList();
return new DashboardStatsDto.MeteringDataOverview(summaries, timeSeries);
}
}