Commit Graph

140 Commits

Author SHA1 Message Date
Marcel
46dae8a826 feat(bulk-upload): guard discard-all with confirm dialog
Uses getConfirmService() (optional — null fallback when context is absent so
unit tests that don't exercise the discard path need no CONFIRM_KEY context)
and the new bulk_discard_confirm i18n key.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 11:26:05 +02:00
Marcel
f1b3e8c2d8 fix(i18n): remove orphaned merge conflict markers from message files
All three message files had a bare `<<<<<<< HEAD` at line 814 with no
corresponding separator or closing marker, making them invalid JSON and
breaking the Paraglide build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 01:07:44 +02:00
Marcel
a2a7d547ee fix(bulk-upload): i18n topbar title; replace hardcoded German strings
'Neues Dokument' / 'Neue Dokumente' in BulkDocumentEditLayout topbar
bypassed Paraglide. Added bulk_title_single and bulk_title_multi keys
to de/en/es message files and switched to m.*() calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 23:22:36 +02:00
Marcel
43122c20cb fix(bulk-upload): i18n hardcoded strings in BulkDropZone and FileSwitcherStrip
- Add bulk_drop_desc, bulk_select_files, bulk_drop_zone_label, bulk_remove_file
  keys to de/en/es message files
- BulkDropZone: use m.bulk_drop_zone_label(), m.bulk_drop_desc(),
  m.bulk_select_files() — removes all hardcoded German
- FileSwitcherStrip: use m.bulk_remove_file() on × button; move aria-live
  from <ul> to a dedicated visually-hidden region above the strip (screen
  readers now announce changes without coupling the live region to the list)
- Spec: import FileEntry from component instead of re-declaring; use
  data-remove-id selector instead of hardcoded German aria-label

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 23:22:35 +02:00
Marcel
8b05451f42 fix(bulk-upload): PDF-only file acceptance
Drop non-PDF accept types from file input and update format hint strings
in all three languages. JPEG/PNG/TIFF were never officially supported.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 23:22:35 +02:00
Marcel
edd96b05fe feat(bulk-upload): add UploadSaveBar component + fix bulk_save_cta message
Save bar with sticky positioning, a determinate progress bar while
uploading chunks, plural save CTA, and a destructive discard link.
Replaces broken ICU plural in bulk_save_cta with two-key approach
(bulk_save_cta_one / bulk_save_cta) since Paraglide 2.5 does not support
ICU plural syntax.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 23:22:35 +02:00
Marcel
f86105a1be feat(i18n): add BATCH_TOO_LARGE error code + 16 bulk-upload Paraglide keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 23:22:35 +02:00
Marcel
7fb9d74515 feat(transcribe): copy pass markieren→einrahmen in transcription_next_block_cta
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 21:08:40 +02:00
Marcel
86584a53a8 feat(transcribe): add TranscribeCoachEmptyState and TranscribeDragDemo components
New coach card replaces the icon+sentence empty state in the Transcribe
panel (edit mode). Three-step guide with 5-s SMIL drawing animation in
step 1 only. Animation freezes at the final frame when
prefers-reduced-motion is active. Footer links to Wikipedia Kurrent and
the Richtlinien page open in new tabs with visible '(öffnet in neuem Tab)'
annotations. 34 new i18n keys in de/en/es.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 21:00:01 +02:00
Marcel
78ac5d663d feat(documents): paginate search with a Pagination control
Frontend side of the /documents pagination work. The page.server.ts load
reads ?page= from the URL, forwards page+size=50 to the backend, and
exposes the new totalElements/pageNumber/pageSize/totalPages fields on
`data`. +page.svelte renders a <Pagination> component below the result
list; buildPageHref preserves every filter param and only updates page.
The existing triggerSearch debounce flow intentionally drops `page`
when any filter changes, so filter edits reset to page 0 automatically.

<Pagination> uses plain <a href> links (not goto) so SvelteKit's default
scroll restoration scrolls new pages to the top — the expected senior-UX
behaviour. Decorative chevrons wrapped in aria-hidden spans, 44px touch
targets, focus-visible ring, stacks vertically under 640px. The control
hides itself when totalPages ≤ 1.

Test coverage: 9 cases on Pagination (label, aria-current, prev/next
enable/disable, makeHref invocation, decorative chevron, touch target),
plus a filter-reset assertion on +page.svelte (page 5 → edit q →
goto URL must drop page=). Adds i18n keys in de/en/es. Manual edit to
api.ts pending a post-merge npm run generate:api against a rebuilt
dev backend. (#315)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 13:20:24 +02:00
Marcel
f5a30c71b7 i18n(briefwechsel): ThumbnailRow direction label via Paraglide
Adds row_direction_sent / row_direction_received keys across the
three locale files (de: Gesendet/Empfangen, en: Sent/Received, es:
Enviada/Recibida) and routes ThumbnailRow's directionLabel through
Paraglide. An English or Spanish screen-reader user now hears
"Sent:" / "Enviada:" in their language, matching the DistributionBar
i18n pass.

Refs #305
Fixes @leonievoss round-2 follow-up from PR review

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 21:38:56 +02:00
Marcel
d4617a96d1 i18n(briefwechsel): DistributionBar reads text + aria-label via Paraglide
Drops the hardcoded German strings ("Briefverteilung in diesem Zeitraum",
"{n} von {name}") and routes every visible + assistive-tech string
through dist_bar_aria and dist_bar_segment message keys. An English
or Spanish user now sees "from" / "de" instead of "von" both on
screen and in the aria-label their screen reader announces.

Refs #305
Fixes @leonievoss i18n concern from PR review

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 21:38:56 +02:00
Marcel
7bb3800490 feat(frontend): add admin card to generate thumbnails with polling
Fourth card on /admin/system mirrors the mass-import pattern:
- POST /api/admin/generate-thumbnails to trigger
- 2000 ms polling on /api/admin/thumbnail-status while RUNNING
- processed / skipped / failed counters in the DONE message
- standalone pollInterval so import and thumbnail polling don't
  interfere with each other

Paraglide keys added in de/en/es, mirroring admin_system_import_*.

Refs #307

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 22:39:47 +02:00
Marcel
fd93f1a4da feat(chronik): rename route and heading to Aktivitäten
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m48s
CI / OCR Service Tests (push) Successful in 31s
CI / Backend Unit Tests (push) Failing after 2m43s
/chronik → /aktivitaeten; heading updated in all three locales.
Component folder (lib/components/chronik/) stays unchanged — internal
implementation detail, not user-facing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 09:28:09 +02:00
Marcel
4f671824dd feat(chronik): align layout to grouped card pattern; fix duplicate rollup count
Some checks failed
CI / Unit & Component Tests (push) Failing after 3m31s
CI / OCR Service Tests (push) Successful in 57s
CI / Backend Unit Tests (push) Failing after 3m0s
- ChronikTimeline: date buckets now render as bordered cards with muted
  header (border-line / bg-surface / shadow-sm) and divide-y row
  separators, matching the DocumentList card pattern
- ChronikRow: remove rounded-sm (card handles clipping), hover:bg-canvas
  → hover:bg-muted/50; restore rollup count badge after doc title
- Messages (de/en/es): remove embedded {count} from all four rollup verb
  strings so the badge is the single source of truth, consistent with
  DashboardActivityFeed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 09:13:03 +02:00
Marcel
727569aa32 i18n: add upload-banner + enrichment-block keys
Singular/plural banner copy, a count-aware "show all" footer link, and
the dismiss aria-label for the new dashboard enrichment-list-block
(issue #296). Covers de / en / es.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:25:17 +02:00
Marcel
6b433fa82a feat(chronik): add ADR-003 + Paraglide keys for /chronik page (de/en/es)
- docs/adr/003-chronik-unified-activity-feed.md: records the session-rollup
  decision (LAG + 120-min gap), the dedupe deletion, the single-endpoint
  composition, and the German-URL convention.
- frontend/messages/{de,en,es}.json: adds chronik_* keys for page title,
  Für-dich box, filter pills, day headers, singleton/rollup verb variants
  per kind, empty states, error card, Mehr-laden pagination, and the Bell
  footer link retarget.

No pluralization via ICU match — separate singleton/rollup keys per verb,
per the Felix discussion (comment #3573).

Part of #285.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
909041adbb feat(i18n): add unknown sender/receiver fallback labels for document grouping
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:29:33 +02:00
Marcel
d6e5d3d1e8 fix(layout): replace hardcoded 'Hochladen' with m.upload_action() + aria-label
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 22:23:32 +02:00
Marcel
18e321b1e6 feat(dashboard): show block count instead of page numbers in resume strip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 21:32:13 +02:00
Marcel
99247ed58d feat(i18n): add dashboard i18n keys (de/en/es)
Greeting, resume card, mission control, family pulse, activity feed,
audit action verbs, and dropzone keys for the Issue #271 dashboard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 17:13:57 +02:00
Marcel
692c2c0629 feat(register): show invite-only error when no code param is present
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m34s
CI / OCR Service Tests (push) Successful in 34s
CI / Backend Unit Tests (push) Failing after 2m50s
Visiting /register without a code now shows a friendly error card
explaining the archive is invite-only, instead of the empty form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:29:34 +02:00
Marcel
d07f7debf8 feat(register): redesign register page to match spec
Replaces the minimal login-style form with the full spec design:
hero section (eyebrow, headline, subtext), three labelled form sections,
2-column name grid, confirm-password field with client-side match hints,
password strength indicator, notification checkbox card, loading state on
submit, and "already have an account?" footer link.

Backend: adds notifyOnMention to RegisterRequest and wires both
notifyOnMention and notifyOnReply via updateNotificationPreferences on
invite redemption.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:27:03 +02:00
Marcel
daea748a20 feat(frontend): invite-based registration UI
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m37s
CI / OCR Service Tests (push) Successful in 32s
CI / OCR Service Tests (pull_request) Successful in 30s
CI / Backend Unit Tests (push) Failing after 2m47s
CI / Unit & Component Tests (pull_request) Failing after 2m29s
CI / Backend Unit Tests (pull_request) Failing after 2m46s
- Add /register route with invite code prefill, password show/hide
- Add /login?registered=1 success banner
- Add /admin/invites page: list, create, revoke, copy link
- Add Einladungen nav section to admin sidebar (ADMIN_USER perm)
- Add invite error codes to errors.ts
- Add 48 i18n keys across de/en/es
- Update hooks.server.ts to allow public access to invite/register API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 01:01:19 +02:00
Marcel
d816e94a90 feat(auth): migrate frontend from username to email-only authentication
- Login page: email input replaces username field (type=email, name=email)
- Login server action: reads email, uses i18n error for missing credentials
- AccountSection: email input (type=email) replaces username text field
- New user server action: sends email as required field, drops username
- UsersListPanel: displays and searches by email instead of username
- Admin edit user page: heading and delete confirm use email
- Profile page: fullName fallback uses email, drops @username display
- app.d.ts: email required on User, username removed
- Generated API types: AppUser.email required, username removed; CreateUserRequest.email required, username removed
- i18n: login_label_email, login_error_missing_credentials, admin_col_login updated (de/en/es)
- errors.ts: MISSING_CREDENTIALS → login_error_missing_credentials

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 23:36:55 +02:00
Marcel
d31ea12086 feat(upload): validate MIME type and size on file replace in DocumentEditLayout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 23:36:31 +02:00
Marcel
b0ea5f5552 feat(i18n): extract hardcoded strings in DocumentEditLayout to i18n keys
Adds label_required_fields to all three locales. Fixes "Datei ersetzen"
toolbar colors to use semantic ink tokens (readable in both light and dark
pdf-bg themes).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 23:36:31 +02:00
Marcel
9bad9e807b fix(i18n): replace hardcoded strings with Paraglide message keys
- error_file_upload_failed key used in enrich upload handler
- label_optional key added (de/en/es) and used in DescriptionSection divider

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 23:36:31 +02:00
Marcel
1279753ddb fix(ocr): clarify stat card labels to distinguish available vs total blocks
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m30s
CI / OCR Service Tests (push) Successful in 38s
CI / Backend Unit Tests (push) Failing after 2m50s
CI / Unit & Component Tests (pull_request) Failing after 2m52s
CI / OCR Service Tests (pull_request) Successful in 48s
CI / Backend Unit Tests (pull_request) Failing after 2m55s
'Trainingsblöcke' and 'Gesamt Blöcke' were indistinguishable.
Labels now read 'Bereit (OCR-Training)', 'Textblöcke gesamt',
'Trainingsdokumente', 'Bereit (Segm.-Training)'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 11:06:43 +02:00
Marcel
a00617194c fix(admin): i18n all hardcoded OCR strings, fix personName lookup, add empty state
Some checks failed
CI / Unit & Component Tests (push) Failing after 3m17s
CI / OCR Service Tests (push) Successful in 57s
CI / Backend Unit Tests (push) Failing after 2m52s
CI / Unit & Component Tests (pull_request) Failing after 2m47s
CI / OCR Service Tests (pull_request) Successful in 43s
CI / Backend Unit Tests (pull_request) Failing after 2m48s
- 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>
2026-04-18 08:59:49 +02:00
Marcel
5f4e60a14c feat(admin): add OCR entry to EntityNav sidebar and flyout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 00:25:42 +02:00
Marcel
1e289100a1 fix(frontend): show error on training start failure, add aria-live and dismiss to success message
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 20:46:06 +02:00
Marcel
18cf839fac feat(ocr): wire SenderModelService into OcrAsyncRunner; stage missing foundational files
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m21s
CI / OCR Service Tests (push) Successful in 29s
CI / Backend Unit Tests (push) Failing after 2m38s
CI / Unit & Component Tests (pull_request) Failing after 2m26s
CI / OCR Service Tests (pull_request) Successful in 31s
CI / Backend Unit Tests (pull_request) Failing after 2m44s
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>
2026-04-17 19:27:02 +02:00
Marcel
eaefd4091e feat(ocr): add PREPROCESSING_PAGE progress translation and i18n strings
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m34s
CI / Backend Unit Tests (push) Failing after 2m57s
CI / Unit & Component Tests (pull_request) Failing after 2m36s
CI / Backend Unit Tests (pull_request) Failing after 2m43s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 14:27:42 +02:00
Marcel
3b1317af98 fix(admin-tags): name clears after save and wrong confirmation text
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m30s
CI / Backend Unit Tests (pull_request) Failing after 2m45s
CI / Unit & Component Tests (push) Failing after 2m35s
CI / Backend Unit Tests (push) Failing after 2m44s
SvelteKit's use:enhance resets the form after a successful action.
The name input used value={data.tag.name} without bind:, so Svelte 5's
fine-grained reactivity did not re-apply the unchanged value after the
reset — leaving the field empty. Passing reset: false to update() fixes
this.

Also corrected the confirmation message from "renamed" to "saved" in
all three locales, since the action updates name, parent, and color.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 10:22:54 +02:00
Marcel
654575bf16 feat(#248): add admin_tag_merge_target_placeholder and admin_tag_merge_success i18n keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 08:05:50 +02:00
Marcel
ba8758c085 fix(#248): mode-aware delete button text in TagDeleteGuard and fix document.querySelector in spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 00:58:50 +02:00
Marcel
7919ba3a57 fix(#248): address PR review concerns — i18n, aria-label, stable keys, test selectors
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m37s
CI / Backend Unit Tests (push) Failing after 2m48s
CI / Unit & Component Tests (pull_request) Failing after 2m35s
CI / Backend Unit Tests (pull_request) Failing after 2m49s
- 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>
2026-04-17 00:24:53 +02:00
Marcel
e01733eaf2 feat(#248): add TAG_NOT_FOUND/MERGE_SELF/MERGE_INVALID_TARGET to errors.ts and all i18n keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 22:38:28 +02:00
Marcel
39ed66c97f feat(#221): add i18n keys and error codes for tag hierarchy errors
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>
2026-04-16 16:51:03 +02:00
Marcel
b0c6d15f99 fix(#240): rename transcription column heading to "Text transkribieren"
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m26s
CI / Backend Unit Tests (pull_request) Failing after 2m41s
CI / Unit & Component Tests (push) Failing after 2m26s
CI / Backend Unit Tests (push) Failing after 2m41s
"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>
2026-04-16 13:37:46 +02:00
Marcel
e808525312 fix(#240): rename segmentation column heading to "Text markieren"
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m30s
CI / Backend Unit Tests (push) Has been cancelled
CI / Unit & Component Tests (push) Has started running
CI / Backend Unit Tests (pull_request) Failing after 2m40s
"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>
2026-04-16 13:35:56 +02:00
Marcel
ca0cf4903c refactor(#240): remove needsExpert feature completely
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m23s
CI / Backend Unit Tests (pull_request) Failing after 2m43s
CI / Backend Unit Tests (push) Has been cancelled
CI / Unit & Component Tests (push) Has started running
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>
2026-04-16 10:52:14 +02:00
Marcel
9fb1821db5 fix(#240): remove CTA buttons and dead i18n keys from Mission Control Strip
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m29s
CI / Backend Unit Tests (pull_request) Failing after 2m41s
CI / Backend Unit Tests (push) Has been cancelled
CI / Unit & Component Tests (push) Has started running
The enrich page already handles task routing; the buttons in the
segmentation and transcription columns were redundant. Removes the
unused mission_control_segmentation_cta, mission_control_transcription_cta,
and mission_control_ready_all_cta keys from all three locale files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:42:18 +02:00
Marcel
94b5d1a5a8 fix(#240): align Mission Control Strip UI with final spec
- Strip heading: "Mitarbeiten" → "Was braucht Aufmerksamkeit?"
- Column 1 heading: "Segmentierung" → "Rahmen einzeichnen"; add green
  skill pill "✓ Ohne Vorkenntnisse"; heading color gray → ink (navy)
- Column 2 heading: "Transkription" → "Text eintippen"; add navy skill
  pill "Kurrent hilfreich"; heading color gray → ink; weekly pulse
  color green → ink (task, not achievement); progress bar track
  bg-gray-200/h-1.5 → bg-ink/20/h-1; add transition-all to fill
- Column 3 heading: "Lesefertig" → "Lesefertig ✓"; heading color
  gray → green-800; add "N Dokumente bereit" subtitle in green; add
  "Alle N lesen →" link at bottom; reviewed % color gray → green-800
- All columns: add CTA buttons at bottom (Jetzt einzeichnen /
  Jetzt tippen); empty state removed from cols 1 & 2 (columns
  hide when empty); empty-state ghost CTA in col 3 restyled as
  bordered button with hover:bg-ink
- Strip: add visibility guard — hides when all three lists are empty
- i18n: add mission_control_seg_skill_pill, mission_control_trans_skill_pill,
  mission_control_ready_subtitle, mission_control_ready_all_cta in
  de/en/es; update heading and CTA copy in all three locales

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:42:18 +02:00
Marcel
f36bebd1a8 feat(#240): Mission Control Strip frontend — 5 components + dashboard wiring
Adds the full-width 3-column collaboration widget below the existing
dashboard grid. Renders without the backend running (Promise.allSettled
isolation keeps failures silent).

Components (src/lib/components/):
- ExpertBadge.svelte — purple pill with icon, no props
- SegmentationColumn.svelte — col 1: links to /enrich/{id}, weekly pulse
- TranscriptionColumn.svelte — col 2: per-doc progress bar when blocks exist
- ReadyColumn.svelte — col 3: mint border when filled, dashed empty state
- MissionControlStrip.svelte — strip wrapper, 1-col mobile / 3-col sm+

i18n: 19 new keys added to de/en/es (mission_control_*)

Page wiring:
- +page.server.ts: 4 new Promise.allSettled calls for segmentation-queue,
  transcription-queue, ready-to-read, weekly-stats; all failures silent
- +page.svelte: MissionControlStrip rendered below the grid in isDashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:42:07 +02:00
Marcel
eb18d4f568 feat(search): restyle highlights to navy underline and add snippet labels
Switch search match highlights from bordered mint chips to a plain navy
underline (decoration-brand-navy). Add visible "Inhalt" / "Content" /
"Contenido" label before the transcription snippet, matching the style
of the Von/An sender-receiver labels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 09:10:10 +02:00
Marcel
7fb6ec04ab fix(i18n): replace hardcoded German edit hint in CommentMessage with Paraglide key
Adds comment_edit_hint key to de/en/es message files and replaces the
hardcoded "Enter speichern · Esc abbrechen" string in CommentMessage.svelte.

Fixes @felixbrandt + @leonievoss: "hardcoded German bypasses Paraglide"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:14:14 +02:00
Marcel
731cdc75ab refactor(frontend): delete dead conversations/ route (#193)
Remove the old conversations page that was superseded by briefwechsel/.
No navigation link pointed to /conversations; it was unreachable through
the UI. Deletes 5 files, removes 14 orphaned i18n keys from de/en/es
message bundles, and removes E2E tests that navigated to /conversations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 12:43:40 +02:00
Marcel
34a97cbfa2 i18n: add docs_group_undated and docs_group_unknown translation keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 23:21:43 +02:00