🎵 Muzibu Platform - Complete Technical Guide

Site girişinden şarkı çalmaya, infinite scroll'a kadar tüm akış
📅 7 Aralık 2025 🎯 Tenant: muzibu.com (ID: 1001) 🔧 Redis Session + Hybrid Device Tracking
Kullanıcı Perspektifi (Basit)
Teknik Perspektif (AI/Developer)

1 Siteye Giriş (Login Flow)

👤 Kullanıcı Deneyimi

1. Giriş Sayfası

Kullanıcı e-posta ve şifresini girer, "Giriş Yap" butonuna tıklar.

2. Başarılı Giriş

Sayfa yenilenmeden giriş yapılır, header'da kullanıcı adı görünür.

3. Sidebar Durumu

  • Deneme Üyesi: Trial aktif
  • Premium Üye: Ödeme yapılmış
  • Ücretsiz Üye: Hiç subscription yok

4. Cihaz Limiti

İlk girişte hiç modal çıkmaz. Sadece limit aşılırsa (2+ cihaz) uyarı gösterilir.

⚙️ Teknik Detaylar

API Endpoint

POST /api/auth/login
{
  "email": "user@example.com",
  "password": "******",
  "remember": true
}

AuthController::login()

  1. Auth::attempt() - Credentials doğrula
  2. session()->regenerate() - Session ID yenile
  3. Cache::forget() - Premium cache temizle
  4. DeviceService::registerSession() - Cihaz kaydet

DeviceService::registerSession()

// 1. Session ID al (Redis'ten)
$sessionId = session()->getId();

// 2. user_active_sessions tablosuna kaydet
DB::table('user_active_sessions')
  ->updateOrInsert(
    ['session_id' => $sessionId],
    [
      'user_id' => $user->id,
      'device_name' => 'OS X - Chrome',
      'last_activity' => now()
    ]
  );

// 3. Limit kontrolü ve cleanup
$this->handlePostLoginDeviceLimit($user);

Session Storage

⚠️ Redis Session Driver Zorunlu!

# .env
SESSION_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379

Session Redis'te, device tracking DB'de (hybrid sistem)

2 Cihaz Limiti Sistemi

👤 Kullanıcı Deneyimi

Ne Zaman Uyarı Çıkar?

  • Başka bir cihazdan giriş yapılırsa
  • Ve cihaz limiti aşılırsa (genelde 1-2 cihaz)
  • Mevcut oturum sonlandırılırsa

Uyarı Modalı

Modal göründüğünde kullanıcı:

  • Hangi cihazları kapatacağını seçebilir
  • Veya mevcut oturumu koruyabilir

✅ İlk Girişte Modal YOK!

Tek cihazdan giriş yapıyorsanız hiçbir uyarı görmezsiniz. Sistem arka planda çalışır.

Cihaz Limitleri

Ücretsiz Üye 1 cihaz
Trial (Deneme) Plan'a göre
Premium Plan'a göre (1-5)

⚙️ Teknik Detaylar

3-Seviyeli Device Limit Hierarchy

DeviceService::getDeviceLimit($user):

1. User Override (VIP/Ban)
   → $user->device_limit (nullable)

2. Subscription Plan
   → $subscription->plan->device_limit

3. Tenant Settings Fallback
   → setting('auth_device_limit')

4. Ultimate Fallback
   → return 1;

Session Polling (30 saniye)

// player-core.js
startSessionPolling() {
  setInterval(() => {
    fetch('/api/auth/check-session')
      .then(r => r.json())
      .then(data => {
        if (!data.valid) {
          // Session sonlandırıldı
          showDeviceLimitModal();
        }
      });
  }, 30000);
}

Backend Check

// AuthController::checkSession()
$isValid = $deviceService
  ->updateSessionActivity($user);

if (!$isValid) {
  // Session DB'de yok = başka yerden kapatıldı
  Auth::logout();
  return [
    'valid' => false,
    'reason' => 'device_limit_exceeded'
  ];
}

⚠️ Dinamik Tenant Kontrolü

// YANLIŞ (hardcoded)
if (tenant()->id == 1001) { ... }

// DOĞRU (dinamik)
if (tenant()) {
  // Tüm tenant'lar için çalışır
  $deviceService->registerSession($user);
}

3 Üyelik Durumu (Premium/Trial)

👤 Kullanıcı Deneyimi

Sidebar'da Görünen Durum

DENEME Deneme Üyesi (Trial aktif)
PREMIUM Premium Üye (Ödeme yapılmış)
FREE Ücretsiz Üye (30sn önizleme)

