Harika bir pivot! **Kategori Gruplama** yaklaşımı gerçekten çok daha esnek ve mantıklı. Detaylıca tartışalım:

---

## 🎯 Yeni Yaklaşım: Kategori Grupları (Many-to-Many)

### **Veritabanı Yapısı**

```
┌─────────────┐     ┌──────────────────┐     ┌────────────┐
│ categories  │     │ category_group   │     │ groups     │
├─────────────┤     ├──────────────────┤     ├────────────┤
│ id          │◄────│ category_id      │     │ id         │
│ name        │     │ group_id         │────►│ name       │
│ company_id  │     └──────────────────┘     │ order_num  │
│ data (JSON) │                              │ enabled    │
└─────────────┘                              └────────────┘
```

---

## ✅ Avantajlar (Top Category'ye Göre)

| Özellik                                           | Top Category (1:N)  | Kategori Grupları (M:N)      |
| ------------------------------------------------- | ------------------- | ---------------------------- |
| **Bir kategori birden fazla grupta olabilir mi?** | ❌ Hayır            | ✅ Evet                      |
| **Grupların kendi servis saati olur mu?**         | Sadece parent'ın    | ✅ Her grubun bağımsız saati |
| **Gruplar arası overlap mümkün mü?**              | ❌ Hayır            | ✅ Evet                      |
| **Migration karmaşıklığı**                        | Self-referencing FK | Pivot table (standart)       |
| **Circular reference riski**                      | 🔴 Var              | ✅ Yok                       |
| **UI esnekliği**                                  | Tree view gerekli   | Flat liste + badges          |
| **Query performansı**                             | Recursive join      | Simple pivot join            |

---

## 💡 Kullanım Senaryoları

### **Senaryo 1: Aynı Ürün Birden Fazla Kategoride**

```
📦 Izgara Köfte (Ürün)
   ├── Ana Yemekler (Kategori)
   └── Et Yemekleri (Kategori)

🏷️ Gruplar:
   ├── "Öğle Menüsü" → [Ana Yemekler, Çorbalar, İçecekler]
   ├── "Akşam Menüsü" → [Ana Yemekler, Tatlılar, Şaraplar]
   └── "Vejetaryen" → [Salatalar, Vejetaryen Ana Yemekler]
```

**Avantaj:** "Izgara Köfte" hem Öğle hem Akşam menüsünde görünür, ama farklı gruplamalarla.

---

### **Senaryo 2: Zaman Bazlı Gruplama**

```
🕐 Kahvaltı Grubu (07:00-11:00)
   ├── Kahvaltılıklar
   ├── Sıcak İçecekler
   └── Hamur İşleri

🕐 Gece Menüsü Grubu (22:00-02:00)
   ├── Atıştırmalıklar
   ├── Kokteyller
   └── Geç Saat Tatlıları
```

**Avantaj:** Servis saatleri **grup seviyesinde** yönetilir, kategoriler sadece organizasyon için.

---

### **Senaryo 3: Özel Kampanya Grupları**

```
🎉 Ramazan Özel
   ├── Çorbalar
   ├── Ana Yemekler (bazı ürünler)
   └── Tatlılar

💑 Sevgililer Günü Menü
   ├── Başlangıçlar
   ├── Ana Yemekler (premium)
   └── Şaraplar
```

**Avantaj:** Geçici gruplar oluşturulabilir, kategorilere dokunmadan.

---

## 🏗️ Implementation Plan

### **1. Migration Files**

#### **Migration 1: `create_groups_table.php`**

```php
Schema::create('groups', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('company_id'); // Multi-tenancy
    $table->string('name'); // "Öğle Menüsü", "Akşam Menüsü", vb.
    $table->text('description')->nullable();
    $table->integer('order_number')->default(0);
    $table->boolean('enabled')->default(true);
    $table->json('data')->nullable(); // Servis saatleri, özel ayarlar
    $table->timestamps();
    $table->softDeletes();

    $table->foreign('company_id')->references('id')->on('companies');
});
```

#### **Migration 2: `create_category_group_table.php`**

```php
Schema::create('category_group', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('category_id');
    $table->unsignedBigInteger('group_id');
    $table->integer('order_in_group')->default(0); // Grup içinde sıralama
    $table->timestamps();

    $table->foreign('category_id')->references('id')->on('categories')->cascadeOnDelete();
    $table->foreign('group_id')->references('id')->on('groups')->cascadeOnDelete();

    // Unique constraint: Aynı kategori aynı gruba 2 kez eklenemez
    $table->unique(['category_id', 'group_id']);
});
```

#### **Migration 3: `add_group_id_to_categories_table.php`** (Opsiyonel - Tekil ilişki için)

