Subscription Master Plan

Trial + Premium + Tüm Sistem Birleştirme - 3 Tenant Analizi

📅 2025-12-04 🎯 Tenant 1, 2, 1001 🎵 Muzibu Odaklı

📊 Mevcut Durum: 3 Tenant Analizi

Central (tuufi.com)

✅ Users: 8 kullanıcı

✅ Plans: 2 plan

✅ Subscriptions: 1 aktif

Plans: premium-annual, premium-plan

Tenant 2 (ixtif.com)

✅ Plans: 2 plan

❌ Subscriptions: 0 kayıt (BOŞ!)

Plans: premium, gold

⚠️ Tablolar var ama kullanılmıyor

Tenant 1001 (muzibu) 🎯

✅ Plans: 1 plan

❌ Subscriptions: 0 kayıt (BOŞ!)

Plans: premium (4 cycle)

⚠️ Tablolar var ama kullanılmıyor

🔴 Kritik Bulgular

❌ EKSİKLER (Olması Gerekenler)

  • 1. users.has_used_trial field yok → Trial kontrolü yapılamıyor
  • 2. subscription_plans.is_trial field yok → Hangi plan trial belirsiz
  • 3. Ayrı Trial Plan yok → Cycle bazlı trial karışık
  • 4. Tenant subscriptions kullanılmıyor → İxtif ve Muzibu tenant DB'leri boş
  • 5. Cache-free check yok → isPremium() 1 saat cached
  • 6. Event system yok → Status değişimlerinde aksiyon alınamıyor

⚠️ FAZLALAR (Gereksiz/Karışık)

  • 1. 3 farklı tablo yapısı → Central, İxtif, Muzibu planları farklı field'lara sahip
  • 2. Kullanılmayan tenant tabloları → İxtif ve Muzibu subscription tabloları boş duruyor
  • 3. Plan ID çakışması → Central plan_id=1,2 / İxtif plan_id=3,4 / Muzibu plan_id=4
  • 4. Cycle bazlı trial → Her cycle'da farklı trial_days (karışık mantık)
  • 5. Pricing fields karmaşası → price_daily, price_weekly, price_monthly... vs billing_cycles JSON

🗑️ SİLİNMESİ GEREKENLER

  • 1. Tenant DB subscription tabloları → Kullanılmıyorlarsa kaldırılmalı veya aktif hale getirilmeli
  • 2. Legacy price fields → price_daily, price_weekly artık billing_cycles JSON var
  • 3. Eski enum billing_cycle → Artık dynamic cycle_key sistemi var
  • 4. Duplike plan kayıtları → 3 tenant'ta 5 plan, ama ID'ler çakışıyor

✅ Unified System Mantığı

🎯 Ana Prensip: Tek Elden Yönetim

Tüm subscription sistemi tek bir merkezden kontrol edilecek. Trial, Premium, Gold, her şey aynı mantıkla çalışacak.

Subscription Database Stratejisi:

Seçenek 1 (Önerilen): Sadece Central DB'de subscription'lar → Tüm tenant'lar Central'a bakar, tenant DB'lerdeki subscription tabloları silinir

Seçenek 2: Her tenant kendi DB'sinde → Tenant 2 ve 1001'deki boş tablolar aktif kullanılır

Hangi strateji seçilirse seçilsin, mantık aynı olacak:

Katman 1: Plan Sistemi (Master Data)

  • Trial Plan: Ayrı bir plan olarak (is_trial=true)
  • Premium Plan: Ücretli plan (is_trial=false)
  • Gold Plan: Üst seviye plan (is_trial=false)
  • Billing Cycles: JSON formatında dinamik (1-aylik, 3-aylik, 6-aylik, 12-aylik)
  • Her plan kendi trial_days değerine sahip olabilir ama kullanıcı sadece 1 kere trial kullanabilir

Katman 2: User Trial Kontrolü

  • has_used_trial field: User kayıt olunca false
  • Kullanıcı trial başlattığında → has_used_trial = true (ömür boyu)
  • Artık bu kullanıcı hiçbir trial plana kayıt olamaz
  • Premium'a geçebilir, iptal edip tekrar premium alabilir, ama trial bir daha asla

