Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .kiro/specs/notification-expiration/.config.kiro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"specId": "notification-expiration", "workflowType": "requirements-first", "specType": "feature"}
77 changes: 77 additions & 0 deletions .kiro/specs/notification-expiration/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Design Document

## Overview

This design implements notification expiration for the Notify-Chain listener. Notifications will store an expiration timestamp and the processing pipeline will check and skip expired notifications.

## Architecture

### Components

1. **NotificationExpirationService** - Core service for checking expiration
2. **ExpirationConfig** - Configuration for expiration settings
3. **Event Registry Update** - Store expiration with events

### Data Model

```
NotificationExpiration {
createdAt: number (timestamp)
expiresAt: number (timestamp)
}

EventStore extends with expiration {
...existing fields
expiresAt?: number (optional - if not set, uses default)
}
```

## Implementation Details

### 1. Expiration Service

```typescript
interface ExpirationConfig {
defaultExpirationMs: number; // Default 24 hours
perEventTypeExpiration: Record<string, number>;
enabled: boolean; // If false, no expiration checks
}

class NotificationExpirationService {
constructor(config: ExpirationConfig)

isExpired(event: EventResponse): boolean
shouldProcess(event: EventResponse): boolean
getExpirationTime(eventType?: string): number
}
```

### 2. Integration Points

- **EventSubscriber.shouldProcessEvent()** - Add expiration check
- **DiscordNotificationService** - Check expiration before sending
- **Config** - Add expiration configuration options

### 3. Configuration

```typescript
interface Config {
// ... existing fields
expiration?: {
defaultExpirationMs: number;
perEventTypeExpiration: Record<string, number>;
enabled: boolean;
};
}
```

## Default Values

- `defaultExpirationMs`: 24 * 60 * 60 * 1000 (24 hours)
- `enabled`: true

## Testing Strategy

1. Unit tests for NotificationExpirationService
2. Integration tests for expiration in EventSubscriber
3. Edge cases: null expiration, very long expiration, past expiration
56 changes: 56 additions & 0 deletions .kiro/specs/notification-expiration/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Requirements Document

## Introduction

This feature implements expiration support to prevent outdated notifications from being processed or delivered. It ensures notifications have a valid time window and are filtered out once expired.

## Glossary

- **Notification**: A message sent to users about blockchain events
- **Expiration Timestamp**: The time after which a notification is no longer valid
- **Processed Notification**: A notification that has been handled by the notification service
- **Event Timestamp**: The time when the blockchain event occurred

## Requirements

### Requirement 1: Expiration Timestamp Storage

**User Story:** As a system administrator, I want notifications to store an expiration timestamp, so that I can control how long notifications remain valid.

#### Acceptance Criteria

1. WHEN a notification is created, THE system SHALL store an expiration timestamp
2. THE expiration timestamp SHALL be configurable per notification type
3. DEFAULT expiration time SHALL be 24 hours from notification creation if not specified

### Requirement 2: Expiration Validation

**User Story:** As a system administrator, I want expired notifications to be blocked from processing, so that outdated notifications don't reach users.

#### Acceptance Criteria

1. WHEN a notification is about to be processed, THE system SHALL check if the current time exceeds the expiration timestamp
2. IF the notification is expired, THE system SHALL skip processing and log the expiration
3. IF the notification is expired, THE system SHALL NOT send the notification to any channel (Discord, etc.)
4. EXPIRED notifications SHALL be recorded in the audit log with "EXPIRED" status

### Requirement 3: Unit Test Coverage

**User Story:** As a developer, I want expiration checks to be covered by unit tests, so that the expiration logic works correctly.

#### Acceptance Criteria

1. UNIT tests SHALL verify that expired notifications are not processed
2. UNIT tests SHALL verify that valid notifications are processed
3. UNIT tests SHALL verify the default expiration time behavior
4. UNIT tests SHALL cover edge cases (null expiration, very long expiration, etc.)

### Requirement 4: Configuration Options

**User Story:** As a system administrator, I want to configure expiration settings, so that different notification types can have different validity periods.

#### Acceptance Criteria

1. THE system SHALL allow configuring default expiration time via configuration
2. THE system SHALL allow setting per-event-type expiration times
3. THE configuration SHALL support disabling expiration (infinite validity)
47 changes: 47 additions & 0 deletions .kiro/specs/notification-expiration/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Implementation Plan: notification-expiration

## Overview

This implementation plan adds expiration support to prevent outdated notifications from being processed or delivered.

## Tasks

- [-] 1. Add expiration configuration to types
- [x] 1.1 Add ExpirationConfig interface to Config type
- [x] 1.2 Add expiresAt field to AppCleanupConfig if applicable
- _Requirements: 1.1, 4.1, 4.2_

- [-] 2. Create NotificationExpirationService
- [x] 2.1 Create src/services/notification-expiration.ts
- [x] 2.2 Implement isExpired() method
- [x] 2.3 Implement shouldProcess() method
- [x] 2.4 Implement getExpirationTime() method
- _Requirements: 2.1, 2.2, 2.3_

- [x] 3. Update EventSubscriber to check expiration
- [x] 3.1 Integrate NotificationExpirationService in EventSubscriber
- [x] 3.2 Add expiration check in shouldProcessEvent()
- [x] 3.3 Log when notifications are skipped due to expiration
- _Requirements: 2.1, 2.2, 2.3_

- [x] 4. Add unit tests
- [x] 4.1 Create notification-expiration.test.ts
- [x] 4.2 Test isExpired() with past time
- [x] 4.3 Test isExpired() with future time
- [x] 4.4 Test shouldProcess() returns false for expired
- [x] 4.5 Test shouldProcess() returns true for valid
- [x] 4.6 Test default expiration behavior
- [x] 4.7 Test per-event-type expiration
- _Requirements: 3.1, 3.2, 3.3, 3.4_

- [x] 5. Update config schema if needed
- [x] 5.1 Add expiration to Config interface
- [x] 5.2 Update .env.example with expiration settings
- _Requirements: 4.1, 4.2, 4.3_

## Notes

- Default expiration: 24 hours (86400000 ms)
- Check expiration after event validation but before notification sending
- Log skipped notifications with "expired" reason
- Support disabling expiration via config for backward compatibility
7 changes: 7 additions & 0 deletions listener/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,10 @@ RATE_LIMIT_CLIENT_OVERRIDES={}
# ARCHIVE_AFTER_MS=604800000 # Archive notifications completed > X ms ago (default: 7 days)
# ARCHIVE_DELETE_AFTER_MS=7776000000 # Permanently delete archive rows > X ms old (default: 90 days; 0 = never)
# ARCHIVE_BATCH_SIZE=500 # Max rows processed per cycle

# Notification Expiration Configuration
EXPIRATION_ENABLED=true
EXPIRATION_DEFAULT_MS=86400000
# Per-event-type expiration times in milliseconds (JSON object)
# Example: {"notification_scheduled":3600000,"alert":604800000}
# EXPIRATION_PER_EVENT_TYPE={}
Loading
Loading