```php
// NOT: Eğer her kategori SADECE 1 gruba ait olacaksa bu yeterli
// Ama M:N istiyorsak bu migration'a gerek YOK
Schema::table('categories', function (Blueprint $table) {
    // BU MIGRATION'I YAPMIYORUZ - pivot table kullanıyoruz
});
```

**Karar:** Pivot table (`category_group`) M:N ilişkisi için yeterli. `categories` tablosuna `group_id` eklemeye **gerek yok**.

---

### **2. Models**

#### **`app/Models/Group.php`** (Yeni Model)

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Group extends Model
{
    use HasFactory, SoftDeletes;

    protected $connection = 'mysql-remote';

    protected $fillable = [
        'company_id',
        'name',
        'description',
        'order_number',
        'enabled',
        'data',
    ];

    protected $casts = [
        'order_number' => 'integer',
        'enabled' => 'boolean',
        'data' => 'array',
    ];

    /**
     * Global scope to filter by selected POS
     */
    protected static function booted()
    {
        static::addGlobalScope('selected_pos', function ($builder) {
            $selectedPosServiceId = session('selected_pos_service_id');
            if ($selectedPosServiceId) {
                $builder->where('company_id', $selectedPosServiceId);
            }
        });
    }

    /**
     * Many-to-Many: Group has many Categories
     */
    public function categories()
    {
        return $this->belongsToMany(PosCategory::class, 'category_group')
                    ->withPivot('order_in_group')
                    ->orderBy('pivot_order_in_group');
    }

    /**
     * Check group service hours (similar to category logic)
     */
    public function checkGroupServiceHours(bool $globalIsOpen = true): array
    {
        $data = $this->data ?? [];

        if (!($data['service_hours_enabled'] ?? false)) {
            return [
                'is_open' => $globalIsOpen,
                'reason' => $globalIsOpen ? null : 'Servis saatleri dışında',
            ];
        }

        // Same multi-slot logic as PosCategory::checkCategoryServiceHours()
        // ... (code reuse possible via trait or helper)
    }
}
```

#### **`app/Models/PosCategory.php`** (Güncelleme)

```php
/**
 * Many-to-Many: Category belongs to many Groups
 */
public function groups()
{
    return $this->belongsToMany(Group::class, 'category_group')
                ->withPivot('order_in_group')
                ->orderBy('pivot_order_in_group');
}

/**
 * Scope: Get categories that belong to a specific group
 */
public function scopeInGroup($query, $groupId)
{
    return $query->whereHas('groups', function ($q) use ($groupId) {
        $q->where('group_id', $groupId);
    });
}
```

---

### **3. MenuController Güncellemeleri**

#### **Mevcut Logic (Line 185-236):**

```php
$categories = PosCategory::with([
    'translations',
    'products' => function ($query) use ($currentLocale) {
        // ...
    },
])
->menuEnabled()
->orderBy('order_number')
->get()
->filter(function ($category) use ($currentLocale) {
    // ... translation & image loading
    return $category->products->isNotEmpty();
});
```

#### **Yeni Logic (Grup Filtreleme ile):**

```php
// Option A: Tüm kategorileri getir, gruplara göre organize et
$groups = Group::with([
    'categories' => function ($query) use ($currentLocale) {
        $query->menuEnabled()
              ->with(['translations', 'products.translations'])
              ->orderBy('order_number');
    },
])
->where('enabled', true)
->orderBy('order_number')
->get()
->filter(function ($group) {
    // Boş grupları filtrele
    return $group->categories->isNotEmpty();
});

// Option B: Belirli bir grubun kategorilerini getir (ör: "Öğle Menüsü")
$activeGroupId = session('active_menu_group_id'); // Session'dan alınabilir
$categories = PosCategory::inGroup($activeGroupId)
    ->with(['translations', 'products'])
    ->menuEnabled()
    ->orderBy('order_number')
    ->get();
```

---

### **4. UI/UX Tasarımı**

#### **A) Menü Sayfası - Grup Seçimi**

```blade
{{-- menu/digital.blade.php --}}

<!-- Grup Selector (Tabs veya Dropdown) -->
<div class="mb-6">
    <h2 class="mb-3 text-lg font-semibold">Menü Grupları</h2>
    <div class="flex gap-2 overflow-x-auto">
        @foreach($groups as $group)
            <button
                wire:click="selectGroup({{ $group->id }})"
                class="px-4 py-2 rounded {{ $activeGroupId == $group->id ? 'bg-stone-600 text-white' : 'bg-gray-200' }}"
            >
                {{ $group->name }}
            </button>
        @endforeach
    </div>
</div>

