# Case Study: TahminApp — 500K Kullanıcı, %99.9 Uptime, 6 Ay Production
Problem: Spor tahmin platformunda gerçek zamanlı maç olayları (gol, kart, devre arası) anında 500K+ kullanıcıya push notification gönderme + canlı skaler akışı UI'da güncelleme.
Sonuç: 6 ay production, 500K MAU, p99 latency 180ms, %99.94 uptime, 0 incident (>30dk downtime).
Pro Tip: Bottleneck'in beklediğin yer değil. Bizim için Firestore write değil, push delivery routing'di. Her büyük scaling story aynı şekilde başlar.
1. Architecture Overview
3-tier:
- Edge layer (CF Workers):: Webhook receiver, dedup, fan-out trigger
- Backend (Firestore + Cloud Functions):: Persistent state, business logic
- Mobile (iOS native + Flutter Android):: Realtime listener + push notification handler
swift
1[Sports Data Feed]2 ↓ webhook3[CF Worker — dedup + transform]4 ↓ event5[Cloud Function — match state update]6 ↓ write7[Firestore — predictions, users, scores]8 ↓ realtime listener9[Mobile Apps — UI update]10 ↓11[FCM/APNs — push notification]2. Bottleneck Hikayesi
İlk hipotez: Firestore writes scale etmez. Tutmadı.
İkinci hipotez: Cloud Functions cold start sorun. Tutmadı (warm instance pool).
Gerçek bottleneck: APNs delivery latency. Apple'ın production token routing 500K push'u 30sn'de değil 4-6dk'da teslim ediyordu. Big match olaylarında "geç notification" şikayetleri %12'ye fırladı.
Çözüm: Priority routing — match-event push'lar APNs alpn 10 priority + Cloudflare Workers'tan paralel batch send. 500K push 25-35sn'de teslim. Şikayet %12 → %0.3.
3. Firestore Tasarımı
500K user × 50 prediction/user × 100 match/season = 2.5M document. Naive design /predictions/{id} çökerdi.
Doğru pattern — sharded collection:
swift
1/predictions/shard-{0-19}/items/{predictionID}Shard count 20, prediction ID hash'inden assignment. Her shard ayrı index, ayrı write limit. Toplam write throughput 20x.
Realtime listener: Mobile listen /predictions/shard-{userShard} — sadece kendi shard'ını izle. Network savings %95.
4. Cloud Functions Patterns
40+ Cloud Function var. En kritik 3:
- `onMatchEvent`: webhook trigger, dedup window 30sn, state update + push trigger
- `onPredictionWrite`: leaderboard recalc (sharded counter pattern)
- `onUserWrite`: profile cache invalidation (Cloudflare KV pürge)
Her function:
- Memory: 256MB (most), 1GB (leaderboard)
- Timeout: 60s
- Max instances: 1000 (auto-scale)
- Retry: 3x exponential backoff
- Idempotency:
eventIDFirestore set-based dedup
5. iOS App Architecture
iOS native (SwiftUI iOS 16+):
- TCA (The Composable Architecture): state management
- Firestore Snapshot Publisher: — Combine pattern
- APNS Notification Service Extension: — payload decryption + smart action
- Local cache (SwiftData): — offline read-only mode
Memory baseline: 95MB. Peak (match-time live UI): 145MB.
Crash-free session rate %99.84 (Crashlytics, 6-ay average).
6. Cost Profile
Aylık infrastructure cost (500K MAU peak):
Kalem | Cost |
|---|---|
Firestore (read/write/storage) | $420 |
Cloud Functions (invocations) | $180 |
Cloud Messaging (FCM) | $0 (free tier OK) |
APNs | $0 (Apple side) |
Cloudflare Workers | $25 (Pro plan) |
Cloudflare KV | $5 |
Hetzner monitoring server | $7 |
**Toplam** | **$637/ay** |
Per-user cost: $0.00127/user/ay. Indie unit economics için müthiş.
7. Öğrenimler (Lessons Learned)
1. Predicted bottleneck nadiren gerçek bottleneck. APNs delivery'nin sorun olduğunu launch sonrası 4 hafta sonra anladık.
2. Sharding'i ön ödeme yap. 500K user'a vardığında sharding eklemek 4 ay teknik borç.
3. Idempotency event ID kritik — webhook retry'ları sessiz duplicate yarattı.
4. Notification Service Extension content modification + alert prioritization için altın.
5. Edge layer (CF Workers) dedup + transform yapmak Cloud Functions cost'unu 4x düşürdü.
6. Crashlytics + custom telemetry ikisini birden çalıştır. Crashlytics aggregation, custom telemetry decision data.
7. App Store reviews'da büyük match anlarında ortalama notification latency kullanıcıların en çok yorum yaptığı şey. Latency optimize → 5-yıldız oranı %62 → %78.
Sonuç: Production scale 500K user genellikle "Firestore plate" değil, "delivery infrastructure" sorunu. Architecture'ı en başta multi-tier kur, ölç ve refactor et.

