Add missing test coverage for the amber QUEUED status badge in TrainingHistory.
Fix WCAG 2.2 minimum touch target (24 × 24 px) on the success-message dismiss
button in OcrTrainingCard. Add focus-visible ring to the expand/collapse toggle
in TrainingHistory so keyboard users get a visible focus indicator.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OcrAsyncRunner now passes the per-sender model path to streamBlocks for
HANDWRITING_KURRENT documents. processDocument replaced extractBlocks
with streamBlocks + AtomicReference, removing the unchecked raw-array
pattern.
Also stages all previously uncommitted foundational files for this
feature: SenderModel entity, SenderModelRepository, Flyway migrations
V40/V41, updated OcrClient/RestClientOcrClient streaming API,
TrainingDataExportService.exportForSender, TranscriptionService Kurrent
hook, application.yaml OCR config, and frontend i18n/test additions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extends Run interface with personId and QUEUED status, TrainingInfo with
personNames map, and passes it through to TrainingHistory for per-sender
model column display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OcrTrainingRun now includes personId (uuid, optional) and QUEUED status.
TrainingInfoResponse includes runs array with personId fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OcrTrainingCard and SegmentationTrainingCard now live on the dedicated
OCR overview page. System page no longer fetches training info.
SegmentationTrainingCard updated to use shared TrainingRun type.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add showPersonColumns prop (default true) to TrainingHistory.
SegmentationTrainingCard passes false — segmentation is not person-specific.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ensures the unexpected-state path produces a structured JSON error response
instead of an unmapped 500 RuntimeException. Adds OCR_TRAINING_CONFLICT
ErrorCode and mirrors it in the frontend errors.ts. Adds coverage tests for
getAllSenderModels() and runSenderTraining().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add missing test coverage for the amber QUEUED status badge in TrainingHistory.
Fix WCAG 2.2 minimum touch target (24 × 24 px) on the success-message dismiss
button in OcrTrainingCard. Add focus-visible ring to the expand/collapse toggle
in TrainingHistory so keyboard users get a visible focus indicator.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OcrAsyncRunner now passes the per-sender model path to streamBlocks for
HANDWRITING_KURRENT documents. processDocument replaced extractBlocks
with streamBlocks + AtomicReference, removing the unchecked raw-array
pattern.
Also stages all previously uncommitted foundational files for this
feature: SenderModel entity, SenderModelRepository, Flyway migrations
V40/V41, updated OcrClient/RestClientOcrClient streaming API,
TrainingDataExportService.exportForSender, TranscriptionService Kurrent
hook, application.yaml OCR config, and frontend i18n/test additions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extends Run interface with personId and QUEUED status, TrainingInfo with
personNames map, and passes it through to TrainingHistory for per-sender
model column display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OcrTrainingRun now includes personId (uuid, optional) and QUEUED status.
TrainingInfoResponse includes runs array with personId fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pdfDoc was a plain variable (not \$state), so renderer.isLoaded had no
reactive dependencies in Svelte 5. PdfControls received isLoaded=false
permanently, keeping the next-page button disabled while zoom buttons
(which have no disabled attribute) still worked.
Fix: derive isLoaded from totalPages (\$state) via totalPages > 0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Confirms that Enter on a suggestion item adds the tag even when allowCreation is
false — the activeIndex guard in handleKeydown runs before the allowCreation check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fetchSuggestions has no debounce; the wait is purely for the async mock to
resolve. The old name implied semantics that don't exist and added ~4.5s to
the suite (13 uses × 350ms).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrites orderedSuggestions to a recursive DFS with SuggestionEntry type,
adds role=listbox, depth indentation via inline style, font-medium for direct
matches, text-ink-3 for context nodes, and › prefix for root-level ancestors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add filter_operator_and/or/and_label/or_label i18n keys to de/en/es locale files
- Add aria-label and aria-pressed to AND/OR toggle buttons in SearchFilterBar
- Add data-testid="operator-and/or" for unambiguous test targeting (fixes substring match on German "Schlagwort")
- Use stable keys (tag.id ?? tag.name) for TagInput chip and suggestion lists
- Remove aria-level from role="option" items in TagInput (invalid attribute for that role)
- Add aria-live="polite" role="status" to TagMergeZone step indicator
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds INVALID_TAG_COLOR and TAG_CYCLE_DETECTED to the frontend ErrorCode
type and getErrorMessage() switch. German, English, and Spanish
translations added for both codes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- TagRepository: add findDescendantIdsByName() recursive CTE query
- TagService: add expandTagNamesToDescendantIdSets() for document search
Frontend:
- TagInput: accept Tag[] (id, name, color, parentId) instead of string[]
- Chips show color dot via var(--c-tag-{color}) when tag has color
- Suggestions grouped hierarchically: children indented under their parents
- Update DescriptionSection, edit/new pages, SearchFilterBar, +page.svelte
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds TagTreeNodeDTO, TagUpdateDTO (parentId + color), /api/tags/tree endpoint,
and parentId/color fields on Tag schema.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
"Text eintippen" sounded too casual and diverged from the domain
language used elsewhere in the app.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
"Rahmen einzeichnen" assumed familiarity with the segmentation concept;
"Text markieren" is self-explanatory for new contributors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Lesefertig pulse was removed from the UI; drop the backend support
for it too — removes the subquery from findWeeklyStats(), the projection
getter, the DTO field, and updates all affected tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The weekly count in Lesefertig counted any document with a reviewed
block in the past 7 days, not documents that crossed the ≥90% ready
threshold — a misleading stat given the column shows a different set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
17 tests across SegmentationColumn, TranscriptionColumn, ReadyColumn,
MissionControlStrip. Covers document list rendering, per-column empty
states, weekly pulse visibility, link hrefs, progress bar, and the
reviewedPct denominator (annotationCount, not textedBlockCount).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add formatMCDate() to $lib/utils/date.ts (locale-aware, medium format);
remove duplicated inline formatDate() from all three column components
- Replace local TranscriptionQueueItemDTO/TranscriptionWeeklyStatsDTO type
declarations with imports from $lib/generated/api across all four components
- Add dashed empty states to SegmentationColumn and TranscriptionColumn
(ReadyColumn already had one)
- Remove outer {#if} from MissionControlStrip so the section is always
visible — each column owns its own empty state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TranscriptionColumn progress bar: add aria-hidden="true" (the block count
text above already communicates the value to screen readers)
- TranscriptionColumn weekly pulse: text-ink → text-ink-2 (matches
SegmentationColumn, same semantic element)
- ReadyColumn reviewedPct: align denominator to annotationCount so the
displayed percentage matches the SQL threshold used to classify "ready"
- page.svelte.spec.ts: add missing segmentationDocs/transcriptionDocs/
readyDocs/weeklyStats to emptyData fixture
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The original needsExpert V37 migration was applied to the dev DB before
the feature was removed. Renaming our new indexes migration to V38 avoids
the Flyway checksum conflict. Regenerated api.ts now reflects the
@Schema(requiredMode=REQUIRED) annotations — DTO fields are non-optional.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>