<!-- Aktif Grubun Kategorileri -->
@if($activeGroup)
    <div class="space-y-6">
        @foreach($activeGroup->categories as $category)
            <div class="category-section">
                <h3 class="text-xl font-bold">{{ $category->name }}</h3>

                @foreach($category->products as $product)
                    <!-- Product Card -->
                @endforeach
            </div>
        @endforeach
    </div>
@endif
```

---

#### **B) Admin Panel - Grup Yönetimi**

**Route:** `/pos-groups` (CRUD)

**Livewire Component:** `GroupManager`

- Grup oluştur/düzenle/sil
- Kategorileri gruba ekle/çıkar (multi-select)
- Grup servis saatleri ayarla
- Grup görünürlüğü toggle

**Blade View:** `resources/views/pos-groups/index.blade.php`

```blade
@foreach($groups as $group)
    <div class="card">
        <h3>{{ $group->name }}</h3>
        <p>Kategoriler: {{ $group->categories->count() }}</p>

        <div class="badges">
            @foreach($group->categories as $category)
                <span class="badge">{{ $category->name }}</span>
            @endforeach
        </div>

        <button>Edit</button>
        <button>Delete</button>
    </div>
@endforeach
```

---

## 🔍 Potansiyel Sorunlar & Çözümler

### **Problem 1: Grup Seviyesinde Servis Saati Override**

**Senaryo:**

```
🏷️ Grup: "Öğle Menüsü" (12:00-15:00)
   ├── 📁 Ana Yemekler (Kendi saati: 11:00-22:00)
   └── 📁 Çorbalar (Kendi saati: TANIMSIZ)
```

**Soru:** Saat 13:00'de hangisi açık?

**Çözüm - Öncelik Hiyerarşisi:**

```
1. Kategori'nin KENDİ servisi saati varsa → ONU KULLAN
2. Kategori'nin servisi saati yoksa → GRUBUN servisi saatini kullan
3. Grup'un da servisi saati yoksa → GLOBAL'i kullan
```

**Implementation:**

```php
// PosCategory.php
public function checkCategoryServiceHours(bool $globalIsOpen = true): array
{
    $data = $this->data ?? [];

    // 1. Kendi saati varsa → onu kullan
    if ($data['service_hours_enabled'] ?? false) {
        return $this->evaluateOwnServiceHours();
    }

    // 2. Grubu varsa → grubun saatini kontrol et
    if ($this->groups->isNotEmpty()) {
        foreach ($this->groups as $group) {
            $groupCheck = $group->checkGroupServiceHours($globalIsOpen);
            if ($groupCheck['is_open']) {
                return $groupCheck; // İlk açık grubu döndür
            }
        }
    }

    // 3. Hiçbiri yoksa → global
    return [
        'is_open' => $globalIsOpen,
        'reason' => $globalIsOpen ? null : 'Servis saatleri dışında',
    ];
}
```

---

### **Problem 2: Kategori Birden Fazla Grupta, Farklı Saatlerde**

**Senaryo:**

```
📁 Ana Yemekler
   ├── "Öğle Menüsü" grubunda (12:00-15:00)
   └── "Akşam Menüsü" grubunda (18:00-23:00)
```

**Soru:** Saat 14:00'de "Ana Yemekler" açık mı?

**Cevap:**

- "Öğle Menüsü" seçiliyse → EVET ✅
- "Akşam Menüsü" seçiliyse → HAYIR ❌

**Implementation:**

```php
// MenuController'da aktif gruba göre filtreleme
$activeGroup = Group::find(session('active_menu_group_id'));

$categories = $activeGroup->categories()
    ->menuEnabled()
    ->get()
    ->filter(function ($category) use ($activeGroup) {
        // Grubun servis saatlerini kontrol et
        $groupCheck = $activeGroup->checkGroupServiceHours();

        // Veya kategorinin kendi saatlerini kontrol et
        $categoryCheck = $category->checkCategoryServiceHours($groupCheck['is_open']);

        return $categoryCheck['is_open'];
    });
```

---

### **Problem 3: N+1 Query (Groups Loading)**

**Risk:**

```php
@foreach($categories as $category)
    {{ $category->groups->pluck('name')->join(', ') }}
    <!-- ← Her kategori için ayrı query! -->
@endforeach
```

**Çözüm:**

```php
// Eager loading
$categories = PosCategory::with('groups')
    ->menuEnabled()
    ->get();
