📊 Genel Durum
Müjdeli Haber: Sisteminizde çok kapsamlı bir aktivite takip sistemi zaten çalışıyor! Üyelerinizin sitede yaptığı neredeyse her işlem kayıt altına alınıyor.
📝 Basit Anlatım (Herkes İçin)
Hangi Aktiviteler Kayıt Ediliyor?
Üye ne zaman siteye girdi, ne zaman çıktı, hangi cihazdan bağlandı
İsim, e-posta, telefon gibi hangi bilgileri ne zaman güncelledi
Hangi şarkıyı, ne kadar süre dinledi, atladı mı, nereden çaldı (playlist, albüm...)
Hangi şarkı, albüm veya playlist'i favorilerine ekledi/çıkardı
Playlist oluşturma, düzenleme, silme, şarkı ekleme/çıkarma
Ne zaman yorum yaptı, hangi içeriğe yorum yaptı
Hangi cihazdan (telefon, tablet, bilgisayar), hangi tarayıcıdan bağlandı
Kaç aktif oturum var, son aktivite ne zaman
Bu Veriler Neden Önemli?
-
Kullanıcı Davranışını Anlama: Üyeler hangi saatlerde aktif, hangi içerikleri tercih ediyor?
-
Güvenlik: Şüpheli aktiviteler (çok fazla başarısız giriş, farklı cihazdan erişim) tespit edilebilir
-
İçerik Stratejisi: Hangi şarkılar çok dinleniyor, hangileri atlanıyor? Buna göre öneriler yapılabilir
-
Kullanıcı Desteği: Üyenin geçmiş aktiviteleri görülerek sorunlar daha hızlı çözülebilir
Bu Kayıtlar Nasıl Görülebilir?
- •
/admin/activity-logs→ Tüm sistem aktivitelerini gösterir - •
/admin/users/[id]/activity-logs→ Belirli bir üyenin tüm aktivitelerini gösterir
- • Tarih aralığı seçme (belirli bir ay, hafta, gün)
- • Aktivite tipine göre filtreleme (sadece giriş/çıkış, sadece dinlemeler...)
- • Modüle göre filtreleme (Müzik, Kullanıcı, Playlist...)
- • Arama yapma (örn: "Yağmur Yağar" şarkısı kim dinledi?)
Eksik veya Geliştirilebilir Alanlar
Şarkı indirme işlemleri için özel bir tablo yok. Activity log'dan takip edilebilir ama daha detaylı olabilir.
Veriler toplanıyor ama görsel istatistik paneli (günlük aktif kullanıcı, en çok dinlenen saatler...) geliştirilebilir.
🔧 Teknik Detaylar (Geliştiriciler İçin)
Sistem Mimarisi
Aktivite takip sistemi 4 ana bileşenden oluşuyor:
1. Spatie Activity Log
Genel aktivite logları (CRUD işlemleri, kullanıcı işlemleri)
activity_log
2. Song Plays System
Müzik dinleme analitikleri (duration, skip, source tracking)
muzibu_song_plays
3. Session Management
Aktif oturum takibi (device, IP, last_activity)
user_active_sessions
4. User Model Fields
Kullanıcı tablosunda doğrudan saklanan aktivite verileri
users (last_login_at, last_played_song_id)
1. Activity Log Tablosu (activity_log)
Tablo Yapısı:
CREATE TABLE activity_log (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
log_name VARCHAR(255) NULL COMMENT 'Modül adı (Song, Album, User...)',
description TEXT NOT NULL COMMENT 'İşlem açıklaması',
subject_type VARCHAR(255) NULL COMMENT 'Etkilenen model (polymorphic)',
subject_id BIGINT UNSIGNED NULL,
causer_type VARCHAR(255) NULL COMMENT 'İşlemi yapan (User)',
causer_id BIGINT UNSIGNED NULL,
event VARCHAR(255) NULL COMMENT 'created, updated, deleted...',
properties JSON NULL COMMENT 'Ek bilgiler',
batch_uuid CHAR(36) NULL COMMENT 'Toplu işlem UUID',
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX causer (causer_type, causer_id, created_at),
INDEX subject (subject_type, subject_id, created_at),
INDEX created_at,
INDEX log_name,
INDEX event,
FULLTEXT KEY activity_search (description, properties)
) ENGINE=InnoDB;
Properties JSON Yapısı:
{
"baslik": "Model başlığı (Song name, User name...)",
"modul": "Song / Album / User / Playlist...",
"degisenler": ["field1", "field2", "field3"],
"event_key": "oluşturuldu / güncellendi / silindi",
"eski_baslik": "Eski başlık (değişmişse)"
}
Log Oluşturma Helper:
// Lokasyon: /app/Helpers/Functions.php
function log_activity(
\Illuminate\Database\Eloquent\Model $model,
string $event,
?array $degisenler = null,
$old_title = null
): void {
activity()
->causedBy(auth()->user())
->performedOn($model)
->event($event)
->withProperties([
'baslik' => $model->name ?? $model->title,
'modul' => class_basename($model),
'degisenler' => $degisenler,
'event_key' => $event,
'eski_baslik' => $old_title
])
->log($event);
}
Kullanım Örneği (Observer):
// Örnek: SongObserver
public function updated(Song $song)
{
$changes = $song->getDirty();
unset($changes['play_count']); // play_count her dinlemede değişir, log'lama
if (!empty($changes)) {
log_activity(
$song,
'güncellendi',
array_keys($changes),
$song->getOriginal('title')
);
}
}
- • Helper:
/app/Helpers/Functions.php - • Config:
/config/activitylog.php - • Migration:
/database/migrations/*_create_activity_log_table.php - • Fulltext Index:
/Modules/UserManagement/database/migrations/2026_01_18_020000_add_fulltext_index_to_activity_log.php
2. Song Plays System (muzibu_song_plays)
Tablo Yapısı:
CREATE TABLE muzibu_song_plays (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
song_id BIGINT UNSIGNED NOT NULL,
user_id BIGINT UNSIGNED NULL COMMENT 'NULL = Anonymous',
-- Dinleme Detayları
created_at TIMESTAMP NULL COMMENT 'Başlangıç zamanı',
ended_at TIMESTAMP NULL COMMENT 'Bitiş zamanı',
listened_duration INT NULL COMMENT 'Dinlenen süre (saniye)',
was_skipped BOOLEAN DEFAULT 0 COMMENT 'Atlanan mı?',
-- Kaynak Bilgisi
source_type VARCHAR(50) NULL COMMENT 'playlist, album, artist, search, radio, queue',
source_id BIGINT UNSIGNED NULL,
-- Cihaz Bilgileri
ip_address VARCHAR(45) NULL,
user_agent TEXT NULL,
device_type VARCHAR(20) NULL COMMENT 'mobile, tablet, desktop',
browser VARCHAR(50) NULL COMMENT 'Chrome, Firefox, Safari...',
platform VARCHAR(50) NULL COMMENT 'Windows, iOS, Android...',
updated_at TIMESTAMP NULL,
INDEX user_ended (user_id, ended_at),
INDEX source (source_type, source_id),
INDEX song_created (song_id, created_at)
) ENGINE=InnoDB;
Model Scopes ve Analitik Metodlar:
// Lokasyon: /Modules/Muzibu/App/Models/SongPlay.php
// Zaman Filtreleri
SongPlay::today()->get(); // Bugün dinlenenler
SongPlay::thisWeek()->get(); // Bu hafta
SongPlay::thisMonth()->get(); // Bu ay
// Cihaz Filtreleri
SongPlay::byDevice('mobile')->get(); // Mobil cihazlardan
SongPlay::byDevice('desktop')->get(); // Masaüstünden
// Davranış Filtreleri
SongPlay::skipped()->get(); // Atlanan şarkılar
SongPlay::completed()->get(); // Tamamlanan
SongPlay::shortListens(10)->get(); // 10 saniyeden az dinlenenler (abuse detection)
// Kaynak Filtreleri
SongPlay::fromSource('playlist', 123)->get(); // Playlist'ten çalınanlar
SongPlay::fromSource('album', 456)->get(); // Albümden çalınanlar
// Analitik Metodlar
SongPlay::getTopSongs(10, 'week'); // Haftanın en çok dinlenen 10 şarkısı
SongPlay::getDeviceDistribution(); // Cihaz dağılımı (% mobile, % desktop)
SongPlay::getHourlyDistribution(); // Saatlik dinleme dağılımı
SongPlay::getUniqueListenersCount($songId); // Benzersiz dinleyici sayısı
SongPlay::getSkipRate($userId); // Kullanıcının atlama oranı
SongPlay::getAverageListenDuration($songId); // Ortalama dinleme süresi
- • Model:
/Modules/Muzibu/App/Models/SongPlay.php - • Migration:
/Modules/Muzibu/database/migrations/*_create_song_plays_table.php - • Observer:
/Modules/Muzibu/App/Observers/SongObserver.php
3. Session Management (user_active_sessions)
Tablo Yapısı:
CREATE TABLE user_active_sessions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNSIGNED NOT NULL,
session_id VARCHAR(255) NOT NULL,
ip_address VARCHAR(45) NULL,
user_agent TEXT NULL,
last_activity TIMESTAMP NULL COMMENT 'Son aktivite zamanı',
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
INDEX user_last_activity (user_id, last_activity),
UNIQUE KEY unique_session (session_id)
) ENGINE=InnoDB;
Kullanım Senaryoları:
-
Çoklu Oturum Kontrolü:
Kullanıcı aynı anda kaç cihazdan bağlı?
-
Şüpheli Aktivite Tespiti:
Farklı IP'lerden eş zamanlı giriş var mı?
-
Cihaz Yönetimi:
Kullanıcı diğer oturumlarını sonlandırabilir
last_activity alanı her sayfa isteğinde güncelleniyor.
Bu sayede kullanıcının ne zaman son aktif olduğu anında görülebilir.
4. User Model Fields (Doğrudan Kullanıcı Tablosu)
Aktivite İle İlgili Alanlar:
ALTER TABLE users ADD COLUMN:
last_login_at TIMESTAMP NULL COMMENT 'Son giriş zamanı',
last_played_song_id BIGINT UNSIGNED NULL COMMENT 'Son çalınan şarkı',
subscription_expires_at DATETIME NULL COMMENT 'Abonelik bitiş tarihi',
failed_login_attempts INT DEFAULT 0 COMMENT 'Başarısız giriş denemesi',
locked_until TIMESTAMP NULL COMMENT 'Hesap kilitli mi?';
Model Metodları:
// Güvenlik Metodları
$user->incrementFailedLogins(); // Başarısız giriş sayısını artır
$user->resetFailedLogins(); // Sayacı sıfırla (başarılı giriş sonrası)
$user->isLocked(); // Hesap kilitli mi kontrol et
// Son Aktivite
$user->last_login_at; // Son giriş zamanı
$user->lastPlayedSong; // Son çalınan şarkı (relation)
Admin Panel Görüntüleme
Livewire Components:
ActivityLogComponent.php
Tüm sistem aktivitelerini görüntüler
Lokasyon: /Modules/UserManagement/App/Http/Livewire/ActivityLogComponent.php
Route: /admin/activity-logs
UserActivityLogComponent.php
Belirli bir kullanıcının aktivitelerini görüntüler
Lokasyon: /Modules/UserManagement/App/Http/Livewire/UserActivityLogComponent.php
Route: /admin/users/{id}/activity-logs
Filtreleme Özellikleri:
- search: Fulltext arama (description, baslik, modul)
- userFilter: Kullanıcıya göre filtreleme
- moduleFilter: Modüle göre (Song, Album, User...)
- eventFilter: Event tipine göre (created, updated, deleted)
- dateFrom, dateTo: Tarih aralığı
- • Root user'ın aktiviteleri sadece root user tarafından görülebilir
- • Aktivite silme yetkisi sadece root user'da
Favorileme Sistemi (favorites)
Tablo Yapısı (Polymorphic):
CREATE TABLE favorites (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNSIGNED NOT NULL,
favoritable_id BIGINT UNSIGNED NOT NULL,
favoritable_type VARCHAR(255) NOT NULL COMMENT 'Song, Album, Playlist...',
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
UNIQUE KEY unique_favorite (user_id, favoritable_id, favoritable_type),
INDEX favoritable (favoritable_type, favoritable_id)
) ENGINE=InnoDB;
Observer (FavoriteObserver):
// Lokasyon: /Modules/Favorite/App/Observers/FavoriteObserver.php
created() → Cache temizle + log_activity('favorilere eklendi')
updated() → Cache temizle + log_activity('favori güncellendi', changed_fields)
deleted() → Cache temizle + log_activity('favorilerden çıkarıldı')
Helper Metodlar:
// Kontrol Et
Favorite::check($userId, 'Song', $songId); // Boolean döner
// İlişkiler
$user->favorites()->where('favoritable_type', 'Song')->get();
$song->favorites()->count(); // Kaç kişi favoriledi?
- • Model:
/Modules/Favorite/App/Models/Favorite.php - • Observer:
/Modules/Favorite/App/Observers/FavoriteObserver.php
Aktivite Kapsam Tablosu
| Aktivite | Tablo | Durum | Kapsam |
|---|---|---|---|
| Login/Logout | activity_log, user_active_sessions |
✅ Tam | Zaman, IP, cihaz, başarısız denemeler |
| Profil Güncelleme | activity_log |
✅ Tam | Hangi alanlar değişti, eski/yeni değer |
| Şarkı Dinleme | muzibu_song_plays |
✅ Çok Detaylı | Duration, skip, source, cihaz, browser |
| Favorileme/Çıkarma | activity_log, favorites |
✅ Tam | Hangi içerik, ne zaman |
| Playlist CRUD | activity_log |
✅ Tam | Oluşturma, düzenleme, silme, şarkı ekle/çıkar |
| Yorum/Değerlendirme | activity_log, reviews |
✅ Tam | Hangi içeriğe yorum, ne zaman |
| Cihaz Bilgisi | user_active_sessions, song_plays |
✅ Tam | Device type, browser, platform, user agent |
| Abuse Detection | song_plays |
✅ Tam | Skip rate, short listens, IP tracking |
| İndirme | activity_log |
⚠️ Kontrol Gerekli | Özel tablo yok, activity_log'dan izlenebilir |
| Analitik Dashboard | - |
❌ Yok | Veriler var ama görsel dashboard geliştirilebilir |
Örnek Analitik Sorgular
1. Bir kullanıcının son 30 günlük aktiviteleri:
$activities = \Spatie\Activitylog\Models\Activity::query()
->where('causer_id', $userId)
->where('created_at', '>=', now()->subDays(30))
->orderBy('created_at', 'desc')
->get();
2. En çok dinlenen şarkılar (bu hafta):
use Modules\Muzibu\App\Models\SongPlay;
$topSongs = SongPlay::getTopSongs(10, 'week');
// [song_id => play_count]
3. Cihaz dağılımı (bugün):
$distribution = SongPlay::today()->getDeviceDistribution();
// ['mobile' => 65%, 'desktop' => 30%, 'tablet' => 5%]
4. Kullanıcının atlama oranı:
$skipRate = SongPlay::where('user_id', $userId)
->whereNotNull('ended_at')
->selectRaw('AVG(was_skipped) * 100 as skip_rate')
->value('skip_rate');
// 25.5 (% olarak)
5. Şüpheli aktiviteler (kısa dinlemeler):
$suspicious = SongPlay::shortListens(10) // 10 saniyeden az
->where('created_at', '>=', now()->subHour())
->groupBy('user_id')
->selectRaw('user_id, COUNT(*) as count')
->having('count', '>', 20) // Saatte 20+ kısa dinleme
->get();
6. Aktif oturum sayısı:
$activeSessions = DB::table('user_active_sessions')
->where('user_id', $userId)
->where('last_activity', '>=', now()->subMinutes(30))
->count();
Geliştirme Önerileri
1. İndirme Takibi
Özel bir downloads tablosu oluşturulabilir:
- • user_id, song_id, downloaded_at
- • file_format (mp3, flac, wav...)
- • quality (320kbps, lossless...)
- • ip_address, user_agent
2. Analitik Dashboard
Admin paneline görsel istatistik paneli:
- • Günlük/Haftalık aktif kullanıcı grafiği
- • Saatlik dinleme dağılımı
- • Cihaz dağılımı (pie chart)
- • Top 10 şarkılar/albümler
- • Kullanıcı büyüme trendi
3. Real-time Monitoring
Anlık aktivite izleme:
- • Şu anda dinlenen şarkılar (live)
- • Aktif kullanıcı sayısı (canlı)
- • Son login'ler feed'i
4. Otomatik Veri Temizleme
Eski kayıtları otomatik sil:
- • activity_log: 1 yıldan eski kayıtlar (zaten config'de var: 365 gün)
- • song_plays: 2 yıldan eski kayıtlar (istatistik özetleri tutularak)
- • user_active_sessions: 30 günden eski oturumlar
5. Performans Optimizasyonu
Büyük veri setleri için:
- • activity_log partition'lama (aylık)
- • song_plays için aggregate tables (günlük/aylık özetler)
- • Index optimizasyonu (yavaş sorgular için)
🎯 Sonuç ve Değerlendirme
Sisteminizde çok kapsamlı ve profesyonel bir aktivite takip sistemi mevcut. Üyelerinizin site üzerindeki neredeyse tüm işlemleri kayıt altına alınıyor ve analiz edilebilir durumda.
✅ Güçlü Yönler:
- • Observer pattern ile otomatik log'lama
- • Çok detaylı dinleme analitikleri
- • Multi-tenant uyumlu
- • Abuse detection yetenekleri
- • Fulltext search desteği
⚡ Geliştirme Alanları:
- • İndirme takibi özel tablo ile geliştirilebilir
- • Görsel analitik dashboard eklenebilir
- • Real-time monitoring sistemi
- • Aggregate tables (performans için)
Önemli Not: Tüm bu veriler zaten toplanıyor ve admin panelinden görüntülenebilir durumda. Sadece görselleştirme ve raporlama tarafı daha da geliştirilebilir.