Commit Graph

678 Commits

Author SHA1 Message Date
Marcel
902172e4e2 fix(#248): fix 3 merge zone bugs — stale state, wrong placeholder, missing success feedback
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m41s
CI / Backend Unit Tests (pull_request) Failing after 2m34s
CI / Unit & Component Tests (push) Failing after 2m21s
CI / Backend Unit Tests (push) Failing after 2m35s
- TagMergeZone: add $effect to reset targetId when tag prop changes (fixes stale form after navigation)
- TagMergeZone: pass merge-specific placeholder to TagParentPicker
- TagMergeZone: show success banner on form.mergeSuccess and goto() target tag
- +page.server.ts: merge action returns { mergeSuccess, mergeTargetId } instead of redirect

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 08:12:35 +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
b5ea04e47a feat(#248): add optional placeholder prop to TagParentPicker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 08:04:16 +02:00
Marcel
3cd6483042 fix(#248): replace focus:outline-none with focus-visible ring on TagParentPicker clear button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 07:43:38 +02:00
Marcel
aff7afa7cb fix(#248): resolve parent UUID to name in TagParentPicker dropdown subtitle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 07:42:13 +02:00
Marcel
be7009f9ed fix(#248): replace document.querySelectorAll with page.getByRole in TagDeleteGuard spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 07:39:06 +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
61976e9479 fix(#248): increase tree-node indent from 12px to 16px for better scanability
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 00:43:44 +02:00
Marcel
901483ab73 fix(#248): complete ARIA combobox pattern in TagParentPicker — role="option", aria-activedescendant, keyboard nav
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 00:42:54 +02:00
Marcel
6f6ff8e9ed fix(#248): add console.error to typeahead catch block and expose setActiveIndex
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 00:37:18 +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
172c5613ed feat(#248): overhaul tag edit page — TagParentPicker, new components, merge+subtree actions
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m51s
CI / Backend Unit Tests (push) Failing after 2m46s
CI / Unit & Component Tests (pull_request) Failing after 2m39s
CI / Backend Unit Tests (pull_request) Failing after 2m58s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 23:46:06 +02:00
Marcel
f1889ff20c feat(#248): add TagDeleteGuard component and brand-warning CSS token
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 23:34:29 +02:00
Marcel
4d670de156 feat(#248): add TagMergeZone component with 2-step merge flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 23:30:28 +02:00
Marcel
b6b1b142dc feat(#248): add TagAncestry and TagChildrenPreview components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 23:26:02 +02:00
Marcel
a3660a79e1 feat(#248): add TagParentPicker combobox component with excludeIds filtering
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 23:16:18 +02:00
Marcel
53d89a44fc refactor(#248): extract typeahead logic into createTypeahead composable, use in PersonTypeahead
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 23:07:59 +02:00
Marcel
83629e0c6e feat(#248): add createTypeahead composable with debounced fetch and selection state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 23:01:33 +02:00
Marcel
97fbf1e4ca feat(#248): replace flat TagsListPanel with collapsible ARIA tree (TagTreeNode)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 22:57:45 +02:00
Marcel
9b5af67780 feat(#248): switch layout load to GET /api/tags/tree, expose tree + flat tags
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 22:40:23 +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
a669f6368d feat(#248): expose parentId in TagTreeNodeDTO OpenAPI schema and regenerate TypeScript types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 22:33:12 +02:00
Marcel
171f06da22 fix(#221): reset parent/color/delete state when navigating between tag edit pages
SvelteKit reuses the same +page.svelte instance on client-side navigation,
so $state() initialisations only run on mount. Add an $effect keyed on
data.tag.id to reset parentId, selectedColor and deleteConfirmName whenever
the user switches to a different tag in the admin sidebar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 19:14:28 +02:00
Marcel
89949977c7 fix(#221): suppress tagQ when tags are already selected
Sending tagQ alongside selected tags caused an unintended AND: documents
had to match both the selected-tag filter and the partial-name filter,
making the list shrink while the user was still typing a new tag.

tagQ is now only forwarded to the backend when no tags are selected,
which is the only case where the live partial-filter is meaningful.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 18:18:25 +02:00
Marcel
532692e0fb fix(#221): bypass debounce on AND/OR operator toggle to prevent race condition
The tag-change $effect called triggerSearch() immediately (no debounce).
When the user toggled AND/OR within the 500 ms debounce window, the prior
navigation would complete and reset tagOperator back to AND before the
debounced search fired. The toggle now calls onSearchImmediate, which
clears any pending timer and fires triggerSearch() synchronously.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 17:24:30 +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
7f53651f13 feat(#221): render tag list hierarchically with indentation and color dots
TagsListPanel now accepts optional parentId/color on each Tag. A
$derived.by walk produces an ordered flat list with depth annotations.
Child tags are indented with pl-5; root-level tags with a color get
a colored dot before their name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 16:46:55 +02:00
Marcel
d900480920 feat(#221): add parent selector and color picker to admin tag edit form
Tag edit form gains a parent <select> listing all other tags (self
excluded) and a 10-swatch color picker that is only shown when no
parent is selected. Submitting passes parentId and color to the PUT
/api/tags/{id} endpoint via TagUpdateDTO.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 16:39:02 +02:00
Marcel
abba85a451 feat(#221): wire tagOp URL param from server to SearchFilterBar
Reads ?tagOp=OR from URL in +page.server.ts, passes it to the backend
search endpoint, and surfaces it via the filters return. +page.svelte
initialises tagOperator state from filters, writes it back to the URL
in triggerSearch(), and binds it to SearchFilterBar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 16:25:27 +02:00
Marcel
b54d2b0125 feat(#221): add AND/OR pill toggle to SearchFilterBar tag filter
Toggle appears when ≥2 tags are selected; defaults to AND.
Exposes tagOperator prop ('AND'|'OR') for parent to read via bind.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 16:20:21 +02:00
Marcel
e03fb38274 feat(#221): add color dot to tag chips in DocumentList
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 16:14:32 +02:00
Marcel
e8e54cc282 feat(#221): change TagInput binding to Tag[], add color dots and hierarchy grouping
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>
2026-04-16 16:11:38 +02:00
Marcel
e4f21bd896 feat(#221): add --c-tag-* CSS custom properties for 10 semantic tag color tokens
Light and dark variants for: sage, sienna, amber, slate, violet, rose,
cobalt, moss, sand, coral — used as decorative dot colors on tag chips.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 15:50:13 +02:00
Marcel
c3e007d421 chore(#221): regenerate TypeScript API types with Tag hierarchy fields
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>
2026-04-16 15:48:37 +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
da5c92fe39 fix(#240): remove readyCount from weekly stats DTO and SQL query
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m26s
CI / Backend Unit Tests (push) Failing after 2m46s
CI / Unit & Component Tests (pull_request) Failing after 2m32s
CI / Backend Unit Tests (pull_request) Failing after 2m30s
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>
2026-04-16 13:19:53 +02:00
Marcel
6c2da648db fix(#240): remove weekly pulse badge from ReadyColumn
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m32s
CI / Backend Unit Tests (push) Failing after 2m45s
CI / Unit & Component Tests (pull_request) Failing after 2m27s
CI / Backend Unit Tests (pull_request) Failing after 2m46s
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>
2026-04-16 13:12:46 +02:00
Marcel
ca660f103d test(#240): add component tests for all four Mission Control Strip components
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m29s
CI / Backend Unit Tests (pull_request) Failing after 2m37s
CI / Unit & Component Tests (push) Failing after 2m21s
CI / Backend Unit Tests (push) Failing after 2m38s
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>
2026-04-16 12:36:33 +02:00
Marcel
06eb1cada8 refactor(#240): deduplicate formatDate, use generated types, always-visible strip
- 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>
2026-04-16 12:28:20 +02:00
Marcel
d78685c5a4 fix(#240): accessibility, color consistency, and reviewedPct denominator
- 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>
2026-04-16 12:25:36 +02:00
Marcel
23410aa4b8 fix(#240): rename V37→V38 (V37 was already applied); regenerate api.ts
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>
2026-04-16 12:23:14 +02:00
Marcel
ff1606f63d fix(#240): update test fixtures broken by rebase changes
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m29s
CI / Backend Unit Tests (push) Failing after 2m38s
CI / Unit & Component Tests (pull_request) Failing after 2m31s
CI / Backend Unit Tests (pull_request) Failing after 2m42s
Two backend tests passed a 6-element enrichment row but the rebase
added summary_snippet as column 7 — added null at index 6 to both
fixtures.

Two frontend page.server tests mocked only 4 dashboard API calls but
the page now makes 8 (3 Mission Control queues + weekly-stats added
on this branch) — added the 4 missing mock responses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 11:50:49 +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
86a216918f fix(#240): make Mission Control Strip dark-mode compatible
Replace all hardcoded Tailwind colours with semantic tokens:
- bg-white → bg-surface (outer strip container)
- text-gray-400 → text-ink-3 (dates, meta text, empty-state copy)
- text-green-800 / text-green-700 → text-ink / text-ink-2 (headings, pulse, reviewed %)
- bg-green-50 / border-green-200 → bg-accent-bg / border-line (skill pill, weekly pulse badge)
- bg-ink text-white → bg-primary text-primary-fg (CTA buttons; dark: mint bg + navy text)
- hover:text-white → hover:text-primary-fg (ghost CTA hover text)
- focus-visible:ring-brand-navy → focus-visible:ring-focus-ring (all doc links)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:42:18 +02:00
Marcel
48152517aa fix(#240): fix invisible hover on column 1 & 2 doc links
brand-sand/30 on white background is near-invisible; use full
hover:bg-brand-sand instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:42:18 +02:00
Marcel
4af2e4ad17 fix(#240): remove dead "Alle lesen" link and add hover shadow to ReadyColumn
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
aa8fb70d10 fix(#240): redirect Mission Control Strip links to document detail page
The /enrich route is for metadata (title, date, sender/receiver).
Segmentation and transcription work happens on the document detail page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:42:18 +02:00