From d1c9881b67286b8516880ce2ebba5ab81100f73e Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 31 May 2026 12:42:14 +0200 Subject: [PATCH] refactor(document): compute hasTranscription only on the detail path (#697) Move the hasTranscription existence query out of the shared getDocumentById into a dedicated getDocumentDetail used solely by GET /api/documents/{id}. The flag is only consumed by the detail page, so the extra EXISTS query no longer runs for the many internal getDocumentById callers (e.g. the Geschichte resolve loop and the dashboard resume path). Behaviour of the detail endpoint is unchanged. Co-Authored-By: Claude Opus 4.8 --- .../document/DocumentController.java | 2 +- .../document/DocumentService.java | 12 ++++++++++++ .../document/DocumentServiceTest.java | 19 +++++++++++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentController.java b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentController.java index daaa96c5..b77b57b7 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentController.java @@ -138,7 +138,7 @@ public class DocumentController { // --- METADATA --- @GetMapping("/{id}") public Document getDocument(@PathVariable UUID id) { - return documentService.getDocumentById(id); + return documentService.getDocumentDetail(id); } @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java index 934f3417..93570e49 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java @@ -943,6 +943,18 @@ public class DocumentService { Document doc = documentRepository.findById(id) .orElseThrow(() -> DomainException.notFound(ErrorCode.DOCUMENT_NOT_FOUND, "Document not found: " + id)); tagService.resolveEffectiveColors(doc.getTags()); + return doc; + } + + /** + * Loads a document for the detail view, additionally flagging whether it has any + * transcription to read. Kept separate from {@link #getDocumentById} so the cheap + * existence query only runs for the single-document detail endpoint, not for the + * many internal callers that never read the flag. + */ + @Transactional(readOnly = true) + public Document getDocumentDetail(UUID id) { + Document doc = getDocumentById(id); doc.setHasTranscription(transcriptionBlockQueryService.hasBlocks(id)); return doc; } diff --git a/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java index 34b5ddf0..ccf162f9 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java @@ -119,23 +119,34 @@ class DocumentServiceTest { } @Test - void getDocumentById_setsHasTranscriptionTrue_whenBlocksExist() { + void getDocumentById_doesNotQueryTranscription() { + UUID id = UUID.randomUUID(); + Document doc = Document.builder().id(id).title("Test").build(); + when(documentRepository.findById(id)).thenReturn(Optional.of(doc)); + + documentService.getDocumentById(id); + + verifyNoInteractions(transcriptionBlockQueryService); + } + + @Test + void getDocumentDetail_setsHasTranscriptionTrue_whenBlocksExist() { UUID id = UUID.randomUUID(); Document doc = Document.builder().id(id).title("Test").build(); when(documentRepository.findById(id)).thenReturn(Optional.of(doc)); when(transcriptionBlockQueryService.hasBlocks(id)).thenReturn(true); - assertThat(documentService.getDocumentById(id).isHasTranscription()).isTrue(); + assertThat(documentService.getDocumentDetail(id).isHasTranscription()).isTrue(); } @Test - void getDocumentById_setsHasTranscriptionFalse_whenNoBlocksExist() { + void getDocumentDetail_setsHasTranscriptionFalse_whenNoBlocksExist() { UUID id = UUID.randomUUID(); Document doc = Document.builder().id(id).title("Test").build(); when(documentRepository.findById(id)).thenReturn(Optional.of(doc)); when(transcriptionBlockQueryService.hasBlocks(id)).thenReturn(false); - assertThat(documentService.getDocumentById(id).isHasTranscription()).isFalse(); + assertThat(documentService.getDocumentDetail(id).isHasTranscription()).isFalse(); } // ─── updateDocument ───────────────────────────────────────────────────────