Commit Graph

1336 Commits

Author SHA1 Message Date
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
6c99c6a670 test(nav): add E2E tests for BackButton navigation and accessibility
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m47s
CI / OCR Service Tests (pull_request) Successful in 31s
CI / Unit & Component Tests (push) Failing after 2m39s
CI / OCR Service Tests (push) Successful in 40s
CI / Backend Unit Tests (push) Failing after 2m52s
CI / Backend Unit Tests (pull_request) Failing after 3m7s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 11:00:56 +02:00
Marcel
ae3bc3f246 docs(claude): update back link pattern to use BackButton component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 10:50:35 +02:00
Marcel
cc9c47254b refactor(nav): replace static back-link hrefs with BackButton
All 7 in-scope back navigation links converted to use history.back().
Admin panel mobile chevron converted inline (icon-only, different
visual pattern). Cancel buttons left as static <a> links.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 10:49:23 +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
ba0f9bb325 refactor(test): fix unchecked cast and derive ALL_ELIGIBLE_KINDS from enum
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m36s
CI / OCR Service Tests (pull_request) Successful in 29s
CI / Backend Unit Tests (pull_request) Failing after 2m46s
CI / Unit & Component Tests (push) Failing after 2m43s
CI / OCR Service Tests (push) Successful in 31s
CI / Backend Unit Tests (push) Failing after 2m51s
- Replace any(Set.class) with any() to eliminate the raw-type unchecked
  cast in DashboardControllerTest
- Derive ALL_ELIGIBLE_KINDS from AuditKind.ROLLUP_ELIGIBLE.stream() so
  the integration test constant stays in sync with the production constant
  automatically when new kinds are added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 22:45:23 +02:00
Marcel
c0e52b8432 refactor(audit): move AuditLogQueryServiceTest to audit package
Addresses review concern: the test lived in the dashboard package but
tests the audit domain service. Package-by-feature convention requires
audit tests to live in the audit package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 22:44:37 +02:00
Marcel
42cf7715d2 test(chronik): extract applyClientFilter helper with full test coverage
Addresses review concern: the fuer-dich predicate (youMentioned ||
youParticipated) had zero test coverage after feedFilters.test.ts was
deleted. The new clientFilter module is a pure function that is directly
testable, and the test explicitly documents why MENTION_CREATED items
without the youMentioned flag are now excluded (they would have shown
mentions directed at OTHER users under the old feedFilters.ts logic).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 22:43:52 +02:00
Marcel
330c6227bc refactor(chronik): remove client-side filter; add aria-live/aria-busy
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m51s
CI / OCR Service Tests (push) Successful in 36s
CI / Backend Unit Tests (push) Failing after 3m3s
CI / Unit & Component Tests (pull_request) Failing after 2m39s
CI / OCR Service Tests (pull_request) Successful in 28s
CI / Backend Unit Tests (pull_request) Failing after 2m50s
- Delete feedFilters.ts and its 9 tests (dead code: server now filters)
- Remove activeFilter $state + $effect — read data.filter directly
- fuer-dich stays client-side via youMentioned/youParticipated predicate
- aria-live="polite" + aria-busy={!!navigating.type} on timeline region

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 22:26:27 +02:00
Marcel
d42293d3f5 feat(chronik): pass kinds query param from filter pill to API
Each filter pill maps to a specific set of AuditKinds sent as
?kinds= to /api/dashboard/activity. fuer-dich omits kinds so the
server returns all eligible events; client-side predicate on
youMentioned/youParticipated handles the final narrowing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 22:20:45 +02:00
Marcel
99c3106835 feat(openapi): expose kinds param in dashboard activity spec
Added @Parameter annotation so SpringDoc renders kinds as an
enum-array query param; regenerated TypeScript API types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 21:19:16 +02:00
Marcel
8d16e4d975 feat(dashboard): add kinds param to GET /api/dashboard/activity
Spring auto-converts ?kinds=FILE_UPLOADED,TEXT_SAVED to Set<AuditKind>.
Absent or empty kinds defaults to ROLLUP_ELIGIBLE. Unknown value → 400.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 21:10:43 +02:00
Marcel
571ecfc626 test(dashboard): guard getPulse always uses 2-arg findActivityFeed
Regression test: getPulse must never receive a kinds filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 21:05:43 +02:00
Marcel
475e16a85d feat(audit): add findActivityFeed(UUID, int, Set<AuditKind>) overload
Two-arg variant delegates to three-arg with ROLLUP_ELIGIBLE so
existing callers (getPulse) are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 21:03:39 +02:00
Marcel
fe7a8ed9ad feat(audit): add kinds param to findRolledUpActivityFeed
Filter is applied at the innermost events CTE to reduce rows
entering the LAG/session CTEs. Existing callers pass ROLLUP_ELIGIBLE
by default so behaviour is unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 20:59:56 +02:00
Marcel
d700b0a948 refactor(audit): add ROLLUP_ELIGIBLE constant to AuditKind
Single source of truth for the six kinds eligible for the activity rollup feed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 20:53:14 +02:00
Marcel
7d9c7f1357 chore(api): mark manually-patched fields for next regen cycle
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m47s
CI / OCR Service Tests (pull_request) Successful in 31s
CI / Backend Unit Tests (pull_request) Failing after 2m47s
CI / Unit & Component Tests (push) Failing after 2m54s
CI / OCR Service Tests (push) Successful in 39s
CI / Backend Unit Tests (push) Failing after 2m59s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 18:38:16 +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
7f40c54b3f feat(utils): add buildCommentHref helper for comment deep-links
Single source of truth for constructing /documents/:id?commentId=…
(&annotationId=…) URLs. Used by the notification bell, the chronik
"Für dich" sidebar, and the chronik main feed so the three surfaces
can no longer diverge.

