From ca0cf4903ce98ef4c9e76776ad8174cf2484dfb4 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 16 Apr 2026 10:52:14 +0200 Subject: [PATCH] refactor(#240): remove needsExpert feature completely Drops the needsExpert / needs_expert flag end-to-end: DB migration (V37, never applied), Document entity field, PATCH endpoint, service method, DTO field, all three queue queries, ExpertBadge component, i18n key, generated API types, and test fixture. Co-Authored-By: Claude Sonnet 4.6 --- .../controller/DocumentController.java | 8 ------ .../dto/TranscriptionQueueItemDTO.java | 1 - .../familienarchiv/model/Document.java | 5 ---- .../repository/DocumentRepository.java | 16 +++++------- .../service/DocumentService.java | 7 ----- .../service/TranscriptionQueueService.java | 14 +++------- .../V37__add_needs_expert_to_documents.sql | 1 - frontend/messages/de.json | 1 - frontend/messages/en.json | 1 - frontend/messages/es.json | 1 - .../src/lib/components/ExpertBadge.svelte | 26 ------------------- .../lib/components/MissionControlStrip.svelte | 1 - .../src/lib/components/ReadyColumn.svelte | 1 - .../lib/components/SegmentationColumn.svelte | 9 +------ .../lib/components/TranscriptionColumn.svelte | 9 +------ frontend/src/lib/generated/api.ts | 2 -- .../routes/briefwechsel/page.svelte.spec.ts | 1 - 17 files changed, 13 insertions(+), 91 deletions(-) delete mode 100644 backend/src/main/resources/db/migration/V37__add_needs_expert_to_documents.sql delete mode 100644 frontend/src/lib/components/ExpertBadge.svelte 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 4e6b9c37..91e3c250 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java @@ -211,14 +211,6 @@ public class DocumentController { return ResponseEntity.ok(documentService.searchDocuments(q, from, to, senderId, receiverId, tags, tagQ, status, sort, dir)); } - // --- EXPERT FLAG --- - - @PatchMapping("/{id}/needs-expert") - @RequirePermission(Permission.WRITE_ALL) - public Document toggleNeedsExpert(@PathVariable UUID id) { - return documentService.toggleNeedsExpert(id); - } - // --- TRAINING LABELS --- public record TrainingLabelRequest(String label, boolean enrolled) {} 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 ab441cd9..f577b32b 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/dto/TranscriptionQueueItemDTO.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/dto/TranscriptionQueueItemDTO.java @@ -12,7 +12,6 @@ public record TranscriptionQueueItemDTO( UUID id, String title, LocalDate documentDate, - boolean needsExpert, int annotationCount, int textedBlockCount, int reviewedBlockCount diff --git a/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java b/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java index 0e7e954a..5a5ca54a 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java @@ -97,11 +97,6 @@ public class Document { @Builder.Default private ScriptType scriptType = ScriptType.UNKNOWN; - @Column(name = "needs_expert", nullable = false) - @Schema(requiredMode = Schema.RequiredMode.REQUIRED) - @Builder.Default - private boolean needsExpert = false; - @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "document_receivers", joinColumns = @JoinColumn(name = "document_id"), inverseJoinColumns = @JoinColumn(name = "person_id")) @Builder.Default diff --git a/backend/src/main/java/org/raddatz/familienarchiv/repository/DocumentRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/repository/DocumentRepository.java index 6e20c064..499b486b 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/repository/DocumentRepository.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/repository/DocumentRepository.java @@ -171,27 +171,26 @@ public interface DocumentRepository extends JpaRepository, JpaSp /** Documents with no annotations — Segmentierung column. */ @Query(nativeQuery = true, value = """ - SELECT d.id, d.title, d.meta_date AS documentDate, d.needs_expert AS needsExpert, + SELECT d.id, d.title, d.meta_date AS documentDate, 0 AS annotationCount, 0 AS textedBlockCount, 0 AS reviewedBlockCount FROM documents d WHERE d.status NOT IN ('PLACEHOLDER') AND NOT EXISTS (SELECT 1 FROM document_annotations da WHERE da.document_id = d.id) - ORDER BY d.needs_expert ASC, - HASHTEXT(d.id::text || EXTRACT(WEEK FROM NOW())::int::text) + ORDER BY HASHTEXT(d.id::text || EXTRACT(WEEK FROM NOW())::int::text) LIMIT :limit """) List findSegmentationQueue(@Param("limit") int limit); /** Documents with annotations but not yet fully reviewed — Transkription column. */ @Query(nativeQuery = true, value = """ - SELECT d.id, d.title, d.meta_date AS documentDate, d.needs_expert AS needsExpert, + SELECT d.id, d.title, d.meta_date AS documentDate, COUNT(DISTINCT da.id) AS annotationCount, COUNT(DISTINCT CASE WHEN tb.text IS NOT NULL AND tb.text <> '' THEN tb.id END) AS textedBlockCount, COUNT(DISTINCT CASE WHEN tb.reviewed = true THEN tb.id END) AS reviewedBlockCount FROM documents d JOIN document_annotations da ON da.document_id = d.id LEFT JOIN transcription_blocks tb ON tb.document_id = d.id - GROUP BY d.id, d.title, d.meta_date, d.needs_expert + GROUP BY d.id, d.title, d.meta_date HAVING COUNT(DISTINCT da.id) > 0 AND ( COUNT(DISTINCT CASE WHEN tb.text IS NOT NULL AND tb.text <> '' THEN tb.id END) = 0 @@ -200,8 +199,7 @@ public interface DocumentRepository extends JpaRepository, JpaSp NULLIF(COUNT(DISTINCT CASE WHEN tb.text IS NOT NULL AND tb.text <> '' THEN tb.id END), 0) ) < 0.90 ) - ORDER BY d.needs_expert ASC, - COUNT(DISTINCT CASE WHEN tb.text IS NOT NULL AND tb.text <> '' THEN tb.id END) DESC, + ORDER BY COUNT(DISTINCT CASE WHEN tb.text IS NOT NULL AND tb.text <> '' THEN tb.id END) DESC, HASHTEXT(d.id::text || EXTRACT(WEEK FROM NOW())::int::text) LIMIT :limit """) @@ -209,14 +207,14 @@ public interface DocumentRepository extends JpaRepository, JpaSp /** Documents with reviewed_pct >= 90 % — Lesefertig column. */ @Query(nativeQuery = true, value = """ - SELECT d.id, d.title, d.meta_date AS documentDate, d.needs_expert AS needsExpert, + SELECT d.id, d.title, d.meta_date AS documentDate, COUNT(DISTINCT da.id) AS annotationCount, COUNT(DISTINCT CASE WHEN tb.text IS NOT NULL AND tb.text <> '' THEN tb.id END) AS textedBlockCount, COUNT(DISTINCT CASE WHEN tb.reviewed = true THEN tb.id END) AS reviewedBlockCount FROM documents d JOIN document_annotations da ON da.document_id = d.id LEFT JOIN transcription_blocks tb ON tb.document_id = d.id - GROUP BY d.id, d.title, d.meta_date, d.needs_expert + GROUP BY d.id, d.title, d.meta_date HAVING COUNT(DISTINCT da.id) > 0 AND COUNT(DISTINCT CASE WHEN tb.text IS NOT NULL AND tb.text <> '' THEN tb.id END) > 0 AND ( diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java index 272da789..ab50ab22 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java @@ -577,13 +577,6 @@ public class DocumentService { return parsed != null ? parsed.title() : stripExtension(filename); } - @Transactional - public Document toggleNeedsExpert(UUID documentId) { - Document doc = getDocumentById(documentId); - doc.setNeedsExpert(!doc.isNeedsExpert()); - return documentRepository.save(doc); - } - private static String tryParseDate(String s) { if (s.matches("\\d{4}-\\d{2}-\\d{2}")) { int m = Integer.parseInt(s.substring(5, 7)); 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 1b4a0fde..9d500e5d 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionQueueService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionQueueService.java @@ -59,11 +59,10 @@ public class TranscriptionQueueService { UUID id = toUUID(row[0]); String title = (String) row[1]; LocalDate documentDate = toLocalDate(row[2]); - boolean needsExpert = toBoolean(row[3]); - int annotationCount = toInt(row[4]); - int textedBlockCount = toInt(row[5]); - int reviewedBlockCount = toInt(row[6]); - return new TranscriptionQueueItemDTO(id, title, documentDate, needsExpert, + int annotationCount = toInt(row[3]); + int textedBlockCount = toInt(row[4]); + int reviewedBlockCount = toInt(row[5]); + return new TranscriptionQueueItemDTO(id, title, documentDate, annotationCount, textedBlockCount, reviewedBlockCount); } @@ -79,11 +78,6 @@ public class TranscriptionQueueService { return LocalDate.parse(o.toString()); } - private boolean toBoolean(Object o) { - if (o instanceof Boolean b) return b; - return Boolean.parseBoolean(o.toString()); - } - private int toInt(Object o) { if (o == null) return 0; if (o instanceof Number n) return n.intValue(); diff --git a/backend/src/main/resources/db/migration/V37__add_needs_expert_to_documents.sql b/backend/src/main/resources/db/migration/V37__add_needs_expert_to_documents.sql deleted file mode 100644 index 03ee225a..00000000 --- a/backend/src/main/resources/db/migration/V37__add_needs_expert_to_documents.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE documents ADD COLUMN needs_expert BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/frontend/messages/de.json b/frontend/messages/de.json index 87ebe4b6..cf360bc9 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -573,7 +573,6 @@ "mission_control_ready_empty": "Noch keine Dokumente vollständig transkribiert.", "mission_control_ready_empty_cta": "Jetzt mitmachen", "mission_control_weekly_pulse": "↑ +{count} diese Woche", - "mission_control_expert_badge": "Experten gesucht", "mission_control_blocks_progress": "{texted} / {total} Blöcke", "mission_control_reviewed_pct": "{pct}% geprüft" } diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 0e558379..734783e6 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -573,7 +573,6 @@ "mission_control_ready_empty": "No documents fully transcribed yet.", "mission_control_ready_empty_cta": "Start contributing", "mission_control_weekly_pulse": "↑ +{count} this week", - "mission_control_expert_badge": "Expert needed", "mission_control_blocks_progress": "{texted} / {total} blocks", "mission_control_reviewed_pct": "{pct}% reviewed" } diff --git a/frontend/messages/es.json b/frontend/messages/es.json index d0000e33..d685d776 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -573,7 +573,6 @@ "mission_control_ready_empty": "Aún no hay documentos completamente transcritos.", "mission_control_ready_empty_cta": "Empezar a colaborar", "mission_control_weekly_pulse": "↑ +{count} esta semana", - "mission_control_expert_badge": "Se busca experto", "mission_control_blocks_progress": "{texted} / {total} bloques", "mission_control_reviewed_pct": "{pct}% revisado" } diff --git a/frontend/src/lib/components/ExpertBadge.svelte b/frontend/src/lib/components/ExpertBadge.svelte deleted file mode 100644 index 7fbdf28b..00000000 --- a/frontend/src/lib/components/ExpertBadge.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - - - {m.mission_control_expert_badge()} - diff --git a/frontend/src/lib/components/MissionControlStrip.svelte b/frontend/src/lib/components/MissionControlStrip.svelte index 00221f0d..52664b54 100644 --- a/frontend/src/lib/components/MissionControlStrip.svelte +++ b/frontend/src/lib/components/MissionControlStrip.svelte @@ -8,7 +8,6 @@ type TranscriptionQueueItemDTO = { id: string; title: string; documentDate?: string; - needsExpert: boolean; annotationCount: number; textedBlockCount: number; reviewedBlockCount: number; diff --git a/frontend/src/lib/components/ReadyColumn.svelte b/frontend/src/lib/components/ReadyColumn.svelte index 3d5f999a..4ab49256 100644 --- a/frontend/src/lib/components/ReadyColumn.svelte +++ b/frontend/src/lib/components/ReadyColumn.svelte @@ -6,7 +6,6 @@ type TranscriptionQueueItemDTO = { id: string; title: string; documentDate?: string; - needsExpert: boolean; annotationCount: number; textedBlockCount: number; reviewedBlockCount: number; diff --git a/frontend/src/lib/components/SegmentationColumn.svelte b/frontend/src/lib/components/SegmentationColumn.svelte index f8ab88bd..2534734f 100644 --- a/frontend/src/lib/components/SegmentationColumn.svelte +++ b/frontend/src/lib/components/SegmentationColumn.svelte @@ -1,13 +1,11 @@