Bug Analizi Premium Sistem

Premium Üyelik Durumu Tutarsızlığı

Kök Neden Analizi ve Çözüm Stratejisi

muzibu.com 9 Ocak 2026 Tenant 1001

Problem Tanımı

Basit Anlatım (Herkes İçin)

Ne oluyor? Kullanıcı siteye girdiğinde her yerde "Premium Üye" olarak görünüyor. Ancak bir şarkıya tıkladığında aniden "Ücretsiz Üye" olarak değişiyor ve "Premium'a Geç" butonu çıkıyor.

Nasıl anlaşılıyor? Aynı kullanıcı, aynı anda, aynı sayfada hem premium hem ücretsiz görünüyor. Sol menüde taç var ama şarkı çalamıyor.

Örnek Senaryo:

  1. Kullanıcı siteye giriş yapıyor
  2. Sol menüde altın taç simgesi ve "Premium Üye" yazısı görüyor
  3. Bir şarkıya tıklıyor
  4. Aniden "Premium üyelik gerekli" uyarısı çıkıyor
  5. Kullanıcı şaşkın: "Ben zaten premium değil miyim?"

Teknik Detaylar (Geliştiriciler İçin)

Sistemde premium kontrolü yapan birden fazla farklı yöntem kullanılıyor. Her yöntem farklı kaynaklardan veri okuyor ve bazıları stale (eski) veri döndürüyor.

Tutarsız Olan:

  • Model property (stale olabilir)
  • Subscription relationship
  • Trial ayrı kontrolü
  • Cache'lenmiş veri

Tek Kaynak Olmalı:

  • users.subscription_expires_at
  • Fresh DB kontrolü
  • Merkezi isPremium() metodu

Etkilenen Alanlar

Sol Sidebar

Kullanıcı avatar'ı yanındaki premium rozeti ve üyelik tipi yazısı

sidebar.blade.php:58-82

Header Menüsü

"Premium'a Geç" butonu ve premium badge gösterimi

header.blade.php:623-677

Dashboard

Üyelik durumu kartı ve kalan süre gösterimi

dashboard.blade.php:32-70

CTA Banner

Premium teşvik banner'ı (3 farklı senaryo)

cta-banner.blade.php:4-96

Müzik Çalar API

Şarkı stream endpoint'i premium kontrolü

SongStreamController.php:82-102

Middleware

Route bazlı premium koruma katmanı

CheckPremiumSubscription.php:60-86

Kök Neden Analizi

1

Çoklu Kontrol Yöntemi

Sistemde premium kontrolü için birden fazla farklı yöntem kullanılıyor. Her bileşen kendi yöntemini kullanıyor ve bunlar birbiriyle uyumsuz olabiliyor.

Kullanılan Yöntemler:

  • Model Property: $user->subscription_expires_at (stale olabilir)
  • Relationship: $user->subscription() (ayrı sorgu)
  • Trial Kontrolü: isTrialActive() (ayrı mantık)
  • Service: SubscriptionService::checkUserAccess()
2

Stale Model Verisi

Sayfa yüklendiğinde User modeli bir kez yükleniyor. Ancak AJAX çağrılarında veya API isteklerinde model yeniden yüklenmiyor. Bu durumda eski (stale) veri kullanılabiliyor.

Senaryo:

  1. Sayfa yüklenir, User modeli okunur (subscription_expires_at: 2026-02-01)
  2. Sidebar bu değeri okur → Premium gösterir
  3. API isteği yapılır, farklı bir kontrol mekanizması devreye girer
  4. API fresh DB kontrolü yapar ama farklı koşul kullanır
  5. Sonuç: İki farklı yerde iki farklı durum
3

Trial ve Premium Ayrımı

Sistemde "trial" ve "premium" kavramları ayrı ayrı kontrol ediliyor. Bazı yerlerde sadece premium kontrol edilirken, bazı yerlerde trial ayrıca kontrol ediliyor.

Problem:

  • Sidebar: isPremium() kullanıyor
  • API: subscription status = 'active' kontrol ediyor
  • Trial kullanıcı API'da aktif görünmüyor

Mevcut Kontrol Noktaları Haritası

Dosya Satır Kontrol Yöntemi Kaynak Durum
User.php 380-398 isPremium() Fresh DB + Model Doğru
sidebar.blade.php 58-82 auth()->user()->isPremium() Model metodu Doğru
header.blade.php 623-677 currentUser?.is_premium (JS) Alpine.js store Kontrol Et
dashboard.blade.php 32-70 $user->isPremium() Controller'dan gelen Doğru
SongStreamController.php 82-102 $user->isPremium() Fresh model Doğru
SongStreamController.php 513-533 getSubscriptionData() Fresh DB query Doğru
SubscriptionService.php 314-356 checkUserAccess() subscription_expires_at Doğru
Middleware 60-86 subscription_expires_at Direct check Doğru

Çözüm: Tek Kaynak Prensibi (Single Source of Truth)

Hedef Mimari

Tek Kaynak:

users.subscription_expires_at

  • Tarih gelecekte ise = Premium
  • Tarih geçmişte veya NULL = Ücretsiz
  • Trial ayrımı yok (trial da premium sayılır)

Tek Metod:

User::isPremium()

  • Her yerde bu metod kullanılmalı
  • Fresh DB kontrolü yapmalı
  • Request-level cache olabilir

Uygulanacak Değişiklikler

1

User::isPremium() metodunu merkezi yap

Tüm premium kontrollerini bu metoda yönlendir

2

Header Alpine.js store'u güncelle

is_premium değerini backend'den doğru şekilde al

3

Trial kontrollerini kaldır

isTrialActive(), isPremiumOrTrial() metodlarını deprecate et

4

API response tutarlılığı sağla

Tüm API'larda aynı is_premium değerini döndür

İncelenmesi Gereken Dosyalar

Backend

  • app/Models/User.php
  • Modules/Subscription/app/Services/SubscriptionService.php
  • Modules/Muzibu/app/Http/Controllers/Api/SongStreamController.php
  • Modules/Muzibu/app/Http/Middleware/CheckPremiumSubscription.php
  • Modules/Muzibu/app/Services/DeviceService.php

Frontend (Blade)

  • resources/views/themes/muzibu/components/header.blade.php
  • resources/views/themes/muzibu/components/sidebar.blade.php
  • resources/views/themes/muzibu/components/sidebar-left.blade.php
  • resources/views/themes/muzibu/dashboard.blade.php
  • resources/views/themes/muzibu/components/subscription/cta-banner.blade.php

Özet

8+
Kontrol Noktası
3
Kök Neden
1
Tek Kaynak Hedefi