Skip to content

Commit a18b215

Browse files
committed
refactor: Make notification system universal and platform-agnostic
- Remove Kogotochki-specific dependencies - Move to proper wireframe structure - Add generic NotificationContext interface - Create platform adapters pattern - Add comprehensive documentation - Include migration scripts
1 parent 1171166 commit a18b215

13 files changed

+954
-724
lines changed

docs/NOTIFICATION_SYSTEM.md

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# Universal Notification System
2+
3+
A robust, platform-agnostic notification system with retry logic, batch processing, and user preferences support.
4+
5+
## Features
6+
7+
- 🔄 **Automatic Retry Logic**: Exponential backoff with jitter for failed notifications
8+
- 📦 **Batch Processing**: Efficient handling of bulk notifications
9+
- ⚙️ **User Preferences**: Granular control over notification categories
10+
- 🛡️ **Error Handling**: Graceful handling of blocked users and network errors
11+
- 📊 **Event-driven**: Integration with EventBus for monitoring
12+
- 🌐 **Platform Agnostic**: Easy to adapt for different messaging platforms
13+
14+
## Architecture
15+
16+
```
17+
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
18+
│ NotificationService │────▶│ NotificationConnector│────▶│ Platform Adapter │
19+
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
20+
│ │ │
21+
│ ▼ ▼
22+
│ ┌─────────────────┐ ┌─────────────────┐
23+
└──────────────────▶│ EventBus │ │ Telegram/Discord │
24+
└─────────────────┘ └─────────────────┘
25+
```
26+
27+
## Quick Start
28+
29+
### 1. Install Dependencies
30+
31+
```bash
32+
npm install grammy # For Telegram adapter
33+
```
34+
35+
### 2. Basic Setup
36+
37+
```typescript
38+
import { NotificationService } from '@/core/services/notification-service';
39+
import { NotificationConnector } from '@/connectors/notification-connector';
40+
import { TelegramNotificationAdapter } from '@/adapters/telegram/notification-adapter';
41+
import { Bot } from 'grammy';
42+
43+
// Create Telegram bot
44+
const bot = new Bot(process.env.BOT_TOKEN);
45+
46+
// Create adapter
47+
const adapter = new TelegramNotificationAdapter({ bot });
48+
49+
// Create connector with retry logic
50+
const connector = new NotificationConnector({
51+
adapter,
52+
storage: env.KV, // Optional: for storing notification status
53+
logger,
54+
eventBus,
55+
retryConfig: {
56+
maxAttempts: 3,
57+
initialDelay: 1000,
58+
maxDelay: 60000,
59+
backoffMultiplier: 2,
60+
},
61+
});
62+
63+
// Create service
64+
const notificationService = new NotificationService({
65+
connector,
66+
userPreferenceService, // Optional: for user preferences
67+
logger,
68+
eventBus,
69+
});
70+
```
71+
72+
### 3. Send Notifications
73+
74+
```typescript
75+
// Simple notification
76+
await notificationService.send(
77+
'123456789', // recipientId
78+
'welcome', // template
79+
{
80+
type: 'user_welcome',
81+
data: {
82+
username: 'John',
83+
service: 'Premium',
84+
},
85+
},
86+
'system', // category
87+
);
88+
89+
// Batch notification
90+
await notificationService.sendBatch(
91+
['123456789', '987654321'], // recipientIds
92+
'announcement',
93+
{
94+
type: 'system_announcement',
95+
data: {
96+
title: 'New Feature',
97+
message: 'Check out our new feature!',
98+
},
99+
},
100+
{
101+
batchSize: 50,
102+
delayBetweenBatches: 1000,
103+
},
104+
);
105+
```
106+
107+
## Components
108+
109+
### NotificationService
110+
111+
High-level service for sending notifications with business logic:
112+
- User preference checking
113+
- Template selection
114+
- Event emission
115+
116+
### NotificationConnector
117+
118+
Low-level connector handling:
119+
- Retry logic with exponential backoff
120+
- Batch processing
121+
- Status tracking
122+
- Error handling
123+
124+
### Platform Adapters
125+
126+
Implement `INotificationAdapter` for your platform:
127+
128+
```typescript
129+
export interface INotificationAdapter {
130+
deliver(recipientId: string, message: FormattedMessage): Promise<void>;
131+
checkReachability(recipientId: string): Promise<boolean>;
132+
getUserInfo(recipientId: string): Promise<UserInfo>;
133+
formatMessage(
134+
template: NotificationTemplate,
135+
params: Record<string, any>,
136+
locale: string,
137+
): Promise<FormattedMessage>;
138+
isRetryableError(error: unknown): boolean;
139+
}
140+
```
141+
142+
## User Preferences
143+
144+
Implement `IUserPreferenceService` to support user preferences:
145+
146+
```typescript
147+
class UserPreferenceService implements IUserPreferenceService {
148+
async getNotificationPreferences(userId: string): Promise<NotificationPreferences> {
149+
// Fetch from database
150+
return {
151+
enabled: true,
152+
categories: {
153+
system: true,
154+
transaction: true,
155+
marketing: false,
156+
// ...
157+
},
158+
};
159+
}
160+
}
161+
```
162+
163+
## Events
164+
165+
The system emits events for monitoring:
166+
167+
```typescript
168+
eventBus.on('notification:sent', (data) => {
169+
console.log('Notification sent:', data);
170+
});
171+
172+
eventBus.on('notification:failed', (data) => {
173+
console.log('Notification failed:', data);
174+
});
175+
176+
eventBus.on('notification:batch:completed', (data) => {
177+
console.log('Batch completed:', data);
178+
});
179+
```
180+
181+
## Templates
182+
183+
Create notification templates:
184+
185+
```typescript
186+
const templates: Record<string, NotificationTemplate> = {
187+
welcome: {
188+
id: 'welcome',
189+
name: 'User Welcome',
190+
category: 'system',
191+
content: {
192+
en: {
193+
body: 'Welcome {{username}}! Your {{service}} is now active.',
194+
parseMode: 'HTML',
195+
buttons: [[
196+
{ text: 'Get Started', url: 'https://example.com/start' },
197+
]],
198+
},
199+
es: {
200+
body: '¡Bienvenido {{username}}! Tu {{service}} está activo.',
201+
parseMode: 'HTML',
202+
},
203+
},
204+
},
205+
};
206+
```
207+
208+
## Error Handling
209+
210+
The system handles various error scenarios:
211+
212+
1. **User Blocked**: Marked as `BLOCKED` status, no retry
213+
2. **Network Errors**: Automatic retry with backoff
214+
3. **Rate Limits**: Respects platform rate limits
215+
4. **Invalid Recipients**: Logged and skipped
216+
217+
## Testing
218+
219+
```typescript
220+
import { createMockAdapter } from '@/test-utils';
221+
222+
const mockAdapter = createMockAdapter({
223+
deliver: vi.fn().mockResolvedValue(undefined),
224+
checkReachability: vi.fn().mockResolvedValue(true),
225+
});
226+
227+
// Test retry logic
228+
mockAdapter.deliver.mockRejectedValueOnce(new Error('Network error'));
229+
mockAdapter.isRetryableError.mockReturnValue(true);
230+
231+
// Should retry and succeed
232+
await connector.send(message);
233+
expect(mockAdapter.deliver).toHaveBeenCalledTimes(2);
234+
```
235+
236+
## Production Considerations
237+
238+
1. **Rate Limiting**: Implement rate limiting in adapters
239+
2. **Monitoring**: Use EventBus events for metrics
240+
3. **Storage**: Use KV/Database for notification history
241+
4. **Scaling**: Batch processing for large recipient lists
242+
5. **Localization**: Support multiple languages in templates
243+
244+
## Contributing
245+
246+
When adding new platform adapters:
247+
1. Implement `INotificationAdapter` interface
248+
2. Handle platform-specific errors
249+
3. Support platform features (buttons, media, etc.)
250+
4. Add comprehensive tests
251+
5. Document platform-specific considerations

0 commit comments

Comments
 (0)