Refs #300.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:15:48 +02:00
Marcel
76a3a2e04c chore(api): hand-edit generated types for commentId + annotationId
Adds the two new optional fields on ActivityFeedItemDTO in the
generated openapi-typescript output. Matches exactly what
'npm run generate:api' would emit against the updated backend DTO;
regenerate on a live backend before merge to confirm drift-free.

Refs #300.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:13:56 +02:00
Marcel
f50a746619 feat(dashboard): enrich activity feed DTO with commentId + annotationId
ActivityFeedItemDTO gains nullable commentId and annotationId fields.
DashboardService.getActivity forwards commentId from the projection
and batch-resolves annotationId via the new
CommentService.findAnnotationIdsByIds lookup. Both remain null for
non-comment kinds, so the bulk lookup is skipped entirely when the
feed has no comment rows.

Refs #300.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:11:03 +02:00
Marcel
40260be07a feat(comment): add findAnnotationIdsByIds batch lookup
Exposes a CommentService method that maps a collection of
commentIds to their annotationIds via commentRepository.findAllById.
Unknown comments and comments with null annotationId are omitted.
Used by the dashboard activity feed enrichment to supply the
deep-link annotationId without growing the audit SQL query.

Refs #300.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:04:38 +02:00
Marcel
b9f5ec22aa feat(audit): expose commentId on rolled-up activity feed projection
Adds getCommentId() to ActivityFeedRow and selects
(ag.payload->>'commentId')::uuid from findRolledUpActivityFeed so
chronik consumers can build deep-link URLs for COMMENT_ADDED and
MENTION_CREATED events. Null for other kinds.

Refs #300.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:00:36 +02:00
Marcel
b07f9efa9c fix(document-detail): force edit panel on notification deep-link
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m39s
CI / OCR Service Tests (push) Successful in 30s
CI / Backend Unit Tests (push) Failing after 2m46s
Comments only render inside TranscriptionEditView, so a deep-link
into a document with existing reviewed transcriptions landed the
user in read mode with no comment element in the DOM — the scroll
target silently missed.

