Documentation
¶
Index ¶
- Constants
- func StartSubscriber(ctx context.Context, bus *events.EventBus, store *NotificationHistoryStore)
- func StartSubscriberWithInterval(ctx context.Context, bus *events.EventBus, store Appender, ...)
- type Appender
- type ListOptions
- type NotificationHistoryStore
- func (s *NotificationHistoryStore) Append(record *NotificationRecord) error
- func (s *NotificationHistoryStore) AppendAutoApproved(...) error
- func (s *NotificationHistoryStore) Clear(before *time.Time) (int, error)
- func (s *NotificationHistoryStore) GetUnreadCount() int
- func (s *NotificationHistoryStore) List(opts ListOptions) ([]*NotificationRecord, int, error)
- func (s *NotificationHistoryStore) MarkRead(ids []string) (int, error)
- func (s *NotificationHistoryStore) SetMetadata(id, key, value string) error
- type NotificationRecord
Constants ¶
const ( // MaxNotifications is the maximum number of notifications to retain. MaxNotifications = 500 // MaxNotificationAge is the maximum age of a notification before it is pruned. MaxNotificationAge = 7 * 24 * time.Hour )
const ( // DefaultCoalesceInterval is the default interval for flushing the coalescing buffer. DefaultCoalesceInterval = 500 * time.Millisecond )
Variables ¶
This section is empty.
Functions ¶
func StartSubscriber ¶
func StartSubscriber(ctx context.Context, bus *events.EventBus, store *NotificationHistoryStore)
StartSubscriber subscribes to the EventBus, filters for EventNotification events, converts them to NotificationRecords, coalesces rapid-fire events for the same (sessionID, notificationType) key within a 500ms window, and flushes them to the store. It stops when the context is canceled, flushing any remaining buffered records.
func StartSubscriberWithInterval ¶
func StartSubscriberWithInterval(ctx context.Context, bus *events.EventBus, store Appender, interval time.Duration)
StartSubscriberWithInterval is like StartSubscriber but allows configuring the coalescing interval. This is primarily useful for tests that need shorter intervals.
Types ¶
type Appender ¶
type Appender interface {
Append(record *NotificationRecord) error
}
Appender is the interface used by the subscriber to append records. This enables testing without a real NotificationHistoryStore.
type ListOptions ¶
ListOptions controls filtering and pagination for List operations.
type NotificationHistoryStore ¶
type NotificationHistoryStore struct {
// contains filtered or unexported fields
}
NotificationHistoryStore persists notification records to a JSON file with in-memory caching for fast reads.
func NewNotificationHistoryStore ¶
func NewNotificationHistoryStore(filePath string) (*NotificationHistoryStore, error)
NewNotificationHistoryStore creates a new store, loading existing data from disk. If the file does not exist or is corrupted, the store starts empty.
func (*NotificationHistoryStore) Append ¶
func (s *NotificationHistoryStore) Append(record *NotificationRecord) error
Append adds a notification record, enforces retention limits, and persists to disk. If an unread record with the same (sessionID, notificationType) already exists, the existing record is updated in place (occurrence count incremented, metadata refreshed, moved to front) instead of inserting a new record. Per ADR-003, if the existing record is already read, a new unread record is created instead.
For APPROVAL_NEEDED notifications the record ID is also updated to the incoming approval UUID so that SetMetadata outcome-stamping (which looks up by record ID) continues to correlate with the most recent approval for this session.
func (*NotificationHistoryStore) AppendAutoApproved ¶ added in v1.35.0
func (s *NotificationHistoryStore) AppendAutoApproved(sessionID, sessionName, toolName, filePath, ruleID, ruleName, ruleSource, decision string) error
AppendAutoApproved writes a silent NOTIFICATION_TYPE_AUTO_APPROVED record directly to history without publishing to the event bus. The record is immediately marked as read so it never appears in the active notification feed — only in the auto-handled history view.
func (*NotificationHistoryStore) Clear ¶
func (s *NotificationHistoryStore) Clear(before *time.Time) (int, error)
Clear removes notifications. If before is nil, clears all. Otherwise clears notifications created before the given time. Returns the number cleared.
func (*NotificationHistoryStore) GetUnreadCount ¶
func (s *NotificationHistoryStore) GetUnreadCount() int
GetUnreadCount returns the number of unread notifications. After server-side deduplication (Task 1.2), each unread record represents a distinct (sessionID, notificationType) group, so this count reflects the number of deduplicated unread groups -- not raw event occurrences.
func (*NotificationHistoryStore) List ¶
func (s *NotificationHistoryStore) List(opts ListOptions) ([]*NotificationRecord, int, error)
List returns a paginated, filtered slice of notification records and the total count.
func (*NotificationHistoryStore) MarkRead ¶
func (s *NotificationHistoryStore) MarkRead(ids []string) (int, error)
MarkRead marks specific notifications as read. If ids is empty, marks all as read. Returns the number of records that were marked.
func (*NotificationHistoryStore) SetMetadata ¶
func (s *NotificationHistoryStore) SetMetadata(id, key, value string) error
SetMetadata updates a single metadata key on the notification record with the given ID. A no-op (not an error) if the record does not exist, since the notification may have been pruned or the approval pre-dates history tracking.
type NotificationRecord ¶
type NotificationRecord struct {
ID string `json:"id"`
SessionID string `json:"session_id"`
SessionName string `json:"session_name"`
NotificationType int32 `json:"notification_type"`
Priority int32 `json:"priority"`
Title string `json:"title"`
Message string `json:"message"`
Metadata map[string]string `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
IsRead bool `json:"is_read"`
ReadAt *time.Time `json:"read_at,omitempty"`
// OccurrenceCount tracks how many deduplicated occurrences this record represents.
// A value of 0 (zero-value from old JSON) should be treated as 1 by consumers.
OccurrenceCount int `json:"occurrence_count,omitempty"`
// LastOccurredAt is the timestamp of the most recent occurrence. May differ from
// CreatedAt which tracks the first occurrence.
LastOccurredAt *time.Time `json:"last_occurred_at,omitempty"`
}
NotificationRecord is the persisted representation of a notification event.