Katman 3: Subscription Lifecycle

  • pending_payment: Ödeme bekliyor
  • trial: Trial süresi aktif
  • active: Ücretli abonelik aktif
  • paused: Dondurulmuş
  • expired: Süresi dolmuş
  • cancelled: İptal edilmiş

⚡ Gerçek Zamanlı Kontrol Mantığı

🚨 Sorun: Kullanıcı 5 Yıl Giriş Yapmayabilir!

Senaryo 1: Trial Bitti Ama Çıkış Yapmadı

Kullanıcı 7 günlük trial aldı. 8. gün oldu ama uygulama açık, çıkış yapmıyor. Mevcut sistem: Cache 1 saat, kullanıcı sınırsız dinlemeye devam eder!

Senaryo 2: Premium Bitti Ama Uygulama Açık

Aylık premium aldı, 30 gün doldu. Ama mobil uygulama açık, token sürekli yenileniyor. Mevcut sistem: Kullanıcı aylarca bedava dinler!

✅ Çözüm: Request-Level Fresh Check

Her müzik isteğinde (stream endpoint) → Database'den fresh kontrol (cache yok!)

Kontrol mantığı:

  • Subscription var mı?
  • Status = active veya trial mi?
  • current_period_end > şu an mı?
  • Eğer hayır → 30 saniye preview
  • Eğer evet → Sınırsız dinle

📡 Event Sistemi Mantığı

Event'ler (Olaylar)

  • 🎯 SubscriptionCreated: Yeni abonelik oluştu
  • 🎯 TrialStarted: Trial başladı
  • 🎯 TrialEnding: Trial bitiyor (1 gün kala)
  • 🎯 TrialExpired: Trial bitti
  • 🎯 SubscriptionRenewed: Abonelik yenilendi
  • 🎯 SubscriptionExpired: Abonelik bitti
  • 🎯 SubscriptionCancelled: İptal edildi

Listener'lar (Aksiyonlar)

  • 📧 Email gönder: "Trial bitiyor, premium al"
  • 🔔 Bildirim gönder: "Aboneliğin yenilendi"
  • 🗄️ Cache temizle: isPremium() cache'ini sil
  • 📊 Analitik kaydet: Conversion tracking
  • 🎁 Bonus ver: Yenileme indirimi

🎯 İmplementasyon Adımları

1

Database Stratejisi Kararı

Subscription'lar nerede tutulacak? (Central only mı, her tenant kendi DB'sinde mi?) → Bu karar alınmadan devam edilemez!

2

Migration: Eksik Field'ler

users tablosuna has_used_trial ekle, subscription_plans tablosuna is_trial ekle

3

Trial Plan Oluştur

Ayrı bir "Ücretsiz Deneme" planı oluştur (is_trial=true, 7 gün süre)

4

isPremium() Cache-Free Versiyon

Stream endpoint için isPremiumFresh() metodu yaz (cache olmadan direkt DB kontrolü)

5

Event System Kur

Tüm event'leri oluştur (TrialStarted, TrialExpired, SubscriptionExpired...) ve listener'ları bağla

6

Cron: Expiry Checker

Dakikada 1 kontrol: Trial ve Premium biten subscription'ları bul, status güncelle, event fırlat

7

Test & Deploy

Tüm senaryoları test et (trial start, trial expire, premium buy, premium expire, cancel, renew...)

⚠️ İlk Karar: Subscription Nerede Tutulacak?

Seçenek 1: Central Only

Mantık: Tüm tenant'lar Central DB'ye bakar

Avantaj: Tek merkezden yönetim, kolay backup

Dezavantaj: Tenant isolation biraz zayıflar

Aksiyon: Tenant 2 ve 1001'deki subscription tabloları silinir

Seçenek 2: Her Tenant Kendi DB

Mantık: Her tenant kendi DB'sinde subscription tutar

Avantaj: Tam isolation, tenant data ayrı

Dezavantaj: Global rapor çıkarmak zor

Aksiyon: Tenant 2 ve 1001 subscription tabloları aktif kullanılır