Commit Graph

365 Commits

Author SHA1 Message Date
Marcel
2b8032524d fix(nav): restore DocumentTopBar back button sizing and add right padding
- BackButton gains showLabel prop: showLabel=false renders icon-only with
  aria-label, no mr-2 on svg (was causing 0px button width in topbar)
- DocumentTopBar: BackButton restored to h-11 w-11 circular touch target
  with showLabel=false matching the original 44×44px <a> it replaced
- Topbar row gets pr-4 (16px right padding per spec); action buttons div
  no longer needs its own pr-3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 14:34:31 +02:00
Marcel
9e59da598e fix(nav): replace static href="/" in DocumentTopBar with <BackButton>
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m46s
CI / OCR Service Tests (pull_request) Successful in 39s
CI / Backend Unit Tests (pull_request) Failing after 3m2s
CI / Unit & Component Tests (push) Failing after 2m46s
CI / OCR Service Tests (push) Successful in 27s
CI / Backend Unit Tests (push) Failing after 2m44s
The document detail page back button was missed in the original refactor —
it still pointed to "/" (dashboard) regardless of where the user came from.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 11:27:03 +02:00
Marcel
367dcc66f2 refactor(nav): add class prop to BackButton, remove mb-4 from topbar contexts
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m41s
CI / OCR Service Tests (push) Successful in 37s
CI / Backend Unit Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Failing after 2m44s
CI / OCR Service Tests (pull_request) Successful in 32s
CI / Backend Unit Tests (pull_request) Failing after 2m51s
- BackButton now accepts a `class` prop (default 'mb-4') so callers can
  override spacing; resolves hardcoded margin in flex-row topbar snippets
- documents/[id]/edit and enrich/[id] pass class="" to suppress the margin
- Replace weak className unit test with class-prop behaviour tests
- Add [data-hydrated] comment in E2E spec explaining what emits the attribute

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 11:16:49 +02:00
Marcel
781c4ffebb feat(nav): add BackButton component calling history.back()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 10:46:41 +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
a76af739e5 test(notification-bell): cover handleMarkRead annotationId and commentId-only paths
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 18:37:18 +02:00
Marcel
a15e4e139b test(chronik-row): add coverage for commentId-only URL when annotationId absent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 18:34:41 +02:00
Marcel
e175e050f9 feat(chronik-row): deep-link COMMENT_ADDED and MENTION_CREATED to comment
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m55s
CI / OCR Service Tests (push) Successful in 37s
CI / Backend Unit Tests (push) Failing after 2m50s
CI / Unit & Component Tests (pull_request) Failing after 2m38s
CI / OCR Service Tests (pull_request) Successful in 34s
CI / Backend Unit Tests (pull_request) Failing after 2m51s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 17:38:50 +02:00
Marcel
95c11b9b46 feat(chronik-fuer-dich): include annotationId in mention deep-link
Sidebar was constructing /documents/:id?commentId=… without the
annotationId, so clicking a mention there no-op'ed the deep-link
scroll helper. Route the href through buildCommentHref so the
bell and the chronik sidebar produce identical URLs.

Refs #300.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:21:16 +02:00
Marcel
7c22e42b8f refactor(notification-bell): use buildCommentHref helper
Drops the inline conditional href construction in favour of the
shared helper. Identical URL shape — behaviour preserved.

Refs #300.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:17:57 +02:00
Marcel
20ae85f879 feat(comment): expose comment id + focus ring on CommentMessage wrapper
Notification deep-link scroll targets #comment-{id}. Add the id to
the article wrapper along with tabindex="-1" so scrollIntoView +
.focus({preventScroll:true}) can land screen-reader and keyboard
focus on the specific comment. A focus-visible ring appears only
for keyboard users so mouse clicks don't trigger a visible outline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:32:04 +02:00
Marcel
35303831f7 a11y(dashboard): larger dismiss target + motion-reduce + sr-only PDF label
- UploadSuccessBanner dismiss button: 24×24 → 40×40 hit area (icon stays
  at 16px). Matches senior-first baseline Leonie flagged.
- DashboardNeedsMetadata chevron: adds motion-reduce:transition-none and
  motion-reduce:group-hover:translate-x-0 so users with prefers-reduced-
  motion do not see the hover translate.