Üyelik Avantajları

Ücretsiz 30sn önizleme, reklamlı
Deneme Tam erişim, sınırlı süre
Premium Tam erişim, HLS streaming

⚙️ Teknik Detaylar

User::isPremium()

// 5 dakikalık cache (performans)
$cacheKey = 'user_' . $this->id .
  '_is_premium_tenant_' . tenant()->id;

return Cache::remember($cacheKey, 300, function() {
  return $this->subscriptions()
    ->where('status', 'active')
    ->where('current_period_end', '>', now())
    ->exists();
});

User::isTrialActive()

return $this->subscriptions()
  ->whereIn('status', ['active', 'trial'])
  ->where('has_trial', true)
  ->whereNotNull('trial_ends_at')
  ->where('trial_ends_at', '>', now())
  ->exists();

Sidebar Badge Logic

// sidebar-left.blade.php
@if($user->isTrialActive())
  <span class="badge bg-yellow-500">
    Deneme Üyesi
  </span>
@elseif($user->isPremium())
  <span class="badge bg-green-500">
    Premium Üye
  </span>
@else
  <span class="badge bg-slate-500">
    Ücretsiz Üye
  </span>
@endif

Subscription Tablosu

subscriptions (tenant DB):
- id
- user_id
- plan_id
- status: 'active' | 'trial' | 'canceled'
- has_trial: boolean
- trial_ends_at: datetime
- current_period_end: datetime

4 Şarkı Çalma (Playback Flow)

👤 Kullanıcı Deneyimi

1. Şarkıya Tıkla

Herhangi bir şarkı kartına tıklayın. Player altta belirir.

2. Player Kontrolleri

  • ▶️ Oynat / ⏸️ Duraklat
  • ⏮️ Önceki / ⏭️ Sonraki
  • 🔀 Karıştır / 🔁 Tekrarla
  • 🔊 Ses kontrolü
  • 📋 Sıra görüntüle

3. Ücretsiz Kullanıcı Kısıtlaması

⚠️ 30 saniye önizleme sonrası şarkı durur ve Premium upgrade modal'ı gösterilir.

Premium/Trial Avantajı

  • Tam şarkı dinleme
  • HLS streaming (yüksek kalite)
  • Sırasız atlama
  • Offline indirme (yakında)

⚙️ Teknik Detaylar

player-core.js - play()

async play(song) {
  // 1. Premium kontrolü
  const isPremium = await this.checkPremiumStatus();

  // 2. URL al
  const url = isPremium
    ? `/api/muzibu/songs/${song.id}/stream` // HLS
    : `/api/muzibu/songs/${song.id}/serve?force_mp3=1`;

  // 3. Howler.js ile çal
  this.playWithHowler(url, song);
}

Streaming Endpoints

/stream HLS (.m3u8) - Premium
/serve MP3 direct - Free preview
/key AES-128 decryption key

Guest Preview Config

guestPreviewConfig: {
  maxPreviewDuration: 30,  // saniye
  showUpgradeModal: true,
  allowSeek: false,        // Seek engelli
  previewMessage: '30 saniyelik önizleme'
}

Seek Block (Free users)

// player-core.js:1085
if (!this.isPremium && seekTo > 30) {
  console.log('🔒 Seek blocked: max 30s');
  return;
}

5 Sıra Sistemi & Infinite Scroll

👤 Kullanıcı Deneyimi

1. Şarkı Sırası (Queue)

Player'da sıra ikonuna tıklayınca çalma listesi açılır. Sıradaki şarkıları görebilir, sürükleyip sıralayabilirsiniz.

2. Otomatik Devam

Bir şarkı bittiğinde otomatik olarak sıradaki şarkı başlar. Liste sonuna gelince yenileri yüklenir.

3. Bitmez Müzik (Infinite)

✨ Sıra azaldığında sistem otomatik olarak benzer şarkılar ekler. Müzik hiç bitmez!

4. Play Context

  • Playlist'ten çalınca → O playlist'in şarkıları
  • Albümden çalınca → O albümün şarkıları
  • Genre'den çalınca → O türün şarkıları

⚙️ Teknik Detaylar

Queue State Management

// muzibu-store.js
state: {
  queue: [],           // Şarkı listesi
  queueIndex: 0,       // Şu anki index
  playContext: {
    type: 'playlist',  // playlist|album|genre
    id: 123,
    name: 'Chill Vibes'
  }
}

Queue Monitor (10 saniye)

