Sistem Özeti
Basit Anlatım (Herkes İçin)
Ne yapıyoruz? Kurumsal müşterilerin (restoranlar, kafeler, mağazalar, ofisler) müzik dinlerken araya kendi duyurularını ekleyebilmesini sağlıyoruz.
Nasıl çalışacak? Örneğin bir restoran müzik çalarken, her 10 şarkıda bir "Değerli müşterilerimiz, happy hour başlamıştır" gibi bir anons otomatik çalacak.
Kim kontrol edecek?
- Muzibu Admin: Anons dosyalarını yükler, sıralar
- Ana Şube: Kaç şarkıda bir çalacağını ayarlar
- Her Şube: Kendi için durdurabilir/devam ettirebilir
Teknik Özet (Geliştiriciler İçin)
Sistemdeki Aktörler
Muzibu Admin
Anons dosyalarını yükler, yönetir, sıralar
Ana Şube
Anons ayarlarını yapar, tüm şubeleri görür
Alt Şube
Sadece kendi için durdur/devam yapabilir
Dinleyici
Müzik dinler, anonsları duyar
Admin Panel (Muzibu Yönetimi)
Menü Konumu
Route: /admin/muzibu/announcements
Anons Listesi Sayfası
Anons Yönetimi
Kurumsal hesaplarda çalacak anonsları yönetin
5
Toplam Anons
3
Aktif
2
Pasif
1,245
Toplam Çalınma
| Sıra | Anons | Süre | Çalınma | Durum | İşlemler | |
|---|---|---|---|---|---|---|
| 1 |
Yılbaşı Kampanyası Yüklenme: 30 Ara 2025 |
0:45 | 523 | Aktif | ||
| 2 |
Happy Hour Duyurusu Yüklenme: 28 Ara 2025 |
0:30 | 412 | Aktif | ||
| 3 |
Eski Kampanya Yüklenme: 15 Ara 2025 |
0:35 | 310 | Pasif |
Sıralama (Drag & Drop)
- • Sol taraftaki tutma ikonundan sürükle-bırak
- • Sıra numarası otomatik güncellenir
- • Anonslar bu sırayla çalar (rotation)
- • Livewire + SortableJS kullanılacak
Durum Yönetimi
- • Aktif: Rotation'a dahil, çalabilir
- • Pasif: Rotation dışı, çalmaz
- • Pasif anonslar listede soluk görünür
- • Tek tıkla durum değiştirilebilir
Anons Yükleme / Düzenleme Formu
Admin panelde görünecek isim
Dosya sürükle veya tıkla
MP3, WAV • Max 10MB • Max 2 dakika
Yılbaşı Kampanyası
anons-yilbasi.mp3
Süre
0:45
Boyut
1.2 MB
Format
MP3
Dosya Kuralları
Format
MP3, WAV, M4A kabul edilir
Boyut
Maksimum 10 MB
Süre
Maksimum 2 dakika (120 saniye)
Admin İstatistikleri
Anons Bazlı İstatistik
Genel Metrikler
Bugün
127
Bu Hafta
843
Atlama Oranı
12%
Ort. Dinleme
38sn
Kurumsal Panel (Ana Şube)
Erişim Noktası
Route: /corporate/announcement-settings
Sadece ana şube (parent_id = null) bu sayfayı görebilir
Anons Ayarları Sayfası
Anons Sistemi Ayarları
Tüm şubeleriniz için anons ayarlarını buradan yönetin
Anons Sistemi
Tüm şubelerde anons çalmasını aç/kapat
Anons Aralığı
Kaç şarkıdan sonra anons çalsın?
Şarkılar en az 30 saniye dinlendiğinde sayılır
10
Şarkıda Bir Anons
3
Aktif Anons
1,245
Toplam Çalınma
Şube Durumları (Ana Şube Görünümü)
| Şube | Anons Durumu | Şarkı Sayacı | Son Anons |
|---|---|---|---|
|
Ana Şube (Merkez)
|
Aktif | 7 / 10 | 5 dk önce |
|
Ankara Şubesi
|
Aktif | 3 / 10 | 12 dk önce |
|
İzmir Şubesi
|
Durduruldu | - | 2 saat önce |
Şubeler kendi panellerinden anonsu durdurabilir. Ana şube sadece görüntüleyebilir, müdahale edemez.
Şube Paneli (Durdur/Devam)
Anons Kontrol Butonu Konumu
Seçenek 1: Sol Sidebar (Önerilen)
3 şarkı sonra
Her zaman görünür, kolay erişim
Seçenek 2: Player İçinde
Şarkı Adı
Sanatçı
Player ile entegre, kompakt
Durdur / Devam Arayüzü
Anons Aktif
Anons Sistemi
Şu an aktif
7 / 10 şarkı
Anons Durdurulmuş
Anons Sistemi
Durduruldu
Anonslar çalmıyor
Not: Durdurma sadece bu şubeyi etkiler. Diğer şubeler ve ana şube etkilenmez. Ana şube ayarları (kaç şarkıda bir) değişmez, sadece bu şubede anons çalmaz.
Player Entegrasyonu
Çalma Akışı
Normal Akış (Anons Yok)
Anonslu Akış (Kurumsal)
Anons Çalarken Player Görünümü
Normal Şarkı Çalarken
Hayal Kahvesi
Sezen Aksu
Anons Çalarken
Yılbaşı Kampanyası
Şirket Duyurusu
Anons Sırasında Davranışlar
İzin Verilenler
- • Ses açma/kapama (volume)
- • Mute/unmute
- • Tam ekran görünümü
Engellenenler
- • İleri/geri atlama (skip) - Opsiyonel
- • Progress bar ile atlama (seek)
- • Şarkı değiştirme
Karar: Anons Atlanabilir mi?
JavaScript Akış Mantığı
// 1. Sayfa yüklendiğinde kurumsal kontrolü
async initAnnouncementSystem() {
const corporate = await this.getCorporateAccount();
if (!corporate) return; // Kurumsal değilse çık
this.announcement = {
enabled: corporate.announcement_enabled,
paused: await this.getBranchPauseStatus(),
counter: await this.getBranchCounter(),
triggerAt: corporate.songs_between_announcements, // default: 10
currentIndex: 0
};
}
// 2. Şarkı 30 saniye dinlendiğinde (trackHit)
onTrackHit() {
// Normal tracking...
// Anons sayacı
if (this.announcement.enabled && !this.announcement.paused) {
this.announcement.counter++;
this.syncCounterToServer(); // Backend'e kaydet
}
}
// 3. Şarkı bittiğinde
onSongEnded() {
if (this.shouldPlayAnnouncement()) {
this.playAnnouncement();
} else {
this.playNextSong();
}
}
// 4. Anons gerekli mi?
shouldPlayAnnouncement() {
return this.announcement.enabled
&& !this.announcement.paused
&& this.announcement.counter >= this.announcement.triggerAt;
}
// 5. Anons çal
async playAnnouncement() {
// Sıradaki anonsu al (rotation)
const next = await fetch('/api/announcement/next');
// Player state'i değiştir
this.isPlayingAnnouncement = true;
this.currentTrack = {
type: 'announcement',
...next.data
};
// Audio src değiştir ve çal
this.audio.src = next.data.audio_url;
this.audio.play();
// Anons bitince
this.audio.onended = () => {
this.trackAnnouncementPlay(next.data.id);
this.announcement.counter = 0; // Sayaç sıfırla
this.isPlayingAnnouncement = false;
this.playNextSong(); // Normal akışa dön
};
}
Dosya Yönetimi
Storage Yapısı
storage/
└── tenant1001/ # Muzibu tenant
└── app/
└── public/
└── announcements/ # Anons dosyaları
├── 1/
│ └── yilbasi-kampanyasi.mp3
├── 2/
│ └── happy-hour.mp3
└── 3/
└── genel-duyuru.mp3
Dosya Adlandırma
- • Orijinal isim slug'lanır
- • Türkçe karakterler dönüştürülür
- • Örn: "Yılbaşı Kampanyası.mp3" → "yilbasi-kampanyasi.mp3"
Erişim URL
/storage/announcements/1/yilbasi-kampanyasi.mp3
Dosya Validasyonu
| Kural | Değer | Açıklama |
|---|---|---|
| Format | mp3, wav, m4a, ogg |
MIME type kontrolü yapılır |
| Max Boyut | 10 MB |
Büyük dosyalar reddedilir |
| Max Süre | 120 saniye |
FFprobe ile kontrol |
| Min Süre | 5 saniye |
Çok kısa dosyalar reddedilir |
Veritabanı Tasarımı
Tablo İlişkileri
announcements
- id
- title
- audio_path
- duration
- position
- is_active
corporate_announcement_settings
- id
- corporate_account_id (FK)
- songs_between
- is_enabled
- current_index
branch_announcement_status
- id
- corporate_account_id (FK)
- user_id (FK)
- is_paused
- song_counter
announcement_plays
- id
- announcement_id (FK)
- corporate_account_id (FK)
- user_id (FK)
- listened_duration
- was_skipped
muzibu_announcements
| Kolon | Tip |
|---|---|
| id | BIGINT PK |
| title | VARCHAR(255) |
| audio_path | VARCHAR(500) |
| duration | INT (saniye) |
| file_size | INT (bytes) |
| position | INT |
| is_active | BOOLEAN |
| play_count | INT default 0 |
| created_at | TIMESTAMP |
| updated_at | TIMESTAMP |
muzibu_corporate_announcement_settings
| Kolon | Tip |
|---|---|
| id | BIGINT PK |
| corporate_account_id | BIGINT FK UNIQUE |
| songs_between_announcements | INT default 10 |
| min_listen_duration | INT default 30 |
| is_enabled | BOOLEAN default true |
| current_announcement_index | INT default 0 |
| created_at | TIMESTAMP |
| updated_at | TIMESTAMP |
muzibu_branch_announcement_status
| Kolon | Tip |
|---|---|
| id | BIGINT PK |
| corporate_account_id | BIGINT FK |
| user_id | BIGINT FK |
| is_paused | BOOLEAN default false |
| song_counter | INT default 0 |
| last_announcement_at | TIMESTAMP NULL |
| created_at | TIMESTAMP |
| updated_at | TIMESTAMP |
UNIQUE: (corporate_account_id, user_id)
muzibu_announcement_plays
| Kolon | Tip |
|---|---|
| id | BIGINT PK |
| announcement_id | BIGINT FK |
| corporate_account_id | BIGINT FK |
| user_id | BIGINT FK NULL |
| listened_duration | INT |
| was_skipped | BOOLEAN |
| device_type | VARCHAR(50) |
| played_at | TIMESTAMP |
INDEX: (announcement_id, played_at)
API Endpoints
Admin API
/api/admin/announcements
Tüm anonsları listele (pagination)
/api/admin/announcements
Yeni anons yükle (multipart/form-data)
/api/admin/announcements/{id}
Anons güncelle (başlık, durum)
/api/admin/announcements/{id}
Anons sil (soft delete)
/api/admin/announcements/reorder
Sıralama güncelle: {"ids": [3,1,2]}
Corporate API (Ana Şube)
/api/corporate/announcement-settings
Mevcut ayarları getir
Response: {
"is_enabled": true,
"songs_between": 10,
"total_announcements": 3,
"total_plays": 1245
}
/api/corporate/announcement-settings
Ayarları güncelle
Body: {
"is_enabled": true,
"songs_between": 10
}
/api/corporate/branch-announcement-statuses
Tüm şubelerin anons durumlarını getir
Player API (Frontend)
/api/announcement/init
Anons sistemi başlangıç bilgileri
Response: {
"enabled": true,
"paused": false,
"counter": 7,
"trigger_at": 10,
"announcements_count": 3
}
/api/announcement/next
Sıradaki anonsu getir (rotation)
Response: {
"id": 2,
"title": "Happy Hour",
"audio_url": "/storage/announcements/2/happy-hour.mp3",
"duration": 30
}
/api/announcement/increment
Şarkı sayacını artır (30sn sonra)
/api/announcement/track-play
Anons çalındı bildir
Body: {
"announcement_id": 2,
"listened_duration": 30,
"was_skipped": false
}
/api/announcement/pause
Bu şube için anonsu durdur
/api/announcement/resume
Bu şube için anonsu devam ettir
Kullanım Senaryoları
Yeni Anons Ekleme (Admin)
- 1 Admin panele giriş yap → Muzibu → Anonslar
- 2 "Yeni Anons Yükle" butonuna tıkla
- 3 Başlık gir: "Yılbaşı Kampanyası"
- 4 MP3 dosyasını sürükle-bırak ile yükle
- 5 Sistem otomatik: süre kontrolü, format kontrolü yapar
- 6 Önizleme ile dinle, "Kaydet" tıkla
- ✓ Anons listede görünür, rotation'a dahil olur
Kurumsal Ayarları Değiştirme (Ana Şube)
- 1 Kurumsal hesapla giriş yap (ana şube)
- 2 Kurumsal Dashboard → "Anons Ayarları"
- 3 Slider ile "15 şarkıda bir" olarak değiştir
- 4 "Ayarları Kaydet" tıkla
- ✓ Tüm şubelerde artık 15 şarkıda bir anons çalar
Şube Anons Durdurma
- 1 Şube hesabıyla giriş yap
- 2 Sol sidebar'da "Anonslar" panelini gör
- 3 "Durdur" butonuna tıkla
- ! Sadece bu şubede anonslar durur
- 5 Diğer şubeler etkilenmez, normal çalmaya devam
Normal Dinleme Akışı (Kullanıcı)
- ♪ Şarkı 1 çalar → 30sn+ dinlenir → Sayaç: 1
- ♪ Şarkı 2 çalar → 30sn+ dinlenir → Sayaç: 2
- ... ... (şarkılar devam eder)
- ♪ Şarkı 10 çalar → 30sn+ dinlenir → Sayaç: 10
- 📢 Şarkı 10 biter → ANONS ÇALAR (45sn)
- ↺ Anons biter → Sayaç sıfırlanır → Şarkı 11 başlar
- ♪ Döngü devam eder...
Edge Cases (Özel Durumlar)
Şarkı 30sn'den az dinlenirse?
Sayaç artmaz. Skip edilen şarkılar sayılmaz.
Aktif anons yoksa?
Anons sistemi devre dışı kalır, normal çalma devam eder.
Sayfa yenilenirse?
Sayaç backend'den çekilir, kaldığı yerden devam.
Kullanıcı çıkış yaparsa?
Sayaç DB'de kalır, tekrar girişte devam.
Aynı anda birden fazla cihaz?
Her cihaz (session) ayrı sayaç tutar.
Kurumsal değilse?
Anons sistemi hiç aktif olmaz, JS yüklenmez.
Geliştirme Adımları
1. Veritabanı
- • 4 migration oluştur
- • 4 model oluştur
- • İlişkileri tanımla
2. Admin Panel
- • Livewire component
- • Liste + Form view
- • Drag-drop sıralama
- • Dosya yükleme
3. Kurumsal Panel
- • Ayarlar sayfası
- • Şube durumları
- • API endpoints
4. Şube Kontrolü
- • Sidebar widget
- • Durdur/devam UI
- • API endpoints
5. Player
- • Alpine store güncelle
- • Sayaç mantığı
- • Anons çalma UI
- • API entegrasyonu
6. Test & Deploy
- • Migration çalıştır
- • Manuel test
- • Cache temizle
- • npm run prod