Kritik Karar: Ping-Pong Pattern'i
Basit Anlatım
Sorun: İlk planda Ping-Pong "normal davranış" sayılıp kaldırılacaktı.
Ama iki kişi aynı hesabı paylaşıp aynı anda dinlediğinde, dinleme kayıtları zamana göre sıralandığında
IP adresleri doğal olarak 1→2→1→2→1→2 şeklinde değişiyor.
Neden önemli: Bu alternating (değişen) IP pattern'i, Ping-Pong tespitinin tam olarak aradığı şey. Eğer kaldırırsak, sırayla dinleyenleri (biri kapatıp diğeri açıyor) yakalayamayız.
Karar: Ping-Pong KALACAK. 3 pattern ile devam edilecek.
Teknik Detay
Ping-Pong
KALIYORIP/browser/platform'da A→B→A döngüsü
Sırayla dinleyenleri yakalar (çakışma olmasa bile)
Her field için: ip_address, browser, platform, device_key
Concurrent Different
KALIYORAynı anda farklı fingerprint
Eş zamanlı dinleyenleri yakalar (zaman çakışması)
Farklı IP+browser+platform, aynı zaman dilimi
Split Stream
KALIYORAynı fingerprint + overlap
1 PC'den 2 hoparlöre yönlendirmeyi yakalar
Aynı IP+browser+platform, farklı şarkılar çakışıyor
Temel Kural
YASAK (Suistimal)
- Aynı anda 2 farklı cihaz/IP'den dinleme (Concurrent)
- Aynı cihazdan 2 ayrı stream açma (Split Stream)
- IP/cihaz sürekli A→B→A değişimi (Ping-Pong)
NORMAL (B2B)
- 15 saat, 7/24 dinleme (işletme)
- Yüksek hacim (restoran)
- Skip yok (arka plan müzik)
- Gece dinleme (24 saat açık mekan)
Bug Listesi (6 Adet)
Basit: İstatistik sayfasındaki "tespit edilen davranışlar" kartları tamamen yanlış isimlere bakıyor. rapid_skips, high_volume gibi eski key'ler arıyor ama veritabanında ping_pong, concurrent_different, split_stream var.
Teknik Detay
Dosya: AbuseReportController.php:166-193
// YANLIŞ (eski key'ler)
$patternCounts = [
'rapid_skips' => 0, 'high_volume' => 0,
'repeat_songs' => 0, 'multi_device' => 0,
'suspicious_ip' => 0, 'no_sleep' => 0, 'bot_like' => 0,
];
// DOĞRU (gerçek pattern key'leri)
$patternCounts = [
'ping_pong' => 0,
'concurrent_different' => 0,
'split_stream' => 0,
];
Ayrıca isset($patterns[$key]) → $patterns[$key]['detected'] ?? false olmalı
Basit: Skor aslında "puan" ama arayüz bunu dakika:saniye olarak gösteriyor. Örneğin skor 500 olunca "8m 20s" yazıyor, ama aslında "500 puan" olmalı.
Teknik Detay
Dosyalar:
- index.blade.php:576-581 →
formatScore()JS fonksiyonu - AbuseReport.php:193-198 →
getAbuseScoreFormattedAttribute() - show.blade.php → abuse_score gösterimi
// YANLIŞ
formatScore(seconds) {
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return m > 0 ? `${m}m ${s}s` : `${s}s`;
}
// DOĞRU
formatScore(score) {
return score + ' puan';
}
Basit: Pattern sayısı her zaman 3 görünüyor, çünkü "tespit edilenler" değil "tüm key'ler" sayılıyor. Temiz bir kullanıcıda bile "3 pattern" yazıyor.
Teknik Detay
Dosya: index.blade.php:592-595
// YANLIŞ
getPatternCount(report) {
return Object.keys(report.patterns_json).length; // Her zaman 3!
}
// DOĞRU
getPatternCount(report) {
if (!report.patterns_json) return 0;
return Object.values(report.patterns_json)
.filter(p => p.detected).length;
}
Basit: Detay sayfasındaki overlap kartları device, platform, overlap_start, overlap_end, same_browser, same_ip gibi alanlar bekliyor ama service bunları üretmiyor. Kartlar boş görünüyor.
Teknik Detay
Dosya: AbuseDetectionService.php
detectConcurrentDifferentSource() ve detectSplitStream() sample yapıları show.blade'in beklediği alanları içermiyor.
Çözüm: Sample yapısına şu alanlar eklenecek:
'device', 'platform', 'start', 'end', 'overlap_start', 'overlap_end', 'same_browser', 'same_ip'
Ayrıca getUserTimelineData() return'e 'overlaps' key eklenecek.
Basit: Günlük istatistiklerde "toplam çakışma" sayısı yok. Detay sayfasında günlük çakışma grafiği boş kalıyor.
Teknik Detay
Dosya: AbuseDetectionService.php:565-598
// Eklenecek 'overlaps' => $concurrentCount + $splitCount
Basit: show.blade'de tarama tarihi "28.02.2026 00:00" şeklinde saat ile gösteriliyor. Sadece tarih gösterilmeli: "28.02.2026"
Teknik Detay
Dosya: show.blade.php
format('d.m.Y H:i') → format('d.m.Y')
Tasarım Hataları (4 Adet)
Basit: Şu anda herhangi bir pattern varsa direkt "abuse" yazıyor. Oysa skora göre kademeli olmalı (temiz / şüpheli / suistimal).
Teknik Detay
// YANLIŞ $hasAbuse = $this->hasAnyPatternDetected($patterns); $status = $hasAbuse ? 'abuse' : 'clean';
// DOĞRU $abuseScore = $this->calculatePatternScore($patterns); $status = AbuseReport::determineStatus($abuseScore);
Basit: Tek fingerprint'li kullanıcılar (suistimal OLAMAZ) gereksiz yere Horizon'a gönderiliyor. Job'un başında quickCheck yapılıp CLEAN kaydedilmeli.
Teknik Detay
Dosya: ScanUserForAbuseJob.php:91-138
handle() başında quickCheck çağrılacak, tek fingerprint ise direkt CLEAN rapor oluşturulacak.
Basit: Threshold sabitleri "saniye cinsinden" yorumlu ama aslında "puan cinsinden". Yorum güncellenmeli.
Basit: Model'deki skor formatlama saniye olarak yapıyor, puan olarak değiştirilecek.
Yeni Özellik: Tarama Batch Ayrımı
Basit Anlatım
Sorun: Şu anda her tarama aynı gün yapılan önceki taramayı eziyor. Sabah "Son 7 Gün" ile tarama yapıp akşam "Son 30 Gün" ile tarama yaparsanız, sabahki sonuçlar kaybolur.
Çözüm: Her taramaya benzersiz bir "batch ID" verilecek. Böylece aynı gün birden fazla tarama yapılabilir ve sonuçlar karışmaz.
Kullanım: Liste sayfasında bir dropdown ile batch'ler arasında geçiş yapılabilecek. Varsayılan olarak son batch gösterilir.
Teknik Detay
Migration
Tablo: muzibu_abuse_reports
- +
scan_batch_idstring(36) nullable — UUID - +
scan_batch_labelstring(100) nullable — "Son 7 Gün — 28.02.2026 01:15" - + Index:
scan_batch_id - + Unique:
(user_id, scan_batch_id)
updateOrCreate Mantığı
AbuseReport::updateOrCreate(
['user_id' => $userId, 'scan_batch_id' => $scanBatchId],
[/* rapor verileri */]
);
Eski: (user_id, scan_date) → aynı günde 1 rapor. Yeni: (user_id, scan_batch_id) → batch başına 1 rapor.
API Endpoint'leri
GET /api/batches— Son 20 batch listesi (label, tarih, rapor sayısı)GET /api/list?batch_id=xxx— Batch'e göre filtreli raporlarGET /api/stats?batch_id=xxx— Batch'e göre istatistikler
Performans Optimizasyonu
Basit: Concurrent ve Split Stream tespitinde her play'i diğer her play ile karşılaştırıyoruz (O(n²)). 1000 play'lik bir kullanıcıda bu 500.000 karşılaştırma demek. Sliding window ile azaltılacak.
Teknik Detay
Play'ler zaman sıralı. Bir şarkının max süresi ~10dk olsun. İç döngüde, başlangıç zamanları arası max süreyi geçerse break yaparak gereksiz karşılaştırmaları atlıyoruz.
// Sort by start time (zaten sıralı geliyor) // Inner loop: break when gap > maxDuration if ($p2['start']->diffInSeconds($p1['start']) > $maxDuration) break;
show.blade.php — Dark Tema Çakışması
Basit: Detay sayfasında dark tema zorla uygulanmış, admin panelin normal görünümü bozulmuş. Arka plan gradient ve form input'lar düzeltilecek.
Teknik Detay
.abuse-report-page background gradient kaldırılacak
Form input'lardaki zorla dark stil kaldırılacak
Container container-xl yapılacak
Kapsam Dışı (Bu Seferde Yapılmayacak)
Değişecek Dosyalar (8 Dosya)
| # | Dosya | Değişiklik | Risk |
|---|---|---|---|
| 1 | migration/tenant/...add_scan_batch.php | YENİ — 2 kolon + index + unique | Orta |
| 2 | AbuseReport.php | fillable, threshold, skor format, scope | Düşük |
| 3 | AbuseDetectionService.php | batch params, sample alanları, overlaps, sliding window | Yüksek |
| 4 | ScanUserForAbuseJob.php | batch params, quickCheck entegrasyonu | Orta |
| 5 | AbuseReportController.php | batch ID üretimi, apiStats fix, apiBatches | Orta |
| 6 | routes/admin.php | api/batches route | Düşük |
| 7 | index.blade.php | 3 pattern kartı, skor format, batch dropdown | Orta |
| 8 | show.blade.php | 3 pattern meta, skor format, dark tema fix | Orta |
Uygulama Sırası
-
1
Migration scan_batch_id + scan_batch_label kolonları (3 aşamalı onay)
-
2
AbuseReport.php fillable, threshold, skor format, batch scope
-
3
AbuseDetectionService.php EN BÜYÜK DEĞİŞİKLİK — batch params, sample alanları, sliding window, overlaps
-
4
ScanUserForAbuseJob.php batch params, quickCheck early exit
-
5
AbuseReportController.php batch ID üretimi, apiStats fix, apiBatches
-
6
routes/admin.php api/batches GET route
-
7
index.blade.php 3 pattern kartı, formatScore, getPatternCount, batch dropdown
-
8
show.blade.php 3 pattern meta, skor format, dark tema fix, batch bilgisi
-
9
İzinler + Cache chown/chmod + cache:clear + config:cache + route:cache