```

---

## 📊 Karşılaştırma: Top Category vs Grup Sistemi

| Kriter                      | Top Category              | Kategori Grupları               |
| --------------------------- | ------------------------- | ------------------------------- |
| **Migration Complexity**    | 🟡 Medium (self-ref FK)   | 🟢 Easy (pivot table)           |
| **Circular Reference Risk** | 🔴 High                   | ✅ None                         |
| **Flexibility**             | 🟡 Low (1:N only)         | ✅ High (M:N)                   |
| **Query Performance**       | 🟡 Recursive joins        | ✅ Simple pivot joins           |
| **UI Complexity**           | 🔴 Tree view needed       | 🟢 Flat list + badges           |
| **Use Case Fit**            | 🟡 Hierarchical menus     | ✅ Campaign/time-based grouping |
| **Maintenance**             | 🟡 Complex (parent-child) | ✅ Simple (attach/detach)       |

---

## ✅ Sonuç ve Önerim

**Kategori Grupları yaklaşımı KESİNLİKLE daha iyi!** Nedenleri:

1. ✅ **Daha az iş:** Circular reference validation yok, recursive logic yok
2. ✅ **Daha fazla esneklik:** Bir kategori birden fazla grupta olabilir
3. ✅ **Daha temiz kod:** Standart Laravel M:N pattern
4. ✅ **Daha güçlü UX:** Grup bazlı filtreleme, kampanya menüleri
5. ✅ **Future-proof:** Yeni kullanım senaryolarına kolay adaptasyon

---

## 🚀 Implementation Plan (Adım Adım)

**Phase 1: Database (30 dk)**

1. `create_groups_table` migration
2. `create_category_group_table` migration
3. Run migrations

**Phase 2: Models (45 dk)** 4. `Group` model oluştur 5. `PosCategory::groups()` relationship ekle 6. `Group::checkGroupServiceHours()` method ekle

**Phase 3: Admin UI (2 saat)** 7. `pos-groups.index` route + controller 8. `GroupManager` Livewire component 9. CRUD blade views

**Phase 4: Menu Integration ✅ TAMAMLANDI** 10. ✅ `MenuController` güncelle — `buildMenuGroups()` helper + `'groups'` eager loading (N+1 fix) 11. ✅ 3 menü view'ı güncelle (`digital`, `customer_qr`, `index`) — koşullu grup/flat render 12. ✅ `grouped-categories.blade.php` partial — yatay scroll tab selector + "Diğer" sekmesi

**Phase 5: Testing (1 saat)** 13. Edge case tests 14. Performance tests

**Total:** ~6 saat

---

## ⚙️ Settings: `show_groups_on_menu`

### **Ayar Tanımı**

Müşteri tarafındaki dijital menüde kategori gruplarının gösterilip gösterilmeyeceğini kontrol eder.

```php
'show_groups_on_menu' => [
    'type'             => 'bool',
    'default'          => false,
    'parent_setting' => 'menu_module_enabled',
],
```

| Özellik         | Değer                      |
| --------------- | -------------------------- |
| **Key**         | `show_groups_on_menu`      |
| **Tür**         | `bool` (Açık/Kapalı)       |
| **Varsayılan**  | `false` (kapalı)           |
| **UI Label**    | "Menüde Grupları Göster"   |
| **UI Kontrolü** | Select box (Açık / Kapalı) |

### **Davranış Mantığı**

```
show_groups_on_menu = false (varsayılan)
   → Mevcut davranış: Tüm kategoriler düz liste olarak gösterilir
   → Gruplar admin panelde yönetilebilir ama menüde görünmez
   → **Geriye uyumlu — prod üzerinde hiçbir değişiklik yok**

show_groups_on_menu = true
   → Grup selector (tab/dropdown) menüde görünür
   → Kategoriler gruplara göre organize edilir
   → Grup servis saatleri uygulanır
```

### **Phase 4 Entegrasyonu**

`MenuController` içinde:

```php
$showGroups = Setting::where('relation_type', 'company')
    ->where('relation_id', $companyId)
    ->where('key', 'show_groups_on_menu')
    ->value('value') === '1';

if ($showGroups) {
    // Grup bazlı kategori organizasyonu
    $groups = Group::where('enabled', true)
        ->with(['categories' => fn($q) => $q->menuEnabled()])
        ->orderBy('order_number')
        ->get();

    return view(..., compact('groups'));
} else {
    // Mevcut davranış — düz liste
    $categories = PosCategory::menuEnabled()
        ->orderBy('order_number')
        ->get();

    return view(..., compact('categories'));
}
```

### **Admin Panel Görünümü**

Settings sayfasında (`/settings/index`) "Menüde Grupları Göster" satırı:

- Ayar adı: Menüde Grupları Göster
- Key: `show_groups_on_menu`
- Kontrol: Açık / Kapalı select box

---

**Başlayalım mı?** Hangi adımdan başlamak istersin? Ben Phase 1 (Database) ile başlamayı öneriyorum! 🎯
