Basit Anlatım (Herkes İçin)
Suistimal Raporları modülü, müzik platformunda bir abonenin hesabını birden fazla kişiyle paylaşıp paylaşmadığını tespit eden bir sistemdir.
Asıl sorun: Sistem arka tarafta (backend) 3 tür şüpheli davranış tespit ederken, kullanıcı arayüzü (frontend) 7 farklı tür gösteriyor. Bu ikisi hiç eşleşmiyor. Yani ekrandaki istatistik kartları her zaman sıfır gösterecektir.
Neden önemli: Admin panelinden tarama yapıldığında sonuçlar yanlış gösteriliyor. Skorlar saniye formatında görünüyor ama aslında puan sistemi. Günlük istatistikler eksik veri gösteriyor. Kısacası modül çalışıyor gibi görünse de sunduğu bilgilerin çoğu yanlış veya eksik.
Tüm Bulgular Özet Tablosu
| # | Bulgu | Önem | Tür | Konum |
|---|---|---|---|---|
| B1 | Pattern Uyumsuzluğu (Backend 3 vs Frontend 7) | KRİTİK | Bug | Service + Views |
| B2 | formatScore() skoru saniye olarak gösteriyor (aslında puan) | KRİTİK | Bug | index.blade.php:576 |
| B3 | getPatternCount() her zaman 3 döndürüyor | KRİTİK | Bug | index.blade.php:592 |
| B4 | timelineData['overlaps'] key'i mevcut değil | KRİTİK | Bug | show.blade.php:442 |
| B5 | daily_stats 'overlaps' key'i mevcut değil | KRİTİK | Bug | show.blade.php:335 |
| B6 | scan_date format hatası (H:i her zaman 00:00) | ORTA | Bug | show.blade.php:300 |
| D1 | 'suspicious' durumu asla atanmıyor | YÜKSEK | Tasarım | Service:122 |
| D2 | quickCheck() tanımlı ama hiç çağrılmıyor | YÜKSEK | Tasarım | Controller + Job |
| D3 | Ping-pong günlük istatistiği tarihe göre filtrelenmiyor | ORTA | Bug | Service:576 |
| D4 | Model'deki abuseScoreFormatted accessor da saniye formatı kullanıyor | ORTA | Tasarım | AbuseReport.php:195 |
| P1 | O(n²) performans (concurrent + split stream) | ORTA | Performans | Service:277,345 |
| E1 | Otomatik tarama (cron/schedule) yok | EKSIK | Eksik | - |
| E2 | Export/İndirme özelliği yok (CSV/PDF) | EKSIK | Eksik | - |
| E3 | Rapor silme/arşivleme özelliği yok | EKSIK | Eksik | - |
| E4 | Tarama ilerleme durumu takibi yok (progress) | EKSIK | Eksik | - |
| E5 | show sayfası dark tema admin layout ile çakışıyor | EKSIK | UX | show.blade.php |
Kritik Buglar
Pattern Uyumsuzluğu: Backend 3 Pattern, Frontend 7 Pattern
Backend (AbuseDetectionService)
ping_pong - A→B→A döngüsü
concurrent_different - Farklı cihaz aynı anda
split_stream - Aynı cihaz çakışma
Frontend (index + show blade)
rapid_skips - Var ama backend'de yok!
high_volume - Var ama backend'de yok!
repeat_songs - Var ama backend'de yok!
multi_device - Var ama backend'de yok!
suspicious_ip - Var ama backend'de yok!
no_sleep - Var ama backend'de yok!
bot_like - Var ama backend'de yok!
Sonuç:
- index.blade.php'deki "Tespit Edilen Şüpheli Davranışlar" kartı her zaman gizli kalır (7 pattern'in hiçbiri veritabanına yazılmaz)
- apiStats() controller'ında 7 pattern sayılmaya çalışılır ama hepsi her zaman 0 döner
- show.blade.php'deki pattern kartları backend'den gelen 3 pattern'i
patternMetasözlüğünde bulamaz, fallback'e düşer
Etkilenen Dosyalar
formatScore() Skoru Saniye Olarak Gösteriyor (Aslında Puan)
Mevcut Kod (index.blade.php:576)
formatScore(seconds) {
if (!seconds) return '0s';
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return m > 0 ? `${m}m ${s}s` : `${s}s`;
}
Olması Gereken
formatScore(score) {
if (!score) return '0';
return score.toLocaleString('tr-TR');
// 300 → "300"
// 1300 → "1.300"
}
Sorun: abuse_score puan bazlı (Ping-Pong: cycle×100, Concurrent: ×50, Split: ×30, max 1300).
Ama formatScore() bunu saniye olarak gösteriyor. Skor 300 olan bir rapor ekranda "5m 0s" olarak görünüyor.
Aynı hata Model'deki getAbuseScoreFormattedAttribute() accessor'ında da var.
getPatternCount() Her Zaman 3 Döndürüyor
Mevcut Kod (index.blade.php:592)
getPatternCount(report) {
if (!report.patterns_json) return 0;
return Object.keys(report.patterns_json).length; // HER ZAMAN 3!
}
patterns_json her zaman 3 key içerir: ping_pong, concurrent_different, split_stream.
Her birinin detected: true/false alanı var ama fonksiyon bunu kontrol etmiyor.
Doğru Implementasyon:
getPatternCount(report) {
if (!report.patterns_json) return 0;
return Object.values(report.patterns_json)
.filter(p => p.detected === true).length;
}
show.blade.php: timelineData['overlaps'] Key'i Mevcut Değil
View'da Kullanılan (show.blade.php)
$allOverlaps = $timelineData['overlaps'] ?? []; $overlapIds = collect($allOverlaps)->flatMap(...);
Satır: 442-443, 661, 744
Service'in Döndürdüğü (getUserTimelineData)
return [
'items' => $items, // ✓
'patterns' => $patterns, // ✓
'stats' => [...] // ✓
// 'overlaps' YOK!
];
Sonuç: Detay sayfasındaki çakışma bölümü her zaman boş. Vis.js timeline'da çakışmalar vurgulanmıyor. "X ÇAKIŞMA TESPİT EDİLDİ" uyarısı asla görünmüyor. Gantt bar'lar overlap class'ı almıyor.
daily_stats'ta 'overlaps' Key'i Yok
show.blade.php Bekliyor
$stat['overlaps'] // Kullanılan key
Satır 335, 430, 901 gibi yerlerde kullanılıyor
calculateDailyStats() Üretiyor
$dailyStats[$date] = [
'plays' => ...,
'desktop' => ...,
'mobile' => ...,
'ping_pong' => ...,
'concurrent' => ...,
'split_stream' => ...,
// 'overlaps' KEY'İ YOK!
];
Çözüm: Ya calculateDailyStats()'a 'overlaps' => $concurrentCount + $splitCount ekle, ya da view'ları concurrent + split_stream key'lerini kullanacak şekilde güncelle.
scan_date Format Hatası
show.blade.php:300'de $report->scan_date->format('d.m.Y H:i') kullanılıyor.
Ama scan_date model'de 'date' olarak cast ediliyor (datetime değil).
Bu yüzden saat kısmı her zaman "00:00" gösterecektir.
Düzeltme: $report->scan_date->format('d.m.Y') kullanılmalı.
Tasarım & Mantık Hataları
'suspicious' (Şüpheli) Durumu Asla Atanmıyor
scanUser() - Satır 120-122
$hasAbuse = $this->hasAnyPatternDetected($patterns);
$status = $hasAbuse ? AbuseReport::STATUS_ABUSE : AbuseReport::STATUS_CLEAN;
// ↑ SADECE "abuse" veya "clean"! "suspicious" HİÇ YOK!
Model'de determineStatus() metodu var ve threshold bazlı çalışıyor (300=şüpheli, 600=suistimal) ama hiç çağrılmıyor.
Frontend filtre dropdown'unda "Şüpheli" seçeneği var ama hiçbir kayıt bu durumda olmayacak.
Önerilen: hasAbuse yerine score bazlı determineStatus($abuseScore) kullanılmalı.
quickCheck() Tanımlı Ama Hiç Çağrılmıyor
quickCheck() tek fingerprint'li kullanıcıları erken filtrelemek için tasarlanmış. Job'un docblock'unda "Early Exit'i geçmiştir" yazıyor ama ne controller ne de Job bu fonksiyonu çağırıyor.
Akış Şu An:
Olması Gereken:
Performans etkisi: Tek cihazdan dinleyen kullanıcılar (çoğunluk) gereksiz yere Horizon'da job oluşturuyor.
Ping-Pong Günlük İstatistiği Tarihe Göre Filtrelenmiyor
$pingPongCount = collect($patterns['ping_pong']['cycles'] ?? [])
->filter(fn($c) => true) // ← BU FİLTRE HİÇBİR ŞEY YAPMIYOR!
->count();
filter(fn($c) => true) tüm elemanları geçirir. Her gün için aynı toplam ping-pong sayısı yazılır.
concurrent ve split_stream doğru şekilde tarihe göre filtreleniyor ama ping_pong değil.
Performans Sorunu
O(n²) Algoritma: Concurrent & Split Stream Tespiti
Hem detectConcurrentDifferentSource() hem de detectSplitStream() iç içe for döngüsü kullanıyor (O(n²)).
| Play Sayısı | Karşılaştırma (Her pattern) | Toplam (2 pattern) |
|---|---|---|
| 100 | 4,950 | ~10K |
| 500 | 124,750 | ~250K |
| 1,000 | 499,500 | ~1M |
| 5,000 | 12,497,500 | ~25M |
Öneri: Zaman bazlı sıralama + sliding window yaklaşımı O(n²)'yi O(n log n)'e düşürür.
Eksik Özellikler
Otomatik Tarama Yok
Tarama tamamen manuel (buton tıklaması). Günlük/haftalık cron schedule ile otomatik tarama yapılabilir.
Export/İndirme Yok
CSV veya PDF olarak rapor indirme özelliği bulunmuyor. Raporları paylaşmak veya arşivlemek zor.
Silme/Arşivleme Yok
Eski raporları temizleme veya arşivleme mekanizması yok. SoftDelete var ama kullanılmıyor.
Tarama İlerleme Takibi Yok
"Tarama Başlat" tıklandığında job'lar dispatch edilir ama progress gösterilmez. Kaç kullanıcı tarandı, kaçı kaldı bilinmez.
Dark Tema & Admin Layout Çakışması
show.blade.php özel dark tema kullanıyor ama admin layout muhtemelen Tabler.io light tema. CSS override'ları form kontrollerini bozabilir.