- Row title prefixed with an sr-only "PDF: " span so assistive tech
  announces the document affordance alongside the title.

Addresses Leonie's review concerns #2, #3, and the sr-only nit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:44:45 +02:00
Marcel
30ea1f0dcf test(dashboard): exercise the EnrichmentBlock skeleton branch
Hoists the $navigating store into a shared __mocks__ module so tests can
drive it through real transitions. Adds two specs covering (a) skeleton
visible while $navigating && topDocs empty and (b) skeleton hidden when
topDocs is non-empty. Also sets aria-busy="true" on the skeleton so
screen readers announce the loading state (Leonie's a11y suggestion).

Addresses Sara's and Felix's review concern that the skeleton branch was
dead code in the test world.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:36:41 +02:00
Marcel
e824e23c8c feat(dashboard): add EnrichmentBlock wrapper component
Composes UploadSuccessBanner + DashboardNeedsMetadata and reserves a
360px skeleton while \$navigating re-runs the loader with a fresh
incomplete list. Prevents the layout-shift jump after a batch upload
(Leonie's resolved decision #3 on issue #296).

Renders nothing when there is nothing to show — keeps the clean empty
dashboard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:58:05 +02:00
Marcel
b29125615f feat(dashboard): add UploadSuccessBanner component
Transient post-upload banner for issue #296: singular/plural German copy,
aria-live=polite for screen readers, manual X dismiss, 8s auto-dismiss.
"Jetzt ergänzen →" CTA links directly to /enrich so seniors can continue
straight into the enrichment flow after a batch upload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:53:28 +02:00
Marcel
01e72611f0 feat(dashboard): redesign needs-metadata with row anatomy + totalCount
Switches to two props — topDocs (max 5, capped by caller) and totalCount —
so the footer link can surface "Alle 12 anzeigen →" even when only 5
items are shown. Each row gets a generic document icon, title, relative
upload time and a chevron, wrapped in a single <a> per the issue spec.

Still returns null when topDocs is empty, keeping the empty dashboard
clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:34:23 +02:00
Marcel
f68c892170 fix(chronik): sentinel-based title split + drop duplicate comment preview
Two PR #288 blockers from Felix and Leonie:

Felix: verbText.indexOf(docTitle) broke when the title was empty (indexOf
returned 0, the before/after slices both emptied) or when the title
substring-matched any word in the compiled Paraglide message (e.g. "Brief"
appearing inside a translated verb). Swap to a sentinel approach: interpolate
{doc} with U+0001, then split the compiled text on that sentinel — robust
regardless of title content or translator sentence order. Two new red tests
lock the invariant: empty title still renders the row link; short titles
that could substring-match render exactly once as a single chronik-doc-title
span.

Leonie: the comment variant rendered „{documentTitle}" as a placeholder,
which made the row show the same title twice — once as the underlined link,
once as the italic "preview quote" — implying the comment was quoting
itself. Replace with an italic ellipsis „…". A new red test asserts the
preview no longer contains the document title text verbatim.

While here, add a SECURITY comment next to the TODO so the next person who
wires item.commentPreview knows the backend must truncate/strip server-side
and the frontend must use {text}, never {@html} (Nora, issue #285 #3552).

Part of #285, address PR #288 review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
58ea2f827a fix(chronik): split Für-dich row markup — Dismiss is sibling of link, not nested
HTML5 forbids interactive content (<button>, <a>, <input>...) as descendants
of <a>. The original <a href=…><button>✓</button></a> markup triggered two
concrete bugs flagged by Felix, Nora, and Leonie in PR #288 review:

- Browsers inconsistently route the nested click: on some engines the
  stopPropagation() still bubbles, and the user navigates into the document
  instead of dismissing.
- The senior audience (60+) tap-selects with a slight drag, and the OS
  treats the interaction as anchor vs. button inconsistently — a
  reproducible usability failure Leonie has seen in testing before.

Refactor to the Option-C layout from issue #285 comment #3573: outer <li>
flex container, <a> wrapping avatar + body + time, <button> as a sibling.
Independent focus stops, invalid-HTML gone, no behavioural regression.

A new spec locks the invariant: `dismiss.closest('a')` must be null.

Part of #285, address PR #288 review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
93c80671e2 fix(notifications): retarget bell dropdown footer to /chronik
The "Alle anzeigen" link at the bottom of the notification dropdown now
points to /chronik with the new "Zur Chronik →" label key, matching the
unified activity page introduced in #285.

Part of #285.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
81f86474b6 fix(dashboard): retarget feed footer to /chronik + render rollup rows
- "Alle anzeigen" link now goes to /chronik (was /documents — the dead-end
  bug called out in #285).
- Rollup rows (count > 1) render a primary-colored count badge plus a
  compound timestamp line: "14. Apr. · 14:02–14:32" (en-dash U+2013).
- Singleton rows render the existing "14. Apr. 2026" date line.
- BLOCK_REVIEWED now has a verb mapping (re-using the annotation verb until
  the spec pins a distinct copy).
- Three new spec cases: rollup count badge + en-dash range, no badge on
  singletons, /chronik link assertion.

Part of #285.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
e36c9382fc feat(chronik): add six Chronik page components + co-located specs (40 tests)
All under src/lib/components/chronik/:

- ChronikRow.svelte — single orchestrator for four variants (comment / for-you /
  rollup / simple), discriminated via $derived. Outer <a> wraps avatar + body +
  time; document title is a styled <span> (no nested anchors). Rollup shows
  count badge + en-dash time range; for-you gets accent left border + @ marker
  hidden below sm:.
- ChronikTimeline.svelte — buckets items by day using bucketByDay() and renders
  Heute/Gestern/Diese Woche/Älter section headers with <span> trailing rule.
- ChronikFuerDichBox.svelte — unread mentions card with inbox-zero variant,
  per-row Dismiss button (prevents bubbling, calls onMarkRead), aria-live count
  badge, and a .fade-in class gated by prefers-reduced-motion.
- ChronikFilterPills.svelte — role=radiogroup with 5 pills, ArrowLeft/Right
  keyboard navigation wrapping across the group, single tabstop via dynamic
  tabindex.
- ChronikEmptyState.svelte — three variants (first-run / filter-empty /
  inbox-zero) sharing a centered-column layout.
- ChronikErrorCard.svelte — warning card with retry button, optional custom
  message override.

Verbs map to chronik_singleton_* / chronik_rollup_* per AuditKind so no ICU
pluralization is needed. Comment preview is a TODO placeholder (currently the
document title) pending a backend preview DTO follow-up.

All 40 unit tests green. No type-check or lint errors in these files.

Part of #285.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
f13b2a984e fix(notifications): retarget NotificationItem import to singleton store
Left over from the hook→singleton refactor — NotificationDropdown still
imported from the deleted $lib/hooks path.

Part of #285.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
5fc39b0371 refactor(notifications): convert per-component stream hook to module-level singleton
Replaces the per-component createNotificationStream() factory with a shared
$lib/stores/notifications.svelte.ts singleton. Ref-counted init()/destroy()
ensures one EventSource per tab no matter how many consumers mount
simultaneously.

Motivation: the /chronik "Für dich" box (#285) needs the same live-arrival
stream that NotificationBell already consumes. Two factories would open two
SSE connections per tab — this refactor avoids the silent regression before
it ships.

- New: src/lib/stores/notifications.svelte.ts (module state, refcount)
- New: src/lib/stores/notifications.svelte.spec.ts (proves single EventSource
  across multiple consumers + ref-counted teardown)
- Deleted: src/lib/hooks/useNotificationStream.svelte.ts (factory)
- Deleted: src/lib/hooks/__tests__/useNotificationStream.svelte.test.ts
- NotificationBell now imports the singleton

Part of #285.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:38:10 +02:00
Marcel
eb3a54b19c fix(document-row): align contributor circles with progress ring
The ProgressRing renders SVG + percentage label as a flex column (~52px
total). With items-center, the contributor circles aligned to the middle
of the full block, placing them 8px below the ring center. Changed to
items-start on the container and wrapped ContributorStack in h-9 (36px =
SVG height) flex items-center so both circles center at the same 18px.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:29:33 +02:00
Marcel
4e1d0b1cf0 chore: merge main into feat/issue-281-documents-page
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m39s
CI / OCR Service Tests (pull_request) Successful in 29s
CI / Backend Unit Tests (pull_request) Failing after 2m50s
CI / Unit & Component Tests (push) Failing after 2m31s
CI / OCR Service Tests (push) Successful in 31s
CI / Backend Unit Tests (push) Failing after 2m52s
Resolved 9 conflicts:
- AuditLogQueryRepository/Service: keep HEAD (findRecentContributorsForDocuments)
- ContributorStack: merge main key fix + text-[10px] with HEAD safeColor + aria
- DashboardResumeStrip: merge main text-[10px] with HEAD safeColor
- +page.server/svelte + tests: keep HEAD (pure dashboard, no isDashboard)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 08:54:17 +02:00
Marcel
55ce696428 fix(dashboard): fix ContributorStack each-block key and add accessible avatar labels
- Replace (actor.name ?? actor.initials + i) with (actor.initials + '-' + actor.color)
  to fix operator-precedence bug that made keys order-dependent when name is null
- Add role="img" + aria-label={actor.name ?? actor.initials} so screen readers
  and touch users can access contributor names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:45:16 +02:00
Marcel
3ede42503a fix(dashboard): i18n, a11y, security, and type-safety fixes from PR review
- Use @RequiredArgsConstructor in AuditLogQueryService; remove unused import
- Add 401/403 tests for /activity endpoint
- Add getPulseStats and findContributorsPerDocument integration tests
- Use m.pulse_headline/pulse_you in FamilyPulse; composite avatar keys
- Replace hover:text-accent with hover:text-ink in ActivityFeed (WCAG AA)
- Localise "Alle →" link with feed_show_all key + aria-label
- Gate DropZone behind {#if data.canWrite}
- Export DashboardResumeDTO, DashboardPulseDTO, ActivityFeedItemDTO from api.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:45:16 +02:00
Marcel
117044aad9 docs(spec): add /documents page design spec with mobile breakpoints
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:45:16 +02:00
Marcel
eac025dec1 feat(dashboard): show block count instead of page numbers in resume strip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:45:16 +02:00
Marcel
7506f8743a fix(dashboard): defensive null guard in ContributorStack; fix spec makeDoc factories 2026-04-20 07:45:16 +02:00
Marcel
520cca58b8 feat(dashboard): show contributor pill stack on each mission control queue item
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:45:16 +02:00
Marcel
4bd1ebfd1e feat(dashboard): add ContributorStack component for mission control pill stacks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:45:16 +02:00
Marcel
5a98edac86 feat(dashboard): complete frontend redesign for Issue #271
- +layout.svelte: Upload button in header (authenticated users only)
- +page.server.ts: call /api/dashboard/resume, /pulse, /activity;
  remove deprecated /api/documents/incomplete and /recent-activity
- +page.svelte: 2-col grid layout (main + 320px sidebar), greeting,
  DashboardFamilyPulse + DashboardActivityFeed in sidebar
- DashboardResumeStrip: refactored to use server data (resumeDoc prop),
  SVG thumbnail, progress bar with aria-*, empty state, CTA
- DashboardFamilyPulse: new component — weekly stats from audit_log
- DashboardActivityFeed: new component — activity feed with "für dich" badge
- Update specs for new data shapes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 07:45:16 +02:00
Marcel
da2ece986a fix(documents): WCAG text-size and API error pattern fixes
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m37s
CI / OCR Service Tests (pull_request) Successful in 29s
CI / Unit & Component Tests (push) Failing after 2m44s
CI / OCR Service Tests (push) Successful in 38s
CI / Backend Unit Tests (push) Failing after 2m45s
CI / Backend Unit Tests (pull_request) Failing after 2m45s
- DashboardResumeStrip: text-[10px] → text-xs on collaborator initials (WCAG 1.4.4)
- documents/+page.server.ts: use !result.response.ok per CLAUDE.md; keep narrow try/catch for network-level failures only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 01:17:04 +02:00
Marcel
f2bed92176 fix(review): cycle 3 — a11y, CSS injection, domain boundary
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m44s
CI / OCR Service Tests (push) Successful in 34s
CI / Unit & Component Tests (pull_request) Failing after 2m33s
CI / OCR Service Tests (pull_request) Successful in 35s
CI / Backend Unit Tests (push) Failing after 2m56s
CI / Backend Unit Tests (pull_request) Failing after 2m48s
- DocumentRow: add data-testid="search-snippet"; sanitize tag.color with safeTagColor()
- ContributorStack: add role="img" aria-label to overflow "…" badge
- DocumentList: year header text-[10px] → text-xs (WCAG 1.4.4 minimum 12px)
- DashboardResumeStrip: sanitize collab.color with safeColor()
- Extract TranscriptionBlockQueryService to fix cross-domain repository access in DocumentService
- Update unit test mocks to use TranscriptionBlockQueryService

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 01:03:06 +02:00
Marcel
7f23e88b69 fix(documents): address review cycle 2 — a11y, CSS injection, debounce tests
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m33s
CI / OCR Service Tests (pull_request) Successful in 38s
CI / Unit & Component Tests (push) Failing after 2m40s
CI / OCR Service Tests (push) Successful in 36s
CI / Backend Unit Tests (push) Failing after 2m54s
CI / Backend Unit Tests (pull_request) Failing after 2m58s
- ContributorStack: text-xs for WCAG 1.4.4 (was text-[10px]), safeColor()
  validation to block CSS injection via actor.color, role="img" aria-label
  on empty placeholder, {#each} keyed by index
- ContributorStack spec: update empty-state assertion to getByRole('img')
- DocumentRow spec: add stopPropagation regression test for tag click
- documents/page.svelte.spec.ts: new — debounce, URL building, initial state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 00:40:48 +02:00
Marcel
dc349947ef fix(a11y): add aria-hidden to decorative SVG and use text-xs for WCAG 12px minimum
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 00:24:36 +02:00
Marcel
80e10e1755 fix(docs): stop tag click propagation to prevent parent anchor navigation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 00:23:48 +02:00
Marcel
3707d34c62 test(docs): add DocumentRow unit tests — title, snippet, tags, sender, progress ring
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 00:23:08 +02:00
Marcel
648aa2a742 feat(frontend): add DocumentRow component with two-column layout, highlights, progress, contributors
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 23:44:31 +02:00
Marcel
ae0e3b271d feat(frontend): add ProgressRing component — SVG progress arc with percentage label
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 23:34:30 +02:00
Marcel
eeca30e7a6 feat(frontend): add --header-height, bump initials to text-[10px], update nav to /documents
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 23:24:46 +02:00
Marcel
5246638014 fix(dashboard): fix ContributorStack each-block key and add accessible avatar labels
- Replace (actor.name ?? actor.initials + i) with (actor.initials + '-' + actor.color)
  to fix operator-precedence bug that made keys order-dependent when name is null
- Add role="img" + aria-label={actor.name ?? actor.initials} so screen readers
  and touch users can access contributor names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 22:28:00 +02:00
Marcel
2bb08b6877 fix(dashboard): i18n, a11y, security, and type-safety fixes from PR review
- Use @RequiredArgsConstructor in AuditLogQueryService; remove unused import
- Add 401/403 tests for /activity endpoint
- Add getPulseStats and findContributorsPerDocument integration tests
- Use m.pulse_headline/pulse_you in FamilyPulse; composite avatar keys
- Replace hover:text-accent with hover:text-ink in ActivityFeed (WCAG AA)
- Localise "Alle →" link with feed_show_all key + aria-label
- Gate DropZone behind {#if data.canWrite}
- Export DashboardResumeDTO, DashboardPulseDTO, ActivityFeedItemDTO from api.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 21:43:16 +02:00
Marcel
148710f2ed docs(spec): add /documents page design spec with mobile breakpoints
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m35s
CI / OCR Service Tests (push) Successful in 27s
CI / Backend Unit Tests (push) Failing after 1m26s
CI / OCR Service Tests (pull_request) Successful in 31s
CI / Backend Unit Tests (pull_request) Failing after 1m28s
CI / Unit & Component Tests (pull_request) Failing after 2m33s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 21:39:56 +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
64c5b40eae fix(dashboard): defensive null guard in ContributorStack; fix spec makeDoc factories 2026-04-19 19:22:52 +02:00
Marcel
0c65d5d748 feat(dashboard): show contributor pill stack on each mission control queue item
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 19:10:16 +02:00
Marcel
031f6ea29a feat(dashboard): add ContributorStack component for mission control pill stacks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 19:06:46 +02:00