From 55b2a0045866a0b0b067e2faec098188867ba2eb Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:38:10 +0200 Subject: [PATCH] =?UTF-8?q?feat(alerts):=20core=20repo=20=E2=80=94=20filte?= =?UTF-8?q?r=20params=20+=20markRead/softDelete/bulkAck/restore;=20drop=20?= =?UTF-8?q?AlertReadRepository?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - listForInbox gains tri-state acked/read filter params - countUnreadBySeverityForUser(envId, userId) → countUnreadBySeverity(envId, userId, groupIds, roleNames) - new methods: markRead, bulkMarkRead, softDelete, bulkSoftDelete, bulkAck, restore - delete AlertReadRepository — read is now global on alert_instances.read_at Co-Authored-By: Claude Opus 4.7 (1M context) --- .../alerting/AlertInstanceRepository.java | 53 +++++++++++++------ .../core/alerting/AlertReadRepository.java | 9 ---- 2 files changed, 37 insertions(+), 25 deletions(-) delete mode 100644 cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertReadRepository.java diff --git a/cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertInstanceRepository.java b/cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertInstanceRepository.java index d2e22278..a01cbfec 100644 --- a/cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertInstanceRepository.java +++ b/cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertInstanceRepository.java @@ -7,26 +7,27 @@ import java.util.Optional; import java.util.UUID; public interface AlertInstanceRepository { - AlertInstance save(AlertInstance instance); // upsert by id + AlertInstance save(AlertInstance instance); Optional findById(UUID id); - Optional findOpenForRule(UUID ruleId); // state IN ('PENDING','FIRING','ACKNOWLEDGED') - /** - * Unfiltered inbox listing. Convenience overload that delegates to the filtered - * variant with {@code states}/{@code severities} set to {@code null} (no filter). - */ + /** Open instance for a rule: state IN ('PENDING','FIRING') AND deleted_at IS NULL. */ + Optional findOpenForRule(UUID ruleId); + + /** Unfiltered inbox listing — convenience overload. */ default List listForInbox(UUID environmentId, List userGroupIdFilter, String userId, List userRoleNames, int limit) { - return listForInbox(environmentId, userGroupIdFilter, userId, userRoleNames, null, null, limit); + return listForInbox(environmentId, userGroupIdFilter, userId, userRoleNames, + null, null, null, null, limit); } /** - * Inbox listing with optional state + severity filters. {@code null} or empty lists mean - * "no filter on that field". When both lists are non-empty the row must match at least one - * value from each list (AND between dimensions, OR within). + * Inbox listing with optional filters. {@code null} or empty lists mean no filter. + * {@code acked} and {@code read} are tri-state: {@code null} = no filter, + * {@code TRUE} = only acked/read, {@code FALSE} = only unacked/unread. + * Always excludes soft-deleted rows ({@code deleted_at IS NOT NULL}). */ List listForInbox(UUID environmentId, List userGroupIdFilter, @@ -34,20 +35,40 @@ public interface AlertInstanceRepository { List userRoleNames, List states, List severities, + Boolean acked, + Boolean read, int limit); /** - * Count unread alert instances for the user, grouped by severity. - *

- * Always returns a map with an entry for every {@link AlertSeverity} (value 0 if no rows), - * so callers never need null-checks. Total unread count is the sum of the values. + * Count unread alert instances visible to the user, grouped by severity. + * Visibility: targets user directly, or via one of the given groups/roles. + * "Unread" = {@code read_at IS NULL AND deleted_at IS NULL}. */ - Map countUnreadBySeverityForUser(UUID environmentId, String userId); + Map countUnreadBySeverity(UUID environmentId, + String userId, + List groupIds, + List roleNames); + void ack(UUID id, String userId, Instant when); void resolve(UUID id, Instant when); void markSilenced(UUID id, boolean silenced); void deleteResolvedBefore(Instant cutoff); - /** FIRING instances whose reNotify cadence has elapsed since last notification. */ + /** Set {@code read_at = when} if currently null. Idempotent. */ + void markRead(UUID id, Instant when); + /** Bulk variant — single UPDATE. */ + void bulkMarkRead(List ids, Instant when); + + /** Set {@code deleted_at = when} if currently null. Idempotent. */ + void softDelete(UUID id, Instant when); + /** Bulk variant — single UPDATE. */ + void bulkSoftDelete(List ids, Instant when); + + /** Clear {@code deleted_at}. Undo for soft-delete. Idempotent. */ + void restore(UUID id); + + /** Bulk ack — single UPDATE. Each row gets {@code acked_at=when, acked_by=userId} if unacked. */ + void bulkAck(List ids, String userId, Instant when); + List listFiringDueForReNotify(Instant now); } diff --git a/cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertReadRepository.java b/cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertReadRepository.java deleted file mode 100644 index a3cd08e4..00000000 --- a/cameleer-server-core/src/main/java/com/cameleer/server/core/alerting/AlertReadRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.cameleer.server.core.alerting; - -import java.util.List; -import java.util.UUID; - -public interface AlertReadRepository { - void markRead(String userId, UUID alertInstanceId); - void bulkMarkRead(String userId, List alertInstanceIds); -}