// player-core.js:3037
startQueueMonitor() {
  setInterval(() => {
    const remaining = queue.length - queueIndex;
    console.log(`Queue Check: ${remaining} songs`);

    if (remaining < 5) {
      this.refillQueue(); // Auto-refill
    }
  }, 10000);
}

Refill API

POST /api/muzibu/queue/refill
{
  "type": "genre",   // Context type
  "id": 3,           // Context ID
  "offset": 15,      // Skip already played
  "limit": 15        // How many to fetch
}

Response:
{
  "songs": [...],    // New songs
  "has_more": true
}

Aggressive Preload

// player-core.js:2944
aggressivePreload() {
  // Sonraki 3 şarkıyı önceden yükle
  const nextSongs = queue.slice(
    queueIndex + 1,
    queueIndex + 4
  );

  nextSongs.forEach(song => {
    this.preloadSong(song);
  });
}

6 Veritabanı Mimarisi

👤 Basit Açıklama

Multi-Tenant Sistem

Her web sitesi (tenant) kendi veritabanına sahip. Veriler birbirinden tamamen izole.

Central vs Tenant DB

  • Central: Kullanıcılar, roller, izinler
  • Tenant: Şarkılar, albümler, abonelikler, cihazlar

Redis Cache

Hızlı erişim için sıkça kullanılan veriler Redis'te saklanır. Session'lar da Redis'te.

⚙️ Teknik Detaylar

Database Mapping

Central (tuufi_4ekim):
├── users
├── roles
├── permissions
├── tenants
└── domains

Tenant (tenant_muzibu_1528d0):
├── songs
├── albums
├── artists
├── playlists
├── genres
├── subscriptions
├── subscription_plans
└── user_active_sessions  ← NEW!

user_active_sessions Table

CREATE TABLE user_active_sessions (
  id BIGINT PRIMARY KEY,
  user_id BIGINT,
  session_id VARCHAR(255) UNIQUE,
  ip_address VARCHAR(45),
  user_agent TEXT,
  device_type VARCHAR(50),
  device_name VARCHAR(255),
  browser VARCHAR(100),
  platform VARCHAR(100),
  last_activity TIMESTAMP,

  INDEX (user_id),
  INDEX (session_id)
);

⚠️ Hybrid Session System

Redis (SESSION_DRIVER=redis):
└── Session data, CSRF tokens, flash messages

MySQL (user_active_sessions):
└── Device tracking, queryable, reportable

Why hybrid?
- Redis = Fast, ephemeral
- MySQL = Queryable, persistent tracking

Test Sonuçları (7 Aralık 2025 - Canlı)

Session Kaydı

Login sonrası user_active_sessions tablosuna kayıt oluşturuluyor.

Total Sessions: 1
ID: 3
Device: OS X - Chrome
Last: 2025-12-07 18:54:17
Trial Status (Tinker)

User::isPremium() ve isTrialActive() doğru çalışıyor.

User: nurullah@nurullah.net
is_premium: true
is_trial: true
Sub Status: active
has_trial: true
trial_ends_at: 2025-12-08 17:42:49
Dinamik Tenant

Hardcoded "1001" referansları kaldırıldı. Artık tüm tenant'lar için çalışıyor.

// ÖNCE (hardcoded)
if (tenant()->id == 1001) { ... }

// SONRA (dinamik)
if (tenant()) { ... }
is_trial Flag

Login/me response'a is_trial flag eklendi. Sidebar doğru badge gösteriyor.

// API Response
{
  "is_premium": true,
  "is_trial": true,  // YENİ!
  "trial_ends_at": "2025-12-08T..."
}
Redis Session

SESSION_DRIVER=redis, hybrid sistem çalışıyor. Session Redis'te, tracking DB'de.

Device Limit

İlk girişte modal çıkmıyor. Sadece limit aşılınca (2+ cihaz) uyarı gösterilir.

Console Log Özeti: Session polling başlatıldı (30s), Queue monitor aktif (10s), Aggressive preload çalışıyor (next 3 songs), HLS streaming hazır.

📁 Anahtar Dosyalar

Backend (PHP/Laravel)

Modules/Muzibu/app/Services/DeviceService.php app/Http/Controllers/Api/Auth/AuthController.php app/Models/User.php Modules/Subscription/app/Models/Subscription.php

Frontend (JS/Blade)

public/themes/muzibu/js/player/core/player-core.js public/themes/muzibu/js/store/muzibu-store.js resources/views/themes/muzibu/components/sidebar-left.blade.php resources/views/themes/muzibu/components/device-limit-modal.blade.php