Skip to content

Push Bildirimi Mimarisi ​

Genel Bakış ​

Push bildirimleri, mobil uygulamalarda kullanıcı katılımını artıran kritik bir özelliktir. Bu dokümantasyon, ölçeklenebilir ve güvenilir push bildirim sistemlerinin tasarımını kapsar.

Hızlı Karar ​

İhtiyaçBildirim TipiDikkat
Kullanıcı aksiyonu gerekliAlert notificationSpam opt-out artırır
Sessiz veri yenilemeSilent pushOS teslim garantisi vermez
Kritik güvenlik uyarısıHigh priorityKötüye kullanım engellenmeli
Toplu kampanyaSegment + rate limitZaman dilimi ve izin dikkate alınmalı

Üretim Kontrol Listesi ​

  • Problem: Bildirim kullanıcı için hangi değeri yaratıyor?
  • Çözüm: Consent, token lifecycle, segmentation, retry ve deep link davranışı net mi?
  • Trade-off: Bildirim engagement artırır; fazla kullanım güven ve izin kaybı yaratır.
  • Hata durumu: Expired token, duplicate push, wrong segment, provider outage ve deep link failure ele alınmalı.
  • Ölçüm: Opt-in rate, delivery rate, open rate, unsubscribe rate ve provider error izlenmeli.
  • Güvenlik/maliyet: Bildirim içeriğinde hassas veri olmamalı; toplu gönderim provider maliyeti üretir.

Push Bildirim Mimarisi ​

Sistem Bileşenleri ​

[Mobile App] → [APNs/FCM] → [Push Service] → [Message Queue] → [Backend API]

Platform-Specific Implementation ​

iOS - Apple Push Notification Service (APNs) ​

swift
import UserNotifications

class PushNotificationManager {
    static func registerForNotifications() {
        UNUserNotificationCenter.current().requestAuthorization(
            options: [.alert, .sound, .badge]
        ) { granted, error in
            guard granted else { return }
            
            DispatchQueue.main.async {
                UIApplication.shared.registerForRemoteNotifications()
            }
        }
    }
    
    static func handleDeviceToken(_ deviceToken: Data) {
        let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        
        // Token'ı backend'e gönder
        APIService.registerDeviceToken(token) { result in
            switch result {
            case .success:
                print("Device token registered successfully")
            case .failure(let error):
                print("Failed to register device token: \(error)")
            }
        }
    }
}

Android - Firebase Cloud Messaging (FCM) ​

kotlin
class PushNotificationService : FirebaseMessagingService() {
    
    override fun onNewToken(token: String) {
        super.onNewToken(token)
        
        // Token'ı backend'e gönder
        ApiService.registerDeviceToken(token) { result ->
            when (result) {
                is Result.Success -> {
                    Log.d(TAG, "Device token registered successfully")
                }
                is Result.Error -> {
                    Log.e(TAG, "Failed to register device token", result.exception)
                }
            }
        }
    }
    
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        
        remoteMessage.notification?.let { notification ->
            showNotification(
                title = notification.title ?: "",
                body = notification.body ?: "",
                data = remoteMessage.data
            )
        }
    }
    
    private fun showNotification(title: String, body: String, data: Map<String, String>) {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        
        val notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle(title)
            .setContentText(body)
            .setSmallIcon(R.drawable.ic_notification)
            .setAutoCancel(true)
            .build()
            
        notificationManager.notify(System.currentTimeMillis().toInt(), notification)
    }
}

Backend Implementation ​

Node.js Push Service ​

javascript
const admin = require('firebase-admin');
const apn = require('apn');

class PushNotificationService {
    constructor() {
        // Firebase Admin SDK
        this.fcm = admin.messaging();
        
        // APNs Provider
        this.apnProvider = new apn.Provider({
            token: {
                key: process.env.APN_KEY_PATH,
                keyId: process.env.APN_KEY_ID,
                teamId: process.env.APN_TEAM_ID
            }
        });
    }
    
    async sendToDevice(deviceToken, platform, payload) {
        try {
            if (platform === 'ios') {
                await this.sendAPNs(deviceToken, payload);
            } else if (platform === 'android') {
                await this.sendFCM(deviceToken, payload);
            }
        } catch (error) {
            console.error('Push notification failed:', error);
            throw error;
        }
    }
    
