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>
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 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>
Manually adds the new types to src/lib/generated/api.ts:
- Document.needsExpert: boolean (required field)
- TranscriptionQueueItemDTO schema
- TranscriptionWeeklyStatsDTO schema
- Paths: /api/transcription/{segmentation-queue, transcription-queue,
ready-to-read, weekly-stats} and /api/documents/{id}/needs-expert
- Operations: matching typed request/response shapes
Fixes briefwechsel spec fixtures to include scriptType and needsExpert
so the Document type shape is satisfied.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a summary_snippet column to findEnrichmentData using ts_headline on
documents.summary, only when the summary's tsvector matches the query.
Expose it via SearchMatchData.summarySnippet / summaryOffsets and render
a "Zusammenfassung" / "Summary" / "Resumen" labelled row in the document
list — identical treatment to the transcription snippet row.
Fixes the case where a document appeared in search results with no
visible match explanation (e.g. searching "frucht" found a document
whose summary mentioned "Früchte").
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Kraken 7 removed support for the legacy `path` format (image + .gt.txt
pairs) in VGSLRecognitionDataModule despite the CLI still advertising it.
Switching to PAGE XML (-f page) format which is the supported standard.
- Java export now writes .xml alongside .png (PAGE XML with TextLine,
Baseline at 75% height, and Unicode transcription)
- XML special characters in transcription text are escaped (& < >)
- Python trainer globs *.xml and passes -f page to ketos train
- Regenerated frontend API types to include cer/loss/accuracy/epochs on
OcrTrainingRun (were missing, causing empty CER column in history)
- Updated and extended TrainingDataExportServiceTest
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Convert TrainingHistory, OcrTrainingCard, SegmentationTrainingCard, and
TranscriptionBlock "Nur Segmentierung" badge to use Paraglide message keys
- Add availableSegBlocks to TrainingInfoResponse to expose segmentation
block count in the training info endpoint
- Wire SegmentationTrainingCard into admin/system page below OCR training card
- Update api.ts with availableSegBlocks field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add displayName default method to PersonSummaryDTO
- Update native SQL queries to include title, person_type columns
- Add getInitials() utility to personFormat.ts
- Update abbreviateName/abbreviateCompact for nullable firstName
- Replace firstName+lastName concatenation with displayName in all
person-displaying components and server load files
- Regenerate API types with displayName on Person and PersonSummaryDTO
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Person type now includes displayName (readonly, required), title,
personType (required enum), and firstName is optional.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blockers (14):
- B1: fix senderName/receiverName to use $derived instead of $state + sync $effect
- B2: migrate all korrespondenz components from messages-extra shim to paraglide m.*
- B3: i18n CorrespondenzEmptyState (heading, subtext, search placeholder)
- B4: add response.ok checks to admin layout server load
- B5: add response.ok checks to korrespondenz page server load
- B6: add page.server.spec.ts with 5 test suites for korrespondenz load function
- B7: add axe-core accessibility checks to all e2e korrespondenz tests
- B8: add Testcontainers JPQL tests for findSinglePersonCorrespondence (DISTINCT + sender)
- B9: hide auth reset-token endpoint from OpenAPI spec; remove from generated api.ts
- B11: replace amber hardcoded hex colors in SinglePersonHintBar with brand tokens
- B12: replace clipboard emoji with Heroicons SVG in SinglePersonHintBar
- B13: create DateInput component (German dd.mm.yyyy); use it in CorrespondenzFilterControls
- B14: add Paraglide compile step to CI workflow before lint/test
Suggestions (11):
- S1: make CorrespondentSuggestionsDropdown a pure display component; lift fetch to PersonBar
- S2: fix leftover messages-extra import in ConversationTimeline; use brand tokens for status dots
- S3: add intent comment to EntityNav openFlyout behavior
- S4: rename canManageGroups → canManagePermissions throughout admin
- S6: remove domFlush helper from DateInput spec; use expect.poll instead
- S7: replace test.skip with throw new Error in bilateral e2e tests
- S8: add inverse aria-disabled test for filter strip
- S9: remove sm:min-h-0 from sort button to preserve 44px touch target
- S10: add title attributes to tablet trigger buttons in EntityNav
- S11: delete messages-extra.ts shim entirely
Also: fix admin pages revealing blank strip at bottom (-mb-6 on admin layout)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves conversations/ to korrespondenz/, updates all internal links,
renames nav label and page heading to Korrespondenz across de/en/es,
and adds all new i18n keys for the redesigned strip and log.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolved conflicts in messages/de.json, en.json, es.json by keeping
both the persons-redesign keys (feature branch) and the notification
keys (main) in all three locale files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace recent-by-creation fetch with GET /api/documents/recent-activity
(sorted by updatedAt) in the dashboard. Update DashboardRecentDocuments
component to use doc.updatedAt, update i18n heading to "Zuletzt aktiv" /
"Recent Activity" / "Actividad reciente", and regenerate API types.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds type, read (notifications) and status (documents/search),
size (documents/incomplete) to the generated TypeScript types.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds NotificationType filter params, IncompleteDocumentDTO, and status
param on document search.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Home page shows "Needs metadata" card when incomplete documents exist.
/enrich list shows all incomplete documents; /enrich/[id] provides a
split PDF-preview + compact form view with Skip / Save / Save & reviewed
actions that auto-advance through the queue.
New document page gets Save vs Save & reviewed split. Edit page gets
"Mark for review" secondary button to push a document back into the queue.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Regenerate API types with fileHash on Document and DocumentAnnotation
- PdfViewer accepts documentFileHash prop; filters visibleAnnotations to
those whose hash matches (or is null) and shows an amber notice banner
when any annotations are hidden due to a hash mismatch
- Document detail page passes doc.fileHash to PdfViewer
- Add i18n key annotation_outdated_notice in de/en/es
- E2E: two new tests covering hide-on-reupload and restore-on-original-reupload
scenarios; add minimal2.pdf fixture for a different-hash upload
Closes#55
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Admin can trigger an initial history snapshot for all documents without
version history. Shows count of backfilled documents after completion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a collapsible history section to the document detail view, showing
all saved versions with changed-field labels, word-level diff between
adjacent versions, and a compare mode for any two arbitrary versions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- /forgot-password: email form → sends POST /api/auth/forgot-password → success banner
- /reset-password: password form reads token from URL → sends POST /api/auth/reset-password
- Login page: add "Passwort vergessen?" link
- hooks.server.ts: add /forgot-password and /reset-password to PUBLIC_PATHS; skip auth
injection for public auth API endpoints
- errors.ts: add INVALID_RESET_TOKEN error code
- i18n: add all new message keys in de/en/es
- playwright.config.ts: use E2E_BASE_URL for webServer check URL (allows reusing docker
dev server at port 5173 locally)
- ci.yml: pass E2E_BACKEND_URL=http://localhost:8080 to E2E test step
- e2e/password-reset.spec.ts: 5 tests (4 pass locally, full flow requires e2e profile in CI)
- Regenerated OpenAPI types including new /api/auth/* endpoints
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The handleFetch hook previously skipped auth headers for all URLs
containing /api/users/me. Since the hook's own user-load call uses
globalThis.fetch (bypassing handleFetch), it is safe to remove this
exception — enabling profile update and password change actions to
authenticate properly.
Also regenerates API types with new profile endpoints and AppUser fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolves merge conflicts with main (feat/person-notes merged first).
Combines both features: birth/death years and notes field on person detail.
Renames migration V5__add_birth_death_years to V6 to avoid Flyway conflict.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
V5 Flyway migration adds TEXT notes column; Person entity, service, and
controller updated to persist notes. Frontend edit form adds textarea and
view mode renders the notes section. Backed by 2 new service unit tests
(persist + blank clears).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
V5 Flyway migration adds birth_year and death_year INTEGER columns.
Service validates birthYear <= deathYear (400 otherwise). Frontend edit
form adds year number inputs; view mode renders * year / † year. Backed
by 3 backend service tests and 1 E2E test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: new POST /api/persons endpoint in PersonController
- Frontend: new /persons/new route with Vorname/Nachname/Alias form,
redirects to the new person's detail page on success
- Persons list: subtle '+ Neue Person' link below the page title
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: new POST /api/documents endpoint with DocumentService.createDocument()
reusing DocumentUpdateDTO; handles file upload, tags, sender, receivers
- Frontend: new /documents/new route with same four-section form as edit page
(Wer & Wann, Beschreibung, Transkription, Datei) but with empty fields
- Home page: subtle '+ Neues Dokument' link above the document list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause 1 — OpenAPI types: add @Schema(requiredMode=REQUIRED) to
non-nullable fields on Person, Tag, Document, AppUser, UserGroup;
regenerate api.ts so required fields are no longer optional.
Root cause 2 — Stale types: api.ts regenerated, picking up the Tag
endpoint fix from commit 62189d8 (List<Tag> instead of List<String>).
Root cause 3 — openapi-fetch error pattern: replace `if (apiError)`
(broken when error type is never/undefined) with `if (!result.response.ok)`
across all +page.server.ts files. Cast error via `unknown` to satisfy TS.
Root cause 4 — FormData casts: add `as string` / `as string[]` to
FormData.get() / FormData.getAll() calls in admin/+page.server.ts.
Standalone fixes:
- +page.server.ts: return error field so home page template compiles
- documents/[id]/+page.svelte: type loadFile param, remove invalid iframe `type`
- conversations: type documents as Document[] instead of unknown[]
- persons/[id]: non-null assert person data after ok-check
a11y: aria-label on all icon-only buttons in TagInput and admin page,
replace invalid <label> with <p> for compound controls, remove autofocus.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Now contains only the 16 intentional /api/* endpoints. TypeScript will
enforce path and parameter correctness for all typed client calls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All server-side fetch calls now go through createApiClient() from
$lib/api.server.ts, which wraps openapi-fetch with the generated OpenAPI
types. This means backend changes are reflected in the frontend after
running npm run generate:api.
- Add stub src/lib/generated/api.ts (replaced by generate:api output)
- Fix GroupController: missing /api prefix and ResponseStatusException
- Root, conversations, persons, documents pages all use typed client
- Error handling uses apiError.code directly (no parseBackendError needed)
- Edit page load uses typed client; PUT action keeps raw fetch (multipart)
- Login keeps raw fetch (explicit Authorization header, not cookie auth)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>