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 d25cf03c..73c60e43 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java @@ -669,6 +669,18 @@ public class DocumentService { public DocumentSearchResult searchDocuments(String text, LocalDate from, LocalDate to, UUID sender, UUID receiver, List tags, String tagQ, DocumentStatus status, DocumentSort sort, String dir, TagOperator tagOperator, boolean undated, Pageable pageable) { boolean hasText = StringUtils.hasText(text); + // Pure-text RELEVANCE: push pagination + ts_rank ordering into SQL — skip + // findAllMatchingIdsByFts entirely (ADR-008). This must run BEFORE any + // findAllMatchingIdsByFts call so the fast path is preserved. An active undated + // filter must NOT take this path: it bypasses buildSearchSpec, so the + // undatedOnly predicate would be silently dropped. By definition this path has + // no date/sender/receiver/tag/status filters, and undated documents are valid + // FTS hits already folded into the ranked page, so there is no separate undated + // count to report here. + if (!undated && isPureTextRelevance(hasText, sort, from, to, sender, receiver, tags, tagQ, status)) { + return relevanceSortedPageFromSql(text, pageable); + } + List rankedIds = null; if (hasText) { rankedIds = documentRepository.findAllMatchingIdsByFts(text); @@ -706,13 +718,8 @@ public class DocumentService { List tags, String tagQ, DocumentStatus status, DocumentSort sort, String dir, TagOperator tagOperator, boolean undated, Pageable pageable) { - // Pure-text RELEVANCE: push pagination into SQL — skip findAllMatchingIdsByFts entirely (ADR-008). - // An active undated filter must NOT take this path: it bypasses buildSearchSpec, so the - // undatedOnly predicate would be silently dropped. - if (!undated && isPureTextRelevance(hasText, sort, from, to, sender, receiver, tags, tagQ, status)) { - return relevanceSortedPageFromSql(text, pageable); - } - + // The pure-text RELEVANCE fast path is handled by the caller (searchDocuments) + // before findAllMatchingIdsByFts runs, so it never reaches here (ADR-008). Specification spec = buildSearchSpec( hasText, rankedIds, from, to, sender, receiver, tags, tagQ, status, tagOperator, undated);