From 879435c8d96b42015a81ab094767178aac650b26 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 6 Apr 2026 13:17:08 +0200 Subject: [PATCH] feat(search): wrap search response in { documents, total } envelope Co-Authored-By: Claude Sonnet 4.6 --- .../controller/DocumentController.java | 6 ++++-- .../familienarchiv/dto/DocumentSearchResult.java | 11 +++++++++++ .../controller/DocumentControllerTest.java | 12 ++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/dto/DocumentSearchResult.java diff --git a/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java b/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java index 57a0f437..b7834937 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java @@ -12,6 +12,7 @@ import java.util.UUID; import io.swagger.v3.oas.annotations.Parameter; +import org.raddatz.familienarchiv.dto.DocumentSearchResult; import org.raddatz.familienarchiv.dto.DocumentUpdateDTO; import org.raddatz.familienarchiv.dto.DocumentVersionSummary; import org.raddatz.familienarchiv.dto.IncompleteDocumentDTO; @@ -187,7 +188,7 @@ public class DocumentController { } @GetMapping("/search") - public ResponseEntity> search( + public ResponseEntity search( @RequestParam(required = false) String q, @RequestParam(required = false) LocalDate from, @RequestParam(required = false) LocalDate to, @@ -198,7 +199,8 @@ public class DocumentController { @Parameter(description = "Filter by document status") @RequestParam(required = false) DocumentStatus status, @Parameter(description = "Sort field") @RequestParam(required = false) DocumentSort sort, @Parameter(description = "Sort direction: ASC or DESC") @RequestParam(required = false, defaultValue = "DESC") String dir) { - return ResponseEntity.ok(documentService.searchDocuments(q, from, to, senderId, receiverId, tags, tagQ, status, sort, dir)); + List results = documentService.searchDocuments(q, from, to, senderId, receiverId, tags, tagQ, status, sort, dir); + return ResponseEntity.ok(DocumentSearchResult.of(results)); } // --- VERSIONS --- diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dto/DocumentSearchResult.java b/backend/src/main/java/org/raddatz/familienarchiv/dto/DocumentSearchResult.java new file mode 100644 index 00000000..9ac03cca --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/dto/DocumentSearchResult.java @@ -0,0 +1,11 @@ +package org.raddatz.familienarchiv.dto; + +import org.raddatz.familienarchiv.model.Document; + +import java.util.List; + +public record DocumentSearchResult(List documents, long total) { + public static DocumentSearchResult of(List documents) { + return new DocumentSearchResult(documents, documents.size()); + } +} diff --git a/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java index 50c31adb..063dfa0a 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java @@ -91,6 +91,18 @@ class DocumentControllerTest { .andExpect(status().isBadRequest()); } + @Test + @WithMockUser + void search_responseContainsTotalCount() throws Exception { + when(documentService.searchDocuments(any(), any(), any(), any(), any(), any(), any(), any(), any(), any())) + .thenReturn(Collections.emptyList()); + + mockMvc.perform(get("/api/documents/search")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.total").value(0)) + .andExpect(jsonPath("$.documents").isArray()); + } + // ─── POST /api/documents ───────────────────────────────────────────────── @Test