Gereksinimler ve Ön Hazırlık
Projeye başlamadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. Flutter 3.24 ve üzeri sürümler, performans iyileştirmeleri ve yeni nesil widget desteği ile bu proje için en uygun tercihtir. Ayrıca, backend tarafında Firebase (Firestore ve Storage) kullanarak sunucusuz (serverless) bir mimari kuracağız.
- Flutter SDK 3.24+
- Dart 3.5+
- Firebase Projesi (Authentication, Firestore, Storage aktif edilmeli)
- VS Code veya Android Studio
Geliştirme sürecinde bağımlılık yönetimi için pubspec.yaml dosyanıza firebase_core, cloud_firestore, firebase_storage ve image_picker paketlerini eklemeyi unutmayın.
Veri Modeli ve İlan Yapısı Tasarımı
İlan sisteminin kalbi, veritabanı şemasıdır. İlanlarınızı tutarlı bir yapıda saklamak, ileride arama ve filtreleme yaparken büyük kolaylık sağlar. Firestore'da her ilan için aşağıdaki gibi bir "Map" yapısı kurmak en verimli yöntemdir.
class ProductModel {
final String id;
final String title;
final double price;
final String category;
final String imageUrl;
final DateTime createdAt;
ProductModel({
required this.id,
required this.title,
required this.price,
required this.category,
required this.imageUrl,
required this.createdAt,
});
Map toMap() {
return {
'title': title,
'price': price,
'category': category,
'imageUrl': imageUrl,
'createdAt': createdAt.toIso8601String(),
};
}
}
Yukarıdaki kod, ilan verilerini veritabanına göndermeden önce standart bir formata dönüştürür. Bu, veritabanı tutarlılığını korumak için kritik bir adımdır.
Firebase Storage ile Görsel Yükleme Adımları
İkinci el ürünlerin en önemli parçası fotoğraflardır. Kullanıcının galerisinden seçtiği görselleri doğrudan veritabanına kaydetmek yerine, Firebase Storage'a yükleyip dönen URL'yi Firestore'da saklamalısınız.
Future uploadImage(File image) async {
final ref = FirebaseStorage.instance.ref().child('product_images/${DateTime.now().toString()}');
await ref.putFile(image);
return await ref.getDownloadURL();
}
Bu fonksiyon, seçilen görseli Firebase Storage'a yükler ve yükleme tamamlandığında dosyanın erişim linkini döndürür. Bu linki ProductModel içerisindeki imageUrl alanına kaydedebilirsiniz.
İlan Listeleme ve StreamBuilder Kullanımı
Gerçek zamanlı bir deneyim için StreamBuilder widget'ı vazgeçilmezdir. Bu widget, veritabanındaki veriler her değiştiğinde arayüzü otomatik olarak günceller.
StreamBuilder(
stream: FirebaseFirestore.instance.collection('products').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
var product = snapshot.data!.docs[index];
return ListTile(
title: Text(product['title']),
subtitle: Text('${product['price']} TL'),
);
},
);
},
)
Bu kod bloğu, veritabanındaki "products" koleksiyonunu dinler ve yeni bir ilan eklendiğinde liste otomatik olarak güncellenir. Kullanıcıya canlı bir deneyim sunmak için oldukça etkilidir.
İlan Filtreleme ve Arama Mantığı
İleri düzey bir sistemde kullanıcılar ürünleri kategoriye veya fiyata göre filtrelemek isteyecektir. Firestore üzerinde where sorguları kullanarak bu işlemi gerçekleştirebilirsiniz.
FirebaseFirestore.instance
.collection('products')
.where('category', isEqualTo: 'Elektronik')
.orderBy('price', descending: true)
.get();
Bu sorgu, sadece "Elektronik" kategorisindeki ürünleri getirir ve fiyatı en yüksekten en düşüğe sıralar. Bu tür sorgular için Firestore üzerinde indeks oluşturmanız gerekebilir.
Güvenlik Uyarısı: Firestore kurallarınızı (Security Rules) mutlaka yapılandırın. Kullanıcıların sadece kendi ilanlarını düzenleyebilmelerini sağlamak için
allow update: if request.auth.uid == resource.data.userId;kuralını kullanın.
Veritabanı Yaklaşımlarının Karşılaştırılması
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Firebase Firestore | Gerçek zamanlı, kurulumu kolay | Karmaşık sorgularda maliyet artabilir |
| Supabase (PostgreSQL) | İlişkisel veri, gelişmiş sorgular | Daha dik öğrenme eğrisi |
Sıkça Sorulan Sorular
İlan görsellerini sıkıştırmak gerekli mi?
Evet, kullanıcı deneyimini artırmak ve veri kullanımını azaltmak için görselleri yüklemeden önce flutter_image_compress paketi ile boyutlandırmanız önerilir.
İlanlara yorum sistemi nasıl eklenir?
İlanların altına "comments" adında bir alt koleksiyon oluşturarak, her yorumu ilan ID'sine bağlayarak kolayca yönetebilirsiniz.
Uygulama çevrimdışı çalışabilir mi?
Firestore, yerel önbellekleme (offline persistence) özelliğine sahiptir. İnternet bağlantısı koptuğunda veriler yerelde saklanır ve bağlantı geldiğinde senkronize edilir.
Güvenliği nasıl artırabilirim?
Firebase Authentication kullanarak sadece doğrulanmış kullanıcıların ilan vermesine izin verin ve her zaman sunucu tarafında (Firebase Functions) doğrulama yapın.
İlan süresi dolduğunda ne yapmalıyım?
Bir "expiryDate" alanı ekleyerek, arka plan işlemleriyle süresi dolan ilanları otomatik olarak pasif duruma getirebilirsiniz.
İlan Sistemlerinde Performans Optimizasyonu: Pagination ve Lazy Loading
İkinci el ürün platformlarında veritabanında binlerce ilan biriktiğinde, tüm veriyi tek bir StreamBuilder ile çekmek uygulamanın hem bellek tüketimini artırır hem de kullanıcı deneyimini olumsuz etkiler. Firestore üzerinde Pagination (Sayfalandırma) kullanarak verileri parçalar halinde yüklemek, uygulamanızın performansını optimize etmenin en etkili yoludur.
Aşağıdaki örnekte, QuerySnapshot kullanarak verileri 10'arlı gruplar halinde nasıl çekeceğinizi görebilirsiniz:
// İlanları sayfalara bölerek getirme mantığı
DocumentSnapshot? lastDocument;
bool hasMore = true;
Future fetchAds() async {
if (!hasMore) return [];
Query query = FirebaseFirestore.instance
.collection('ads')
.orderBy('createdAt', descending: true)
.limit(10);
if (lastDocument != null) {
query = query.startAfterDocument(lastDocument!);
}
QuerySnapshot querySnapshot = await query.get();
if (querySnapshot.docs.length < 10) {
hasMore = false;
}
if (querySnapshot.docs.isNotEmpty) {
lastDocument = querySnapshot.docs.last;
}
return querySnapshot.docs;
}
Uygulama İçi Ödeme ve Güvenli İşlem Yönetimi
İkinci el sistemlerinde "Öne Çıkarılan İlanlar" gibi özellikler için uygulama içi satın alma (In-App Purchase) entegrasyonu kritik bir gelir modelidir. Flutter'da in_app_purchase paketini kullanarak kullanıcıların ilanlarını üst sıralara taşımasını sağlayabilirsiniz.
Ödeme süreçlerinde dikkat etmeniz gereken temel kurallar şunlardır:
- Doğrulama: Satın alma işlemini sadece istemci tarafında değil, Firebase Cloud Functions kullanarak sunucu tarafında da doğrulamalısınız.
- Durum Yönetimi: Ödeme başarılı olduğunda, veritabanındaki
isPremiumveyapriorityScorealanlarını güncelleyerek ilan sıralamasını dinamik olarak değiştirin. - Hata Yönetimi: İnternet kesintisi veya kullanıcı iptali durumlarında işlemin yarım kalmaması için
PendingPurchasesdinleyicilerini mutlaka yapılandırın.
// Ödeme sonrası ilan durumunu güncelleme örneği
Future upgradeAdToPremium(String adId) async {
await FirebaseFirestore.instance.collection('ads').doc(adId).update({
'isPremium': true,
'priorityScore': FieldValue.increment(100),
'updatedAt': FieldValue.serverTimestamp(),
});
}
Test Süreçleri ve Hata Ayıklama
Uygulamanızın üretim ortamına geçmeden önce Integration Testing ile gerçek bir Firebase projesi üzerinde ilan oluşturma, silme ve filtreleme akışlarını test etmeniz gerekir. flutter_test kütüphanesini kullanarak kullanıcı arayüzü bileşenlerinizin (Widget) farklı ekran boyutlarında nasıl tepki verdiğini kontrol etmeyi ihmal etmeyin.
Sonuç
Flutter ve Firebase kullanarak profesyonel bir ikinci el ürün ilan sistemi inşa etmek, doğru mimari ile oldukça verimli bir süreçtir. Bu rehberde öğrendiğiniz veri modelleme, gerçek zamanlı listeleme ve güvenlik kuralları, uygulamanızın temelini oluşturacaktır. Bir sonraki aşamada, kullanıcılar arası mesajlaşma (Chat) özelliğini ekleyerek projenizi bir adım öteye taşıyabilirsiniz.
Sorumluluk Reddi: Bu rehber eğitim amaçlıdır. Üretim ortamına çıkmadan önce veri gizliliği, ödeme sistemleri entegrasyonu ve sunucu tarafı güvenlik (API anahtarlarının gizlenmesi vb.) konularında profesyonel güvenlik denetimlerinden geçmeniz tavsiye edilir.


Yorumlar (0)
Yorum Yaz