scrollToCommentFromQuery now takes a setPanelMode callback and calls
it with 'edit' whenever both query params are present. The page's
own transcribe-mode $effect checks a skipInitialPanelMode flag the
deep-link flow sets, so its default-panel-mode logic doesn't race
against the explicit override.

Two new helper tests pin the contract: panel mode is forced to
'edit' both when transcribe mode is off (entering fresh) and when
it is already on (same-page notification click).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 15:22:38 +02:00
Marcel
3bf0b38c42 polish(document-detail): address review concerns on onMount deep-link wiring
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 2m40s
CI / OCR Service Tests (pull_request) Successful in 30s
CI / Backend Unit Tests (pull_request) Failing after 2m44s
CI / Unit & Component Tests (push) Failing after 2m41s
CI / OCR Service Tests (push) Successful in 37s
CI / Backend Unit Tests (push) Failing after 2m55s
Three small refinements from Felix's review cycle 1:

- replaceState(page.url.pathname, page.state ?? {}) — defend against
  first-navigation cases where page.state can be undefined.
- Extract the inline tick + requestAnimationFrame into a named
  waitForPanelRender() helper; intent is now readable from onMount.
- Attach .catch() to the fire-and-forget scrollToCommentFromQuery
  promise so any helper throw surfaces via console.error instead
  of silently disappearing.

No behavior change on the happy path. All existing tests stay green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 14:10:46 +02:00
Marcel
567faee3cc test(e2e): notification deep-link scrolls to target comment
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m43s
CI / OCR Service Tests (push) Successful in 36s
CI / Backend Unit Tests (push) Failing after 3m0s
CI / Unit & Component Tests (pull_request) Failing after 2m46s
CI / OCR Service Tests (pull_request) Successful in 31s
CI / Backend Unit Tests (pull_request) Failing after 2m45s
Seeds a document, transcription block, and block comment via API,
then visits /documents/{id}?commentId=X&annotationId=Y and asserts
the page enters transcribe mode, the comment article becomes visible,
and the URL query params are stripped. Runs at 320px and 1440px so
the collapsed PDF strip clipping on mobile is caught. An axe-core
pass guards the new tabindex + focus-visible ring against a11y
regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:44:45 +02:00
Marcel
e22265f5bc feat(document-detail): wire notification deep-link scroll in onMount
After navHeight setup, call scrollToCommentFromQuery with the page
URL and callbacks into the component's local state (transcribeMode,
activeAnnotationId, flashAnnotationId) plus SvelteKit's replaceState
to strip the consumed query params.

afterTick awaits both Svelte's tick() and one requestAnimationFrame,
mirroring the existing handleAnnotationClick timing so the annotation
panel has rendered before scrollIntoView fires.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:42:55 +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
251eb9c3fc feat(frontend): add scrollToCommentFromQuery helper for notification deep-link
Pure function that reads commentId + annotationId from the page URL,
enters transcribe mode if needed, activates the block's annotation,
scrolls the target comment into view, focuses it for screen readers,
fires the existing annotation flash, and strips the params via the
injected callback.

All side effects go through callbacks so the helper is unit-testable
without mounting the page or a DOM (only scrollIntoView/focus are
called on the injected element). Eight tests cover both absent params,
happy path, transcribe-mode activation, missing DOM target, reduced
motion, flash trigger, and URL strip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:29:52 +02:00
Marcel
bc69e8ff1e refactor(comment): drop dead document and annotation comment APIs
Only block comments are surfaced by the frontend now. The document-level
and annotation-level comment endpoints and service methods existed but
had no consumer. Remove them along with their repository queries and
test coverage so the surface area matches the actual feature set.

