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 <noreply@anthropic.com>
This commit is contained in:
@@ -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) {}
|
||||
|
||||
@@ -12,7 +12,6 @@ public record TranscriptionQueueItemDTO(
|
||||
UUID id,
|
||||
String title,
|
||||
LocalDate documentDate,
|
||||
boolean needsExpert,
|
||||
int annotationCount,
|
||||
int textedBlockCount,
|
||||
int reviewedBlockCount
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -171,27 +171,26 @@ public interface DocumentRepository extends JpaRepository<Document, UUID>, 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<Object[]> 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<Document, UUID>, 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<Document, UUID>, 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 (
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE documents ADD COLUMN needs_expert BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
Reference in New Issue
Block a user