Field order: Titel → Schlagworte → Kurzinhalt → [Optional divider] → Aufbewahrungsort.
currentTitle is now bindable so the enrich page can derive the required-fields progress bar.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Required fields (Datum, Absender) move to row 1; optional fields (Empfänger, Ort)
to row 2. dateIso is now bindable for the progress bar. Autofocus lands on the
first empty required field on page load.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pixel-accurate spec for the dashboard redesign: Resume + Family Pulse
layout with hero resume card, mission control 3-up, and activity feed.
Relates to #271
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Captures the centered-card registration design 1:1 from the claude.ai/design export. Covers all 10 sections: desktop overview, header, above-card copy, form fields, password states, notification card, submit button, success panel, mobile layout, and i18n/a11y/backend implementation notes.
Relates to #269
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>
Add V42 partial unique index on ocr_training_runs(person_id) WHERE status='QUEUED'
to enforce the per-person queued coalescing guarantee at the DB level. Also adds
@ExtendWith(MockitoExtension.class) to SenderModelServiceTest for consistency with
the rest of the service test suite, with lenient() on the shared txTemplate stub.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the per-run getById loop with a single getAllById call on distinct
person IDs, eliminating the N+1 query when training history contains multiple
sender model runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the intermediate Map<String,Object> and return the typed record directly
so OpenAPI codegen produces a concrete TypeScript type. Fixes lastRun serializing
as {} (empty object) instead of null when no training run exists.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add 503/403 auth tests for the /train-sender endpoint, matching the pattern
already used for /train and /segtrain. Also surface test_sender_registry.py
in CI (it needs no ML stack) and add pytest-asyncio to the install step.
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>
Eliminates cross-domain repository access: OcrTrainingService no longer
holds SenderModelRepository. SenderModelService now owns the full sender
training lifecycle (runOrQueueSenderTraining, triggerSenderTraining,
promoteNextQueuedRun), removing the circular dependency risk.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The controller now builds the map inline (with personNames support).
This method had zero callers.
Fixes reviewer concerns from @felixbrandt and @mkeller.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces catch(Exception ignored){} with log.debug() in getTrainingInfo().
Adds controller test documenting the graceful degradation behavior
(response stays 200 when personService.getById() throws).
Fixes reviewer concerns from @felixbrandt and @nullx.
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>
- OcrAsyncRunnerTest: switch from extractBlocks/4-arg streamBlocks stubs
to 5-arg streamBlocks (senderModelPath param) via doAnswer
- TranscriptionServiceTest: stub documentService.getDocumentById in
updateBlock tests so the new Kurrent training hook does not NPE
- OcrControllerTest: add @MockitoBean PersonService (now injected into
OcrController for personNames assembly in getTrainingInfo)
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>
Consistent with triggerManualSenderTraining — both defensive paths now use
DomainException.internal(OCR_TRAINING_CONFLICT) when the expected RUNNING row
is not found after creation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SvelteKit page components receive only data/form as props; accessing params
directly caused a TypeError and personName always fell back to 'Unknown'.
Also moves py-3 padding from <td> to <a> in OcrModelsTable to give
keyboard/touch users a full-height 44px target (WCAG 2.5.5).
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>
OcrHealthBar spec used /online/i and /offline/i text matchers that would fail
in Spanish locale — replaced with CSS class assertions on role="img" dot.
Added focus-visible:ring-2/ring-brand-navy/rounded-sm to all links in OCR
admin pages (OcrModelsTable person+details, global history link, back-links
in global and personId detail pages) to satisfy WCAG 2.4.7.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Controller was deciding when to fire runSenderTraining based on the returned run
status — a business rule that belongs in the service. Introduces @Lazy self-reference
to preserve @Async proxy dispatch without self-invocation bypassing Spring AOP.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace hardcoded EN strings in OcrHealthBar/OcrStatCards/OcrModelsTable with
Paraglide message keys (de/en/es translations added)
- Add role=img + aria-label to OcrHealthBar status dot
- Add {:else} empty-state row in OcrModelsTable
- Fix personName derivation in [personId]/+page.svelte to use params.personId key
instead of Object.values()[0] (fragile when multiple persons present)
- Update OcrModelsTable spec to assert empty-state row structure (locale-agnostic)
- Add missing availableSegBlocks test to OcrStatCards spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>