Shared edit, delete, and block reply endpoints stay. postBlockComment
now carries the authorName/mention/audit behaviors previously tested
through the dropped postComment method, so those behaviors remain
covered by the block-scoped test suite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:27:10 +02:00
Marcel
13732ab96b fix(db): V51 backfills annotation_id on block comments and notifications
Previously issued block-comment notifications were stored with
annotation_id=NULL because CommentService.postBlockComment did not
populate DocumentComment.annotationId. Now that the code fix is in
place, existing rows need to be filled in so legacy notifications
can also carry the query param that the frontend deep-link flow
expects.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:13:13 +02:00
Marcel
4658852281 fix(comment): populate annotationId on block comments from the block
postBlockComment now looks up the block via TranscriptionService and
sets comment.annotationId from block.getAnnotationId(). This closes
the upstream root cause of issue #276, where notifications for block
comments were stored with annotationId=null, breaking the notification
deep-link flow on the document detail page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:09:30 +02:00
Marcel
edb4e54df2 fix(audit): backfill COMMENT_ADDED and MENTION_CREATED events
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m40s
CI / OCR Service Tests (push) Successful in 35s
CI / Backend Unit Tests (push) Failing after 2m54s
Comments created before audit logging was added in 428c63a2 have no
corresponding audit_log rows, so the Chronik activity feed (which
reads exclusively from audit_log) cannot surface them in "Alle" or
"Für dich", even though the fix from #295 is wired up correctly.
V50 inserts the missing events idempotently from document_comments
and comment_mentions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 12:08:45 +02:00
Marcel
3744a6ba3c fix(admin): preserve form values after save in user and group edit
SvelteKit's default `use:enhance` behaviour calls `form.reset()` after
a successful non-redirecting action, which wipes inputs that use
`value={...}` (property set, not defaultValue). The edit forms now
pass `reset: false` to `update()` so the saved values stay visible
after the success banner appears.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 12:07:50 +02:00
Marcel
4ec0b9d6c8 fix(admin): rename users edit default action to named update
SvelteKit 2 forbids mixing a `default` action with named actions; the
page also exports a `delete` action. Posting the edit form therefore
returned a 500 with "When using named actions, the default action
cannot be used." Rename the action to `update` and point the form
at `?/update`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 12:06:34 +02:00
Marcel
1fd2fab9a1 refactor(audit): document MIN invariant in aggregated CTE comment
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m43s
CI / OCR Service Tests (push) Successful in 32s
CI / Backend Unit Tests (push) Failing after 2m52s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
53352be997 test(audit): document youParticipated graceful degradation when commentId absent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
dc027cdf40 test(audit): add cross-user scoping regression for youParticipated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
5b3fb8fb3f refactor(test): use ObjectMapper for payload JSON in audit test helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
d154bb4b9c refactor(chronik): replace inline filter switch with filterFeed()
Wire the extracted filterFeed function into the displayFeed derived,
removing 20 lines of inline switch logic from +page.svelte.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
8b74f4ec25 feat(chronik): extract feedFilters.ts with youParticipated in fuer-dich
Extract filterFeed(items, filter) from +page.svelte inline switch to a
pure function, widening the fuer-dich branch to include youParticipated.
Regenerate ActivityFeedItemDTO type to include the new field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
388fc5397c feat(dashboard): expose youParticipated in ActivityFeedItemDTO
Add youParticipated field to the DTO record and wire row.isYouParticipated()
through DashboardService.getActivity().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
454e5f7517 feat(audit): surface youParticipated via REPLY notification subquery
Add you_participated correlated subquery to findRolledUpActivityFeed.
Carries payload through the aggregated CTE via MIN(payload::text)::jsonb
so the commentId can be matched against notifications.reference_id.
Uses CAST(:currentUserId AS uuid) to avoid Spring Data JPA misparsin ::
cast syntax as a parameter name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00
Marcel
9c52e1921f test(audit): add youParticipated and youMentioned repository tests
Add isYouParticipated() to ActivityFeedRow interface and cover four
behaviours in AuditLogQueryRepositoryRolledUpTest: youParticipated
true/false and retroactive youMentioned true/false coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 09:00:23 +02:00