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>
This commit is contained in:
Marcel
2026-04-21 17:00:36 +02:00
parent b07f9efa9c
commit b9f5ec22aa
4 changed files with 44 additions and 1 deletions

View File

@@ -15,4 +15,6 @@ public interface ActivityFeedRow {
boolean isYouParticipated();
int getCount();
Instant getHappenedAtUntil();
/** Present only for COMMENT_ADDED and MENTION_CREATED — null otherwise. */
UUID getCommentId();
}

View File

@@ -99,7 +99,8 @@ public interface AuditLogQueryRepository extends JpaRepository<AuditLog, UUID> {
AND n.reference_id = (ag.payload->>'commentId')::uuid
) AS youParticipated,
ag.count AS count,
ag.happened_at_until AS happenedAtUntil
ag.happened_at_until AS happenedAtUntil,
(ag.payload->>'commentId')::uuid AS commentId
FROM aggregated ag
LEFT JOIN users u ON u.id = ag.actor_id
ORDER BY ag.happened_at DESC

View File

@@ -271,6 +271,45 @@ class AuditLogQueryRepositoryRolledUpTest {
);
}
@Test
void rolledUpFeed_exposes_commentId_for_COMMENT_ADDED_events() {
insertUserAndDocs();
UUID commentId = UUID.randomUUID();
insertAuditEvent(USER_ID, DOC_ID, "COMMENT_ADDED",
Instant.parse("2026-04-20T10:00:00Z"), Map.of("commentId", commentId.toString()));
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
assertThat(rows).hasSize(1);
assertThat(rows.get(0).getCommentId()).isEqualTo(commentId);
}
@Test
void rolledUpFeed_exposes_commentId_for_MENTION_CREATED_events() {
insertUserAndDocs();
UUID commentId = UUID.randomUUID();
insertAuditEvent(OTHER_USER_ID, DOC_ID, "MENTION_CREATED",
Instant.parse("2026-04-20T10:00:00Z"),
Map.of("commentId", commentId.toString(), "mentionedUserId", USER_ID.toString()));
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
assertThat(rows).hasSize(1);
assertThat(rows.get(0).getCommentId()).isEqualTo(commentId);
}
@Test
void rolledUpFeed_commentId_is_null_for_non_comment_kinds() {
insertUserAndDocs();
insertAuditEvent(USER_ID, DOC_ID, "TEXT_SAVED",
Instant.parse("2026-04-20T10:00:00Z"), Map.of("blockId", "ccc", "pageNumber", "1"));
List<ActivityFeedRow> rows = auditLogQueryRepository.findRolledUpActivityFeed(USER_ID.toString(), 40);
assertThat(rows).hasSize(1);
assertThat(rows.get(0).getCommentId()).isNull();
}
@Test
void youMentioned_is_false_when_mention_created_payload_targets_different_user() {
insertUserAndDocs();

View File

@@ -107,6 +107,7 @@ class DashboardServiceTest {
public boolean isYouParticipated() { return false; }
public int getCount() { return 1; }
public Instant getHappenedAtUntil() { return null; }
public UUID getCommentId() { return null; }
};
}
}