Firebase, Google'ın Backend-as-a-Service (BaaS) platformudur. Firestore, Authentication, Cloud Functions, Remote Config — tümü entegre çalışır. Bu rehberde temel CRUD'un ötesine geçerek, production-grade Firebase kullanımını öğreneceksin.
💡 Hızlı Not: Firebase iOS SDK 10.0+ ile Swift Concurrency (async/await) tam desteklenir. Bu rehber güncel API'ları kullanır.
İçindekiler
- Firestore İleri Seviye Sorgular
- Offline-First Architecture
- Security Rules Deep Dive
- Cloud Functions ile Backend Logic
- Authentication: Custom Claims ve MFA
- Remote Config ve A/B Testing
- Firebase Extensions
- Maliyet Optimizasyonu
- Monitoring ve Analytics
- Best Practices
Firestore İleri Seviye Sorgular {#firestore-advanced}
swift
1import FirebaseFirestore2 3// Composite query (birden fazla alan filtresi)4func getActiveExpensiveProducts() async throws -> [Product] {5 let snapshot = try await Firestore.firestore()6 .collection("products")7 .whereField("isActive", isEqualTo: true)8 .whereField("price", isGreaterThan: 100)9 .order(by: "price", descending: true)10 .limit(to: 20)11 .getDocuments()12 13 return snapshot.documents.compactMap { try? $0.data(as: Product.self) }14}15 16// Collection group query (tüm subcollection'ları tara)17func getAllReviews(rating: Int) async throws -> [Review] {18 let snapshot = try await Firestore.firestore()19 .collectionGroup("reviews")20 .whereField("rating", isGreaterThanOrEqualTo: rating)21 .getDocuments()22 23 return snapshot.documents.compactMap { try? $0.data(as: Review.self) }24}25 26// Pagination ile cursor-based sayfalama27class PaginatedFetcher {28 private var lastDocument: DocumentSnapshot?29 30 func fetchNextPage() async throws -> [Product] {31 var query = Firestore.firestore()32 .collection("products")33 .order(by: "createdAt", descending: true)34 .limit(to: 20)35 36 if let last = lastDocument {37 query = query.start(afterDocument: last)38 }39 40 let snapshot = try await query.getDocuments()41 lastDocument = snapshot.documents.last42 43 return snapshot.documents.compactMap { try? $0.data(as: Product.self) }44 }45}46 47// Real-time listener48func listenToOrders() -> ListenerRegistration {49 return Firestore.firestore()50 .collection("orders")51 .whereField("userId", isEqualTo: Auth.auth().currentUser!.uid)52 .addSnapshotListener { snapshot, error in53 guard let documents = snapshot?.documents else { return }54 let orders = documents.compactMap { try? $0.data(as: Order.self) }55 self.orders = orders56 }57}Offline-First Architecture {#offline-first}
swift
1// Firestore otomatik offline persistence (varsayılan açık, 100MB cache)2let settings = FirestoreSettings()3settings.cacheSettings = PersistentCacheSettings(sizeBytes: 200 * 1024 * 1024) // 200MB4Firestore.firestore().settings = settings5 6// Offline yazma — queue'ya alınır, bağlantı gelince sync olur7func saveOrder(_ order: Order) async throws {8 try Firestore.firestore()9 .collection("orders")10 .document(order.id)11 .setData(from: order)12 // Offline'da bile çalışır - queue'ya alınır13}14 15// Cache vs server source belirt16func getProduct(id: String, source: FirestoreSource = .default) async throws -> Product {17 let doc = try await Firestore.firestore()18 .collection("products")19 .document(id)20 .getDocument(source: source) // .cache, .server, .default21 .data(as: Product.self)22 return doc23}Security Rules Deep Dive {#security-rules}
javascript
1// firestore.rules2rules_version = '2';3service cloud.firestore {4 match /databases/{database}/documents {5 // Users - sadece kendi profili6 match /users/{userId} {7 allow read: if request.auth != null;8 allow write: if request.auth.uid == userId;9 }10 11 // Products - herkes okuyabilir, admin yazabilir12 match /products/{productId} {13 allow read: if true;14 allow write: if request.auth.token.admin == true;15 16 // Validation17 allow create: if request.resource.data.name is string18 && request.resource.data.name.size() > 019 && request.resource.data.price is number20 && request.resource.data.price > 0;21 }22 23 // Orders - sadece kendi siparişleri24 match /orders/{orderId} {25 allow read: if request.auth.uid == resource.data.userId;26 allow create: if request.auth.uid == request.resource.data.userId27 && request.resource.data.items.size() > 0;28 allow update: if false; // Sipariş değiştirilemez29 }30 }31}Cloud Functions ile Backend Logic {#cloud-functions}
typescript
1// functions/src/index.ts2import * as functions from 'firebase-functions';3import * as admin from 'firebase-admin';4admin.initializeApp();5 6// Yeni sipariş oluşturulduğunda7export const onOrderCreated = functions.firestore8 .document('orders/{orderId}')9 .onCreate(async (snap, context) => {10 const order = snap.data();11 12 // Stok düş13 for (const item of order.items) {14 await admin.firestore()15 .collection('products')16 .doc(item.productId)17 .update({ stock: admin.firestore.FieldValue.increment(-item.quantity) });18 }19 20 // Email gönder21 await sendOrderConfirmation(order.userId, context.params.orderId);22 23 // Push notification24 const user = await admin.firestore().collection('users').doc(order.userId).get();25 const token = user.data()?.fcmToken;26 if (token) {27 await admin.messaging().send({28 token,29 notification: {30 title: 'Sipariş Onayı',31 body: 'Sipariş #' + context.params.orderId + ' alındı!',32 },33 });34 }35 });36 37// Scheduled function - günlük temizlik38export const dailyCleanup = functions.pubsub39 .schedule('every 24 hours')40 .onRun(async () => {41 const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);42 const old = await admin.firestore()43 .collection('logs')44 .where('createdAt', '<', thirtyDaysAgo)45 .get();46 const batch = admin.firestore().batch();47 old.docs.forEach(doc => batch.delete(doc.ref));48 await batch.commit();49 });Authentication: Custom Claims ve MFA {#auth-advanced}
swift
1// Custom claims ile role-based auth2// Cloud Function ile claim ata3// admin.auth().setCustomUserClaims(uid, { admin: true })4 5// iOS'ta claim kontrol6func checkAdminAccess() async throws -> Bool {7 guard let user = Auth.auth().currentUser else { return false }8 let result = try await user.getIDTokenResult()9 return result.claims["admin"] as? Bool ?? false10}Remote Config ve A/B Testing {#remote-config}
swift
1import FirebaseRemoteConfig2 3func setupRemoteConfig() {4 let config = RemoteConfig.remoteConfig()5 config.setDefaults(["new_feature_enabled": false as NSObject])6 config.fetchAndActivate { status, error in7 let isEnabled = config.configValue(forKey: "new_feature_enabled").boolValue8 if isEnabled { self.showNewFeature() }9 }10}Maliyet Optimizasyonu {#cost-optimization}
Teknik | Tasarruf | Nasıl |
|---|---|---|
Pagination | %60-80 | limit(to:) kullan, hepsini çekme |
Cache | %30-50 | Offline persistence aktif |
Denormalization | %40 | Join azalt, veriyi düzleştir |
Listener temizliği | %20 | removeListener ekran kapanınca |
Cloud Functions batch | %50 | Bireysel yerine toplu işlem |
Firebase Extensions {#extensions}
Firebase Extensions, hazır çözümlerle geliştirme sürecini hızlandırır:
bash
1# Firebase Extensions kurulumu2firebase ext:install firebase/firestore-send-email3firebase ext:install firebase/storage-resize-images4firebase ext:install firebase/firestore-translate-textPopüler extension'lar ve kullanım alanları:
Extension | Kullanım | Avantaj |
|---|---|---|
Resize Images | Storage'a yüklenen görselleri otomatik boyutlandır | CDN maliyetini %60 düşürür |
Send Email | Firestore trigger ile otomatik email | Mailgun/SendGrid entegrasyonu |
Translate Text | Doküman field'larını otomatik çevir | 100+ dil desteği |
Algolia Search | Firestore verisini full-text search index'le | Firestore'un limitli arama yetersizliğini çözer |
Stripe Payments | Ödeme entegrasyonu | PCI compliance hazır |
Firestore Data Modeling Kalıpları {#data-modeling}
NoSQL veritabanında doğru data modeling, performans ve maliyet açısından kritiktir:
swift
1// YANLIS: Derin nesting ve fazla subcollection2// users/{userId}/orders/{orderId}/items/{itemId}/reviews/{reviewId}3 4// DOGRU: Flat yapı + denormalization5// users/{userId}6// orders/{orderId} → userId field'ı ile ilişki7// orderItems/{itemId} → orderId field'ı ile ilişki8 9// Denormalization örneği - sipariş içine ürün bilgisi göm10struct Order: Codable {11 let id: String12 let userId: String13 let status: String14 let totalAmount: Double15 let items: [OrderItem] // Embed, ayrı sorgu gerekmez16 17 struct OrderItem: Codable {18 let productId: String19 let productName: String // Denormalized20 let productImage: String // Denormalized21 let quantity: Int22 let unitPrice: Double23 }24}25 26// Aggregation ile sayaç tutma (okuma maliyetini düşürür)27func incrementProductViewCount(productId: String) async throws {28 let ref = Firestore.firestore().collection("products").document(productId)29 try await ref.updateData([30 "viewCount": FieldValue.increment(Int64(1)),31 "lastViewedAt": FieldValue.serverTimestamp()32 ])33}Veri Modeli Karar Tablosu
Senaryo | Yaklaşım | Neden |
|---|---|---|
Kullanıcı profili + siparişleri | Ayrı collection, userId ile bağla | Siparişler bağımsız sorgulansın |
Sipariş + ürün bilgisi | Denormalize (ürün bilgisini göm) | Tek okuma yeterli olsun |
Chat mesajları | Subcollection (rooms/messages) | Sadece ilgili oda yüklensin |
Global ayarlar | Tek doküman | Az okuma, az maliyet |
Etiketler/kategoriler | Array field | Basit filtreleme yeterli |
Best Practices {#best-practices}
- Security rules her zaman yaz — boş bırakma
- Offline persistence aktif tut
- Listener'ları temizle — memory leak önle
- Denormalization — NoSQL'de join yok, veriyi düzleştir
- Cloud Functions — hassas logic client'ta olmasın
- Composite index — çoklu alan sorgularında Firestore Console'dan index oluştur
- Batch write — birden fazla yazma işlemini tek transaction'da yap
- TTL policy — eski dökümanları otomatik sil, maliyet ve boyut kontrolü sağla
Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Okuyucu Ödülü
Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var: **Kaynaklar:** - [Firebase Documentation](https://firebase.google.com/docs) - [Firestore Security Rules](https://firebase.google.com/docs/firestore/security/get-started) - [Cloud Functions](https://firebase.google.com/docs/functions)

