feat(notifications): persistent read cursor + delivery history

notification_cursors table stores one read-cursor per user per tenant;
GET /v1/activity returns unreadCount + readAt, POST /v1/activity/read
persists the cursor. Reminder dispatches now append reminder.sent /
reminder.failed system events so delivery history reaches the feed.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-18 16:55:21 +02:00
1 parent 76e45d4178
commit 2464aa45fa
14 files changed
+332 -8

No files matched your search

@@ -61,6 +61,20 @@ func TestDispatchDueProcessesPendingEmailReminders(t *testing.T) {
if len(pending) != 0 {
t.Fatalf("expected no pending jobs after dispatch, got %d", len(pending))
}
events, err := repo.ListActivityEvents(context.Background(), "5d6b3551-0a3e-4b86-bdf0-e9df20a47148", 10)
if err != nil {
t.Fatalf("list activity: %v", err)
}
for _, event := range events {
if event.Action == "reminder.sent" && event.ActorKind == "system" {
if event.EntityID == nil || *event.EntityID != created.ID {
t.Fatalf("expected entity id %s, got %v", created.ID, event.EntityID)
}
return
}
}
t.Fatal("expected system reminder.sent activity event")
}
func TestDispatchDueFailsUnknownChannel(t *testing.T) {