Ön Hazırlık ve Gereksinimler
Bu projeyi başarıyla tamamlamak için sisteminizde PHP 8.2 veya üzeri bir sürümün, Laravel 11 framework'ünün ve temel düzeyde veritabanı bilgisine sahip olmanız gerekmektedir. Ayrıca, abonelik yönetimi için Laravel Cashier veya benzeri bir ödeme entegrasyonu kullanıyor olmanız, süreci daha verimli kılacaktır.
- PHP 8.2+ ve Composer kurulu bir geliştirme ortamı.
- Laravel 11 projesi.
- Veritabanı (MySQL veya PostgreSQL) bağlantısı.
- İsteğe bağlı: Laravel Cashier (Stripe/Paddle entegrasyonu için).
Veritabanı Yapılandırması ve Soft Delete Kullanımı
Kullanıcıları veritabanından tamamen silmek yerine, "soft delete" yöntemini kullanarak verileri arşivlemek en güvenli yaklaşımdır. Bu, yanlışlıkla yapılan silme işlemlerini geri almayı kolaylaştırır ve analitik verilerin korunmasını sağlar.
Öncelikle, users tablonuza deleted_at sütununu ekleyen bir migration oluşturmalısınız. Laravel'in SoftDeletes trait'ini modelinize ekleyerek bu özelliği aktif edebilirsiniz.
// app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
}
Model içerisinde SoftDeletes trait'ini kullanmak, Laravel'in delete() metodunu çağırdığınızda veriyi silmek yerine deleted_at sütununu doldurmasını sağlar. Sorgularınızda bu kayıtlar otomatik olarak filtrelenir.
Abonelik İptal Sürecinin Mantıksal Tasarımı
Abonelik iptali, kullanıcı silme işleminden önce gerçekleşmesi gereken bir "ön koşul"dur. Kullanıcının aktif bir ödeme planı varsa, önce bu planın ödeme sağlayıcısı tarafında durdurulması, ardından yerel veritabanında güncellenmesi gerekir.
Aşağıdaki tablo, abonelik yönetimi için tercih edilebilecek farklı durumları özetlemektedir:
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Anında İptal | Hızlı ve kesin sonuç. | Kullanıcı kalan günlerini kaybedebilir. |
| Dönem Sonu İptal | Kullanıcı memnuniyeti yüksek. | Karmaşık zamanlama gerektirir. |
Adım Adım Abonelik İptali ve Servis Entegrasyonu
Abonelik iptali için bir servis sınıfı oluşturmak, kodunuzun temiz ve test edilebilir kalmasını sağlar. Bu sınıf, ödeme sağlayıcınızla haberleşerek aboneliği "cancel" durumuna getirir.
// app/Services/SubscriptionService.php
namespace App\Services;
use App\Models\User;
class SubscriptionService
{
public function cancelSubscription(User $user)
{
// Ödeme sağlayıcısı (örn: Stripe) üzerinden iptal
if ($user->subscription('default')->active()) {
$user->subscription('default')->cancel();
return true;
}
return false;
}
}
Bu servis metodu, kullanıcının mevcut aboneliğini kontrol eder ve aktifse iptal komutunu gönderir. Hata yönetimi için try-catch blokları eklemek, API hatalarını yakalamanıza yardımcı olur.
Kullanıcı Hesap İptali İçin Kontrolcü (Controller) Mantığı
Kullanıcı hesabını silerken hem aboneliği iptal etmeli hem de kullanıcıyı sistemden "çıkış" yapmaya zorlamalısınız. Bu işlem için UserController içerisinde bir destroy metodu tanımlayalım.
// app/Http/Controllers/UserController.php
public function destroy(Request $request, SubscriptionService $subscriptionService)
{
$user = $request->user();
// 1. Aboneliği iptal et
$subscriptionService->cancelSubscription($user);
// 2. Kullanıcıyı sil
$user->delete();
// 3. Oturumu sonlandır
Auth::logout();
return redirect('/')->with('status', 'Hesabınız başarıyla silindi.');
}
Bu kod bloğu, kullanıcının tüm süreçlerini tek bir istekte yönetir. Güvenlik için $request->user() kullanarak sadece giriş yapmış kullanıcının kendi hesabını silebildiğinden emin olun.
Kritik Güvenlik Uyarısı: Kullanıcı silme işlemlerinde mutlaka yetkilendirme (Policy) kullanın. Kullanıcıların başkalarının hesabını silmesini engellemek içinUserPolicytanımladığınızdan ve$this->authorize('delete', $user)kontrolünü yaptığınızdan emin olun.
Süreçlerin Otomatize Edilmesi: Job ve Event Kullanımı
Büyük sistemlerde kullanıcı silme işlemi sadece veritabanı kaydıyla bitmez; e-posta bildirimleri, dosya temizliği ve loglama gibi işlemler de gerekir. Bu tür ağır işlemleri Job sınıfları ile arka plana (queue) atmak, uygulamanızın hızını artırır.
// app/Jobs/ProcessUserDeletion.php
public function handle()
{
// Kullanıcıya ait dosyaları temizle
Storage::deleteDirectory('users/' . $this->user->id);
// Kullanıcıya bilgilendirme e-postası gönder
Mail::to($this->user->email)->send(new AccountDeletedMail());
}
Bu işi UserController içerisinde ProcessUserDeletion::dispatch($user) şeklinde tetikleyerek, ana işlemin beklemesini engelleyebilirsiniz.
Sıkça Sorulan Sorular
Soft Delete kullanırken veritabanı performansı nasıl etkilenir?
Soft delete, tablolarda deleted_at sütununa bir index eklediğiniz sürece performans üzerinde ihmal edilebilir bir etkiye sahiptir. Büyük veritabanlarında düzenli olarak "arşivleme" veya "temizleme" görevleri (scheduled tasks) çalıştırmak performansı korur.
Abonelik iptal edilmezse kullanıcı silinebilir mi?
Teknik olarak evet, ancak bu durum ödeme sağlayıcınızda "zombi aboneliklerin" kalmasına neden olur. Bu da hem finansal raporlarınızı bozar hem de kullanıcıdan haksız yere ücret çekilmesine sebep olabilir.
Kullanıcı silme işleminden sonra verileri ne kadar saklamalıyım?
Yasal zorunluluklar ülkeye göre değişse de, genellikle finansal kayıtlar için 5-10 yıl saklama zorunluluğu vardır. Bu nedenle verileri tamamen silmek yerine veritabanında "anonimleştirerek" saklamak en iyi pratiktir.
Kullanıcı silme işlemini geri alabilir miyim?
Evet, $user->restore() metodunu kullanarak soft delete ile silinmiş bir kullanıcıyı kolayca geri getirebilirsiniz.
API üzerinden abonelik iptali nasıl güvenli hale getirilir?
API isteklerinde mutlaka Sanctum veya Passport gibi token tabanlı kimlik doğrulama kullanın ve iptal işlemini gerçekleştiren endpoint'i POST veya DELETE metoduna sınırlayın.
GDPR ve KVKK Uyumluluğu İçin Veri Anonimleştirme Stratejileri
Kullanıcı hesabını sildiğinde veya aboneliğini iptal ettiğinde, yasal düzenlemeler gereği verilerin anonimleştirilmesi kritik bir adımdır. Sadece deleted_at sütununu doldurmak, verilerin veritabanında "okunabilir" kalmasına neden olur. Bu durum, KVKK veya GDPR gibi regülasyonlar kapsamında risk teşkil edebilir.
Verileri anonimleştirmek için Laravel'in Model Observers yapısını kullanarak, silme işlemi gerçekleştiği anda kişisel verilerin üzerine rastgele karakterler yazan bir mekanizma kurabilirsiniz.
// app/Observers/UserObserver.php
public function deleting(User $user)
{
$user->update([
'email' => 'deleted_' . $user->id . '@example.com',
'name' => 'Anonim Kullanıcı',
'phone' => null,
'address' => null,
]);
}
Bu yaklaşım, veritabanı ilişkilerini (Foreign Keys) bozmadan, kullanıcının kimlik bilgilerini geri döndürülemez şekilde maskelemenizi sağlar. İstatistiksel verileriniz (örneğin: "kaç kişi üye oldu") korunurken, kişisel verileriniz temizlenmiş olur.
İptal Süreçlerinde Hata Ayıklama ve Loglama
Abonelik iptal süreçleri, üçüncü taraf ödeme servisleri (Stripe, Iyzico vb.) ile sürekli iletişim halindedir. Ağ hataları, API limitleri veya geçersiz istekler nedeniyle iptal işlemleri başarısız olabilir. Bu tür durumları yönetmek için özel bir SubscriptionLog tablosu tutmak, sisteminizin izlenebilirliğini artırır.
Hataları yakalamak ve merkezi bir şekilde yönetmek için try-catch bloklarını servis katmanınızda şu şekilde yapılandırabilirsiniz:
// app/Services/SubscriptionService.php
public function cancelSubscription(User $user)
{
try {
$response = $this->paymentGateway->cancel($user->subscription_id);
if (!$response->successful()) {
throw new Exception("Ödeme sağlayıcısı hatası: " . $response->error());
}
$user->subscription->update(['status' => 'canceled']);
} catch (\Exception $e) {
Log::error("Abonelik iptal hatası [User ID: {$user->id}]: " . $e->getMessage());
// Hata durumunda kullanıcıya bildirim gönder veya yöneticiyi uyar
Notification::send($user, new SubscriptionCancellationFailed($e->getMessage()));
return false;
}
return true;
}
İleri Düzey İpuçları
- Graceful Degradation: Ödeme servisi yanıt vermediğinde, kullanıcıya "İşleminiz işleme alındı, onay bekliyor" gibi bir mesaj göstererek kullanıcı deneyimini koruyun.
- Event Sourcing: Kullanıcının abonelik geçmişini sadece bir tabloda tutmak yerine, bir
subscription_eventstablosunda tüm geçişleri (created, updated, canceled, resumed) saklayarak denetim izi (audit trail) oluşturun. - Queue Priority: İptal işlemlerini
highöncelikli kuyruklara atayarak, ödeme sistemindeki gecikmelerin kullanıcıyı bekletmesini engelleyin.
Sonuç
Laravel ile dinamik bir kullanıcı ve abonelik iptal sistemi kurmak, veritabanı tutarlılığı ve kullanıcı güvenliği açısından titizlik gerektiren bir süreçtir. Soft delete kullanımı, servis tabanlı mimari ve arka plan işleri (Jobs) sayesinde, kullanıcılarınıza sorunsuz bir ayrılma deneyimi sunabilirsiniz.
Sorumluluk Reddi: Bu makaledeki kod örnekleri genel eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka kendi iş mantığınıza göre test edin, güvenlik açıklarını (SQL injection, XSS) denetleyin ve ödeme sağlayıcınızın (Stripe, Iyzico vb.) güncel API dokümantasyonunu inceleyin.
Bir sonraki adım olarak, silinen kullanıcıların verilerini otomatik olarak anonimleştiren bir "Data Retention Policy" (Veri Saklama Politikası) mekanizması geliştirmeyi düşünebilirsiniz.

Yorumlar (0)
Yorum Yaz