fix(dashboard): bulk-load document titles in getActivity to avoid N+1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-19 21:24:39 +02:00
parent 09a8081e35
commit 3f773cd9c3
3 changed files with 49 additions and 7 deletions

View File

@@ -124,12 +124,11 @@ public class DashboardService {
.toList();
Map<UUID, String> titleCache = new HashMap<>();
for (UUID docId : docIds) {
try {
titleCache.put(docId, documentService.getDocumentById(docId).getTitle());
} catch (Exception e) {
titleCache.put(docId, "");
}
try {
documentService.getDocumentsByIds(docIds)
.forEach(d -> titleCache.put(d.getId(), d.getTitle()));
} catch (Exception e) {
log.warn("Activity: failed to bulk-load document titles", e);
}
return rows.stream().map(row -> {

View File

@@ -484,6 +484,10 @@ public class DocumentService {
return doc;
}
public List<Document> getDocumentsByIds(List<UUID> ids) {
return documentRepository.findAllById(ids);
}
public List<Document> getDocumentsWithoutVersions() {
return documentRepository.findDocumentsWithoutVersions();
}

View File

@@ -12,13 +12,16 @@ import org.raddatz.familienarchiv.service.DocumentService;
import org.raddatz.familienarchiv.service.TranscriptionService;
import org.raddatz.familienarchiv.service.UserService;
import java.time.LocalDateTime;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@@ -65,4 +68,40 @@ class DashboardServiceTest {
assertThat(result.collaborators()).hasSize(1);
assertThat(result.collaborators().get(0).name()).isEqualTo("Schmidt");
}
// ─── getActivity bulk-load ────────────────────────────────────────────────
@Test
void getActivity_loadsDocumentTitles_withoutPerRowLookup() {
UUID userId = UUID.randomUUID();
UUID docId = UUID.randomUUID();
ActivityFeedRow row = mockFeedRow(docId, "ANNOTATION_CREATED");
when(auditLogQueryService.findActivityFeed(userId, 5)).thenReturn(List.of(row, row));
Document doc = Document.builder()
.id(docId).title("Familienbrief").originalFilename("f.pdf")
.receivers(new HashSet<>())
.build();
when(documentService.getDocumentsByIds(List.of(docId))).thenReturn(List.of(doc));
List<ActivityFeedItemDTO> items = dashboardService.getActivity(userId, 5);
assertThat(items).hasSize(2);
assertThat(items.get(0).documentTitle()).isEqualTo("Familienbrief");
verify(documentService, never()).getDocumentById(docId);
}
private ActivityFeedRow mockFeedRow(UUID docId, String kind) {
return new ActivityFeedRow() {
public String getKind() { return kind; }
public UUID getActorId() { return null; }
public String getActorInitials() { return ""; }
public String getActorColor() { return ""; }
public String getActorName() { return ""; }
public UUID getDocumentId() { return docId; }
public Instant getHappenedAt() { return Instant.now(); }
public boolean isYouMentioned() { return false; }
};
}
}