System Design

Case Study: Notification System

**Push:** - FCM (Firebase): Free, both iOS & Android - APNs: Required for iOS, direct connection - OneSignal: Unified API, free tier **Email:** - SendGrid: 100 emails/day free, great API - Mailgun: 5000/month free, EU hosting - AWS SES: Cheapest at scale ($0.10/1000) **SMS:** - Twilio: Most popular, ~$0.0075/SMS - Nexmo/Vonage: Similar pricing - AWS SNS: Cheapest, limited features

**iOS:** - APNs may throttle if too many notifications - Silent notifications limited to ~3/hour - Notification grouping mandatory in iOS 12+ **Android:** - FCM quota: 240 messages/minute per device - High-priority limited to ~10/day per app - Doze mode delays normal priority notifications

- Explicit opt-in required for marketing emails in EU - Easy unsubscribe must be available - Log consent timestamps - Provide notification preferences UI - Delete user data on account deletion

Архитектура Notification System

Архитектура Notification System

Зачем это нужно?

Современные приложения используют множество каналов для уведомлений: push, email, SMS, in-app. Unified notification system обеспечивает консистентный опыт и избегает спама пользователей.

Что это такое?

Notification system состоит из: event ingestion, preference filtering, template rendering, channel routing, delivery providers, и analytics. Асинхронная архитектура обеспечивает масштабируемость.

Как это работает?

Пример

**Пример notification flow:** ```typescript // Order shipped → multiple channels await notificationApi.send({ eventType: 'order.shipped', userId: 'user123', data: { orderId: 'ORD-456', trackingNumber: '1Z999AA10123456784', carrier: 'UPS', estimatedDelivery: '2024-01-20' } }); // Results in: // 1. Push: "Your order is on its way! Track: 1Z999..." // 2. Email: Full HTML email with tracking link // 3. In-app: Notification in inbox ```

Что вы узнали о Архитектура Notification System?

Push Notifications: FCM и APNs

Push Notifications: FCM и APNs

Зачем это нужно?

Push notifications - самый эффективный канал для mobile engagement. Но они сложны: разные провайдеры для iOS и Android, управление токенами, handling failures.

Что это такое?

Firebase Cloud Messaging (FCM) для Android и Apple Push Notification service (APNs) для iOS. Система должна управлять device tokens, обрабатывать невалидные токены, и поддерживать rich notifications.

Как это работает?

Пример

**Rich notification на iOS:** ```typescript // Notification with image and actions await pushService.send(userId, { title: 'New message from John', body: 'Hey, are you coming to the party?', imageUrl: 'https://cdn.app.com/avatars/john.jpg', categoryId: 'MESSAGE', // Enables action buttons data: { type: 'message', senderId: 'john123', threadId: 'thread456' } }); // iOS notification extension renders: // ┌──────────────────────────────┐ // │ [John's avatar] │ // │ New message from John │ // │ Hey, are you coming to... │ // │ ───────────────────────── │ // │ [Reply] [Mark Read] [Mute] │ // └──────────────────────────────┘ ```

Что вы узнали о Push Notifications: FCM и APNs?

User Preferences и Rate Limiting

User Preferences и Rate Limiting

Зачем это нужно?

Без правильного управления preferences и rate limiting уведомления превращаются в спам. Это приводит к отключению уведомлений или удалению приложения. Rate limiting защищает пользователей от notification fatigue.

Что это такое?

Система preferences позволяет пользователям контролировать какие уведомления они получают и по каким каналам. Rate limiting ограничивает количество уведомлений за период времени на разных уровнях: per-user, per-channel, per-category.

Как это работает?

Пример

**Notification batching:** ```typescript // Instead of sending 20 "X liked your post" notifications: class NotificationBatcher { async batchSimilarNotifications( userId: string, eventType: string ): Promise<BatchedNotification | null> { const key = `pending:${userId}:${eventType}`; const pending = await this.redis.lrange(key, 0, -1); if (pending.length < 5) { return null; // Not enough to batch } // Clear pending await this.redis.del(key); const events = pending.map(JSON.parse); if (eventType === 'new_like') { return { title: `${events[0].userName} and ${events.length - 1} others liked your post`, body: null, data: { type: 'batched_likes', postId: events[0].postId, count: events.length } }; } // Similar for new_follower, new_comment, etc. } } ```

Что вы узнали о User Preferences и Rate Limiting?

Template Engine и Localization

Template Engine и Localization

Зачем это нужно?

Уведомления должны быть персонализированы и локализованы. Template engine позволяет отделить контент от логики, поддерживать A/B тестирование и быстро обновлять тексты без деплоя.

Что это такое?

Template system хранит шаблоны для каждого типа события и канала. Шаблоны поддерживают переменные, условия, плюрализацию и локализацию. Могут храниться в БД для динамических обновлений.

Как это работает?

Пример

**Channel-specific templates:** ```typescript // Same event, different templates per channel // Push (short, actionable) const pushTemplate = { title: '🎉 Flash Sale!', body: '50% off everything. Ends in {{hoursLeft}}h' }; // Email (detailed) const emailTemplate = { subject: 'Don\'t miss out! 50% Flash Sale', htmlBody: ` <h1>Flash Sale is ON!</h1> <p>Hi {{userName}},</p> <p>For the next {{hoursLeft}} hours, enjoy 50% off on all items.</p> <a href="{{shopUrl}}" class="cta">Shop Now</a> ` }; // SMS (ultra-short) const smsTemplate = { body: 'Flash Sale! 50% off for {{hoursLeft}}h. Shop: {{shortLink}}' }; ```

Что вы узнали о Template Engine и Localization?

Delivery Tracking и Analytics

Delivery Tracking и Analytics

Зачем это нужно?

Без tracking невозможно понять эффективность уведомлений. Метрики delivery rate, open rate, CTR позволяют оптимизировать контент и время отправки.

Что это такое?

Tracking включает: статус доставки от провайдеров, open tracking (через пиксели или SDK callbacks), click tracking (через redirect URLs), и engagement analytics.

Как это работает?

Пример

**Real-time delivery monitoring:** ```typescript // Dashboard websocket for ops team class DeliveryMonitor { async getRealTimeStats(): Promise<RealTimeStats> { const now = new Date(); const fiveMinAgo = new Date(now.getTime() - 5 * 60 * 1000); return { sent: await this.redis.zcount('sent', fiveMinAgo, now), delivered: await this.redis.zcount('delivered', fiveMinAgo, now), failed: await this.redis.zcount('failed', fiveMinAgo, now), // Alert thresholds deliveryRate: 0.982, // Should be > 0.95 avgLatencyMs: 1250, // Should be < 5000 // Provider status providers: { fcm: { status: 'healthy', latency: 450 }, apns: { status: 'healthy', latency: 380 }, sendgrid: { status: 'degraded', latency: 2100 } } }; } } ```

Что вы узнали о Delivery Tracking и Analytics?

Связанные уроки

  • rt-03-sse
Case Study: Notification System

0

1

Войти