    async sendFCM(token, payload) {
        const message = {
            token: token,
            notification: {
                title: payload.title,
                body: payload.body
            },
            data: payload.data || {}
        };
        
        const response = await this.fcm.send(message);
        return response;
    }
    
    async sendAPNs(token, payload) {
        const notification = new apn.Notification();
        notification.alert = {
            title: payload.title,
            body: payload.body
        };
        notification.badge = payload.badge || 1;
        notification.sound = 'default';
        notification.payload = payload.data || {};
        
        const result = await this.apnProvider.send(notification, token);
        return result;
    }
}

Gelişmiş Özellikler ​

1. Targeting ve Segmentasyon ​

javascript
class NotificationTargeting {
    async sendToUserSegment(segment, payload) {
        const users = await this.getUsersBySegment(segment);
        
        const batch = users.map(user => ({
            token: user.deviceToken,
            platform: user.platform,
            payload: this.personalizePayload(payload, user)
        }));
        
        await this.sendBatchNotifications(batch);
    }
    
    personalizePayload(basePayload, user) {
        return {
            ...basePayload,
            title: basePayload.title.replace('{name}', user.name),
            data: {
                ...basePayload.data,
                userId: user.id
            }
        };
    }
}

2. A/B Testing ​

javascript
class NotificationABTest {
    async runABTest(testConfig) {
        const users = await this.getTestUsers(testConfig.targetSegment);
        
        for (const user of users) {
            const variant = this.assignVariant(user.id, testConfig.variants);
            
            await this.sendNotification(
                user.deviceToken,
                user.platform,
                variant.payload
            );
            
            await this.trackEvent('notification_sent', {
                userId: user.id,
                variant: variant.name,
                testId: testConfig.id
            });
        }
    }
}

Performance ve Ölçeklendirme ​

1. Rate Limiting ​

javascript
class RateLimiter {
    constructor() {
        this.limits = {
            ios: 100, // APNs rate limit
            android: 1000 // FCM rate limit
        };
    }
    
    async sendWithRateLimit(notifications) {
        const grouped = this.groupByPlatform(notifications);
        
        for (const [platform, batch] of Object.entries(grouped)) {
            await this.processBatch(batch, this.limits[platform]);
        }
    }
    
    async processBatch(notifications, batchSize) {
        for (let i = 0; i < notifications.length; i += batchSize) {
            const batch = notifications.slice(i, i + batchSize);
            await Promise.all(batch.map(n => this.sendNotification(n)));
            
            // Rate limiting için bekle
            if (i + batchSize < notifications.length) {
                await this.delay(1000);
            }
        }
    }
}

2. Dead Letter Queue ​

javascript
class NotificationQueue {
    async processNotification(notification) {
        try {
            await this.sendNotification(notification);
        } catch (error) {
            if (this.isRetryableError(error)) {
                await this.retryQueue.add(notification, {
                    delay: this.calculateBackoff(notification.retryCount),
                    attempts: 3
                });
            } else {
                await this.deadLetterQueue.add(notification);
            }
        }
    }
    
    calculateBackoff(retryCount) {
        return Math.pow(2, retryCount) * 1000; // Exponential backoff
    }
}

Monitoring ve Analytics ​

1. Metrics Collection ​

javascript
class NotificationMetrics {
    async trackDelivery(notificationId, status) {
        await this.metrics.increment('notifications.delivered', {
            status: status,
            platform: platform
        });
    }
    
    async trackEngagement(notificationId, action) {
        await this.metrics.increment('notifications.engagement', {
            action: action, // opened, dismissed, clicked
            notificationId: notificationId
        });
    }
}

2. Dashboard Monitoring ​

  • Delivery rate
  • Open rate
  • Click-through rate
  • Platform-specific metrics
  • Error rates ve failure reasons

Bu mimari ile ölçeklenebilir, güvenilir ve kullanıcı dostu push bildirim sistemi oluşturabilirsiniz.

Eren Demir tarafından oluşturulmuştur.