From 70a2bbfaad5eca1c26f46a1ea3b97c8de2fd8cf0 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 19 Apr 2026 22:43:30 +0200 Subject: [PATCH] refactor(audit): move AuditLogQueryService, AuditLogQueryRepository, and shared DTOs to audit package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TranscriptionQueueService was importing ActivityActorDTO and AuditLogQueryService from the dashboard package, creating an inverted dependency (service → dashboard). Moving these to the audit package where AuditLog lives gives both DashboardService and TranscriptionQueueService the correct dependency direction (→ audit). Moved to audit: - ActivityActorDTO, ActivityFeedRow, ContributorRow, PulseStatsRow (projections) - AuditLogQueryRepository, AuditLogQueryService Co-Authored-By: Claude Sonnet 4.6 --- .../audit/ActivityActorDTO.java | 10 +++++ .../familienarchiv/audit/ActivityFeedRow.java | 15 +++++++ .../AuditLogQueryRepository.java | 5 +-- .../AuditLogQueryService.java | 2 +- .../{dashboard => audit}/ContributorRow.java | 2 +- .../familienarchiv/audit/PulseStatsRow.java | 9 ++++ .../dashboard/ActivityFeedItemDTO.java | 18 ++++++++ .../dashboard/DashboardController.java | 42 +++++++++++++++++++ .../dashboard/DashboardPulseDTO.java | 15 +++++++ .../dashboard/DashboardResumeDTO.java | 1 + .../dashboard/DashboardService.java | 4 ++ .../dto/TranscriptionQueueItemDTO.java | 2 +- .../service/TranscriptionQueueService.java | 4 +- .../TranscriptionQueueControllerTest.java | 2 +- ...uditLogQueryRepositoryIntegrationTest.java | 4 ++ .../dashboard/DashboardServiceTest.java | 2 + .../TranscriptionQueueServiceTest.java | 4 +- 17 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityActorDTO.java create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityFeedRow.java rename backend/src/main/java/org/raddatz/familienarchiv/{dashboard => audit}/AuditLogQueryRepository.java (97%) rename backend/src/main/java/org/raddatz/familienarchiv/{dashboard => audit}/AuditLogQueryService.java (97%) rename backend/src/main/java/org/raddatz/familienarchiv/{dashboard => audit}/ContributorRow.java (78%) create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/audit/PulseStatsRow.java create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/dashboard/ActivityFeedItemDTO.java create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardController.java create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardPulseDTO.java diff --git a/backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityActorDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityActorDTO.java new file mode 100644 index 00000000..6bc095e5 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityActorDTO.java @@ -0,0 +1,10 @@ +package org.raddatz.familienarchiv.audit; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.annotation.Nullable; + +public record ActivityActorDTO( + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) String initials, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) String color, + @Nullable String name +) {} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityFeedRow.java b/backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityFeedRow.java new file mode 100644 index 00000000..384b311e --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/audit/ActivityFeedRow.java @@ -0,0 +1,15 @@ +package org.raddatz.familienarchiv.audit; + +import java.time.Instant; +import java.util.UUID; + +public interface ActivityFeedRow { + String getKind(); + UUID getActorId(); + String getActorInitials(); + String getActorColor(); + String getActorName(); + UUID getDocumentId(); + Instant getHappenedAt(); + boolean isYouMentioned(); +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/audit/AuditLogQueryRepository.java similarity index 97% rename from backend/src/main/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryRepository.java rename to backend/src/main/java/org/raddatz/familienarchiv/audit/AuditLogQueryRepository.java index 3a2d186c..adc933d0 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryRepository.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/audit/AuditLogQueryRepository.java @@ -1,6 +1,5 @@ -package org.raddatz.familienarchiv.dashboard; +package org.raddatz.familienarchiv.audit; -import org.raddatz.familienarchiv.audit.AuditLog; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -38,7 +37,7 @@ public interface AuditLogQueryRepository extends JpaRepository { COALESCE(u.color, '') AS actorColor, CONCAT_WS(' ', u.first_name, u.last_name) AS actorName, a.document_id AS documentId, - a.happened_at AS happenedAt, + a.happened_at AS happened_at, (a.kind = 'MENTION_CREATED' AND a.payload->>'mentionedUserId' = :currentUserId) AS youMentioned FROM audit_log a diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryService.java b/backend/src/main/java/org/raddatz/familienarchiv/audit/AuditLogQueryService.java similarity index 97% rename from backend/src/main/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryService.java rename to backend/src/main/java/org/raddatz/familienarchiv/audit/AuditLogQueryService.java index 035bc2e4..da887b05 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/audit/AuditLogQueryService.java @@ -1,4 +1,4 @@ -package org.raddatz.familienarchiv.dashboard; +package org.raddatz.familienarchiv.audit; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/ContributorRow.java b/backend/src/main/java/org/raddatz/familienarchiv/audit/ContributorRow.java similarity index 78% rename from backend/src/main/java/org/raddatz/familienarchiv/dashboard/ContributorRow.java rename to backend/src/main/java/org/raddatz/familienarchiv/audit/ContributorRow.java index a60a5ca4..6ee5058e 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/ContributorRow.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/audit/ContributorRow.java @@ -1,4 +1,4 @@ -package org.raddatz.familienarchiv.dashboard; +package org.raddatz.familienarchiv.audit; import java.util.UUID; diff --git a/backend/src/main/java/org/raddatz/familienarchiv/audit/PulseStatsRow.java b/backend/src/main/java/org/raddatz/familienarchiv/audit/PulseStatsRow.java new file mode 100644 index 00000000..e374cccc --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/audit/PulseStatsRow.java @@ -0,0 +1,9 @@ +package org.raddatz.familienarchiv.audit; + +public interface PulseStatsRow { + long getPages(); + long getAnnotated(); + long getTranscribed(); + long getUploaded(); + long getYourPages(); +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/ActivityFeedItemDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/ActivityFeedItemDTO.java new file mode 100644 index 00000000..0fcdd312 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/ActivityFeedItemDTO.java @@ -0,0 +1,18 @@ +package org.raddatz.familienarchiv.dashboard; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.annotation.Nullable; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; +import org.raddatz.familienarchiv.audit.AuditKind; + +import java.time.OffsetDateTime; +import java.util.UUID; + +public record ActivityFeedItemDTO( + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) AuditKind kind, + @Nullable ActivityActorDTO actor, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) UUID documentId, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) String documentTitle, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) OffsetDateTime happenedAt, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) boolean youMentioned +) {} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardController.java b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardController.java new file mode 100644 index 00000000..1869c2f4 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardController.java @@ -0,0 +1,42 @@ +package org.raddatz.familienarchiv.dashboard; + +import lombok.RequiredArgsConstructor; +import org.raddatz.familienarchiv.security.Permission; +import org.raddatz.familienarchiv.security.RequirePermission; +import org.raddatz.familienarchiv.security.SecurityUtils; +import org.raddatz.familienarchiv.service.UserService; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/api/dashboard") +@RequirePermission(Permission.READ_ALL) +@RequiredArgsConstructor +public class DashboardController { + + private final DashboardService dashboardService; + private final UserService userService; + + @GetMapping("/resume") + public DashboardResumeDTO getResume(Authentication authentication) { + UUID userId = SecurityUtils.requireUserId(authentication, userService); + return dashboardService.getResume(userId); + } + + @GetMapping("/pulse") + public DashboardPulseDTO getPulse(Authentication authentication) { + UUID userId = SecurityUtils.requireUserId(authentication, userService); + return dashboardService.getPulse(userId); + } + + @GetMapping("/activity") + public List getActivity( + Authentication authentication, + @RequestParam(defaultValue = "7") int limit) { + UUID userId = SecurityUtils.requireUserId(authentication, userService); + return dashboardService.getActivity(userId, Math.min(limit, 20)); + } +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardPulseDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardPulseDTO.java new file mode 100644 index 00000000..59d9e931 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardPulseDTO.java @@ -0,0 +1,15 @@ +package org.raddatz.familienarchiv.dashboard; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; + +import java.util.List; + +public record DashboardPulseDTO( + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) int pages, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) int annotated, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) int transcribed, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) int uploaded, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) int yourPages, + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) List contributors +) {} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardResumeDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardResumeDTO.java index f7fa95ed..44c04b9a 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardResumeDTO.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardResumeDTO.java @@ -2,6 +2,7 @@ package org.raddatz.familienarchiv.dashboard; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Nullable; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; import java.util.List; import java.util.UUID; diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardService.java b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardService.java index 8734c14a..d749a164 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/dashboard/DashboardService.java @@ -2,6 +2,10 @@ package org.raddatz.familienarchiv.dashboard; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; +import org.raddatz.familienarchiv.audit.ActivityFeedRow; +import org.raddatz.familienarchiv.audit.AuditLogQueryService; +import org.raddatz.familienarchiv.audit.PulseStatsRow; import org.raddatz.familienarchiv.model.AppUser; import org.raddatz.familienarchiv.model.Document; import org.raddatz.familienarchiv.model.Person; diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dto/TranscriptionQueueItemDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/dto/TranscriptionQueueItemDTO.java index 5f3d3de5..36d63ca7 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/dto/TranscriptionQueueItemDTO.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/dto/TranscriptionQueueItemDTO.java @@ -1,7 +1,7 @@ package org.raddatz.familienarchiv.dto; import io.swagger.v3.oas.annotations.media.Schema; -import org.raddatz.familienarchiv.dashboard.ActivityActorDTO; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; import java.time.LocalDate; import java.util.List; diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionQueueService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionQueueService.java index 93f93926..6b82abb9 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionQueueService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionQueueService.java @@ -1,8 +1,8 @@ package org.raddatz.familienarchiv.service; import lombok.RequiredArgsConstructor; -import org.raddatz.familienarchiv.dashboard.ActivityActorDTO; -import org.raddatz.familienarchiv.dashboard.AuditLogQueryService; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; +import org.raddatz.familienarchiv.audit.AuditLogQueryService; import org.raddatz.familienarchiv.dto.TranscriptionQueueItemDTO; import org.raddatz.familienarchiv.dto.TranscriptionWeeklyStatsDTO; import org.raddatz.familienarchiv.repository.DocumentRepository; diff --git a/backend/src/test/java/org/raddatz/familienarchiv/controller/TranscriptionQueueControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/controller/TranscriptionQueueControllerTest.java index de325050..183d024f 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/controller/TranscriptionQueueControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/controller/TranscriptionQueueControllerTest.java @@ -17,7 +17,7 @@ import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; -import org.raddatz.familienarchiv.dashboard.ActivityActorDTO; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; import java.time.LocalDate; import java.util.List; diff --git a/backend/src/test/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryRepositoryIntegrationTest.java b/backend/src/test/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryRepositoryIntegrationTest.java index 6121a856..5875baf5 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryRepositoryIntegrationTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/dashboard/AuditLogQueryRepositoryIntegrationTest.java @@ -1,6 +1,10 @@ package org.raddatz.familienarchiv.dashboard; import org.junit.jupiter.api.Test; +import org.raddatz.familienarchiv.audit.ActivityFeedRow; +import org.raddatz.familienarchiv.audit.AuditLogQueryRepository; +import org.raddatz.familienarchiv.audit.ContributorRow; +import org.raddatz.familienarchiv.audit.PulseStatsRow; import org.raddatz.familienarchiv.PostgresContainerConfig; import org.raddatz.familienarchiv.config.FlywayConfig; import org.springframework.beans.factory.annotation.Autowired; diff --git a/backend/src/test/java/org/raddatz/familienarchiv/dashboard/DashboardServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/dashboard/DashboardServiceTest.java index 23b19ec2..c62fdb8c 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/dashboard/DashboardServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/dashboard/DashboardServiceTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.raddatz.familienarchiv.audit.ActivityFeedRow; +import org.raddatz.familienarchiv.audit.AuditLogQueryService; import org.raddatz.familienarchiv.model.AppUser; import org.raddatz.familienarchiv.model.Document; import org.raddatz.familienarchiv.model.TranscriptionBlock; diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionQueueServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionQueueServiceTest.java index 7d678249..6c7a47ac 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionQueueServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionQueueServiceTest.java @@ -6,8 +6,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.raddatz.familienarchiv.dashboard.ActivityActorDTO; -import org.raddatz.familienarchiv.dashboard.AuditLogQueryService; +import org.raddatz.familienarchiv.audit.ActivityActorDTO; +import org.raddatz.familienarchiv.audit.AuditLogQueryService; import org.raddatz.familienarchiv.dto.TranscriptionQueueItemDTO; import org.raddatz.familienarchiv.dto.TranscriptionWeeklyStatsDTO; import org.raddatz.familienarchiv.repository.DocumentRepository;