MİMARİ KARAR 6 Ocak 2026

Tag & Category Hiyerarşisi

Cafe → Hard Rock → Güne Başlangıç / Gece Müzikleri - Nasıl Organize Edelim?

Hiyerarşi Problemi

Senaryo:
Cafe Hard Rock
Güne Başlangıç Gece Müzikleri
Cafe (Sector)
İşletme tipi / Sektör
Hard Rock (?)
Müzik karakteristiği / Stil
Güne Başlangıç (?)
Kullanım zamanı / Senaryo

Ana Soru:

"Hard Rock" ve "Güne Başlangıç" nasıl organize edilecek? Hangi tablo/yapı kullanılacak?

3 Mimari Seçenek

SEÇENEK 1

Tag Hiyerarşisi

Parent-Child ilişkisi ile tag ağacı

muzibu_tags:
• id=1, name="Hard Rock", parent=NULL
• id=5, name="Güne Başlangıç", parent=1
• id=6, name="Gece Müzikleri", parent=1
✅ Avantajlar:
  • • Tek tablo, basit yapı
  • • Sınırsız derinlik
  • • Kolay yönetim
❌ Dezavantajlar:
  • • Karmaşık sorgular (recursive)
  • • "Hard Rock" hem stil hem parent
  • • Semantik karışıklık
Frontend: Kategoriler iç içe menü
SEÇENEK 3 ⭐⭐

Polymorphic Tags

Type field ile tag ayırımı

muzibu_tags:
• id=1, name="Hard Rock", type="style"
• id=5, name="Güne Başlangıç", type="scenario"
• id=6, name="Gece Müzikleri", type="scenario"
✅ Avantajlar:
  • • Tek tablo (basit)
  • • Esnek (istediğin kadar type)
  • • Kolay genişletilebilir
❌ Dezavantajlar:
  • • Sector bağlantısı eksik
  • • Type management gerekli
  • • Karışabilir (scenario vs time?)
Frontend: Step-by-step filtreleme

Frontend'de Nasıl Görünür?

Seçenek 1: Tag Hiyerarşisi
Cafe Sektörü
Hard Rock
→ Güne Başlangıç
→ Gece Müzikleri
Jazz
⚠️ İç içe menü, recursive component gerekli
Seçenek 2: Categories ÖNERİLEN
Cafe Sektörü
☀️ Güne Başlangıç
🌙 Gece Müzikleri
✅ Spotify Business gibi! Scroll yaparak kategoriler görünsün

Database Yapıları (Detaylı)

SEÇENEK 2 (ÖNERİLEN)

Database Yapısı

muzibu_tags
tag_id BIGINT PK
name JSON (tr, en)
slug JSON (tr, en)
type VARCHAR (style/mood/tempo)
color VARCHAR (hex code)
icon VARCHAR (FA class)
is_active BOOLEAN
Örnekler: Hard Rock, Jazz, Acoustic, Chill
muzibu_playlist_categories
category_id BIGINT PK
sector_id BIGINT FK (nullable)
name JSON (tr, en)
slug JSON (tr, en)
sort_order INT
is_active BOOLEAN
Örnekler: Güne Başlangıç, Gece Müzikleri, Öğle Arası
Polymorphic İlişki
muzibu_playlistables:
• playlist_id, playlistable_type, playlistable_id
Playlist bağlantıları:
→ type='sector', id=1 (Cafe)
→ type='tag', id=3 (Hard Rock)
→ type='category', id=1 (Güne Başlangıç)
Örnek Sorgu
// Cafe → Hard Rock → Güne Başlangıç
$playlists = Playlist::query()
  ->whereHas('sectors',
    fn($q) => $q->where('sector_id', 1))
  ->whereHas('tags',
    fn($q) => $q->where('tag_id', 3))
  ->whereHas('categories',
    fn($q) => $q->where('category_id', 1))
  ->get();
Neden Bu Seçenek?
  • Semantik Net: Tag = müzik karakteri, Category = kullanım senaryosu
  • Sector Bağlantısı: Category sector'e bağlı (Cafe'ye özel kategoriler)
  • Spotify Pattern: Aynı yapıyı kullanıyor (Browse → Categories → Playlists)
  • Kolay Frontend: Filter butonları + Category sections

Hızlı Karar Tablosu

Özellik Seçenek 1
Tag Hiyerarşisi
Seçenek 2
Categories
Seçenek 3
Polymorphic
Tablo Sayısı 1 tablo 2 tablo 1 tablo
Semantik Netlik ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐
Sorgu Kolaylığı ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
Frontend Kolay ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
Spotify Pattern Kısmen
Sector Bağlantısı
TOPLAM PUAN ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐
👑

ÖNERİLEN: Seçenek 2

Playlist Categories (Tag + Category Ayrımı)

Tablolar:
  • muzibu_tags → Müzik karakteristiği
  • muzibu_playlist_categories → Kullanım senaryosu
  • muzibu_playlistables → Polymorphic ilişki
Avantajları:
  • ✅ Net semantik (Tag ≠ Category)
  • ✅ Spotify Business pattern
  • ✅ Basit sorgular
  • ✅ Frontend'de kolay

Not: Category'ler sector'e bağlı olabilir (nullable). Cafe'ye özel kategoriler → sector_id=1, Global kategoriler → sector_id=NULL