🎯 Subscription Modülü

Tenant-Aware Aktif/Pasif Sistem Tasarımı

📅 2025-12-05 🎯 Multi-Tenant System ⚡ 3 Yaklaşım Analizi

🎯 Problem

Durum: Subscription modülü SADECE bazı tenant'lar için gerekli

✅ Tenant 1001 (Muzibu)

Müzik platformu → Subscription ZORUNLU

❌ Tenant 2 (İxtif)

Endüstriyel ekipman → Subscription GEREKLİ DEĞİL

? Gelecek Tenant'lar

Bazıları kullanacak, bazıları kullanmayacak

🎯 İhtiyaç:

  • ✅ Tenant bazında aktif/pasif edilebilmeli
  • ✅ Admin panelde kolay yönetilebilmeli
  • ✅ Route'lar otomatik açılıp kapanmalı
  • ✅ Menu'ler otomatik gösterilip gizlenmeli
  • ✅ Middleware ile korunmalı (disabled tenant erişemez)

💡 3 Yaklaşım Analizi

1

tenants.data JSON Field

ÖNERİLEN ✅

Nasıl Çalışır?

Tenant tablosundaki data JSON field'ına modül ayarları eklenir.

// tenants.data JSON
{
  "modules": {
    "subscription": {
      "enabled": true,
      "trial_enabled": true,
      "payment_gateway": "stripe"
    },
    "shop": {
      "enabled": true
    }
  }
}

✅ Avantajlar

  • ✅ Yeni migration gerekmez
  • ✅ Esnek yapı (JSON her şeyi tutabilir)
  • ✅ Tek bir yerden tüm modül ayarları
  • ✅ Helper ile kolay erişim
  • ✅ Cache ile hızlı
  • ✅ Admin panel ile kolay yönetim

⚠️ Dezavantajlar

  • ⚠️ JSON query biraz daha yavaş (ama cache var)
  • ⚠️ Yapı yönetimi (JSON schema gerekli)

📝 Kod Örnekleri

Helper Function:

function tenant_module_enabled(string $module): bool
{
  return tenant()?->data['modules'][$module]['enabled'] ?? false;
}

Kullanım:

@if(tenant_module_enabled('subscription'))
  <a href="/admin/subscription">Abonelikler</a>
@endif

Middleware:

if (!tenant_module_enabled('subscription')) {
  abort(404);
}
2

SettingsManagement Modülü

ORTA DÜZEY

Nasıl Çalışır?

SettingsManagement modülüne yeni bir grup eklenir: "Modül Ayarları"

// settings_groups + settings tablosu
Group: "module_settings"
Settings:
  - subscription_enabled (boolean)
  - subscription_trial_enabled (boolean)
  - shop_enabled (boolean)

✅ Avantajlar

  • ✅ Mevcut Settings UI kullanılır
  • ✅ setting() helper ile kolay erişim
  • ✅ Tenant bazında otomatik
  • ✅ Activity log otomatik

⚠️ Dezavantajlar

  • ⚠️ Her modül için yeni setting eklemek gerekir
  • ⚠️ Settings tablosu şişer
  • ⚠️ Performans (cache var ama N+1 riski)
  • ⚠️ Modül ayarları ile site ayarları karışabilir

📝 Kod Örnekleri

Kullanım:

@if(setting('subscription_enabled'))
  <a href="/admin/subscription">Abonelikler</a>
@endif
3

tenants Tablosuna Yeni Kolon

ÖNERİLMEZ ❌

Nasıl Çalışır?

Her modül için tenants tablosuna yeni boolean kolon eklenir.

// tenants tablosuna yeni kolonlar
$table->boolean('subscription_enabled')->default(false);
$table->boolean('shop_enabled')->default(false);
$table->boolean('blog_enabled')->default(true);

✅ Avantajlar

  • ✅ En hızlı query (direkt kolon)
  • ✅ Index'lenebilir
  • ✅ Basit kod

❌ Dezavantajlar (Çok!)

  • ❌ Her modül için migration gerekir
  • ❌ Tablo şişer (5 modül = 5 kolon)
  • ❌ Esneklik yok (JSON gibi nested yapı yok)
  • ❌ Ölçeklenebilir değil
  • ❌ Modül kaldırınca kolon kalır

✅ ÖNERİLEN YAKLAŞIM

🎯

YAKLAŞIM 1: tenants.data JSON

En esnek ve ölçeklenebilir çözüm

🎯 Neden Bu Yaklaşım?

  • Esneklik: JSON'a istediğin kadar modül ekle, nested yapılar kur, hiç migration gerekmez
  • Performans: Cache ile hızlı erişim, tenant() zaten yüklü
  • Merkezi: Tüm modül ayarları tek yerde (tenants.data)
  • Ölçeklenebilir: 100 modül olsa bile tablo şişmez
  • Temiz Kod: Helper function ile kolay kullanım

📋 Implementation Plan

  1. Helper Function Oluştur: tenant_module_enabled()
  2. Middleware Oluştur: TenantModuleEnabled
  3. Admin UI Ekle: Tenant Ayarları → Modül Yönetimi sayfası
  4. Route Guard: Subscription route'larına middleware ekle
  5. Menu Guard: Sidebar menu'lerde kontrol ekle
  6. Cache: tenant() zaten cache'li, ekstra cache gerekmez

🎨 JSON Yapı Örneği

{
  "modules": {
    "subscription": {
      "enabled": true,
      "config": {
        "trial_enabled": true,
        "trial_days": 7,
        "payment_gateway": "stripe",
        "currency": "TRY"
      }
    },
    "shop": {
      "enabled": true,
      "config": {
        "inventory_enabled": false
      }
    },
    "blog": {
      "enabled": true
    }
  },
  "theme": {
    "colors": {...}
  }
}

🛠️ Implementation Adımları

1

Helper Function Oluştur

// app/helpers.php

function tenant_module_enabled(string $module): bool
{
  if (!tenant()) {
    return false;
  }

  $data = tenant()->data ?? [];
  return $data['modules'][$module]['enabled'] ?? false;
}

function tenant_module_config(string $module, ?string $key = null)
{
  if (!tenant()) {
    return $key ? null : [];
  }

  $data = tenant()->data ?? [];
  $config = $data['modules'][$module]['config'] ?? [];

  return $key ? ($config[$key] ?? null) : $config;
}
2

Middleware Oluştur

// app/Http/Middleware/TenantModuleEnabled.php

public function handle($request, Closure $next, string $module)
{
  if (!tenant_module_enabled($module)) {
    abort(404, "Module not enabled for this tenant");
  }

  return $next($request);
}
3

Route'lara Middleware Ekle

// Modules/Subscription/routes/admin.php

Route::middleware(['tenant_module:subscription'])
  ->prefix('admin/subscription')
  ->group(function () {
    // Subscription routes...
  });
4

Menu Guard Ekle

// Admin sidebar menu

@if(tenant_module_enabled('subscription'))
  <li>
    <a href="{{ route('admin.subscription.index') }}">
      <i class="fas fa-crown"></i>
      Abonelikler
    </a>
  </li>
@endif
5

Admin UI (Modül Yönetimi)

Tenant ayarları sayfasına yeni bir bölüm ekle:

  • Sayfa: /admin/tenant-settings/modules
  • UI: Toggle switch'ler ile aktif/pasif
  • Livewire Component: TenantModuleSettingsComponent
  • İşlem: tenant()->update(['data' => $data])
6

İlk Konfigürasyon (Seeder)

// database/seeders/TenantModuleSeeder.php

Tenant::where('id', 1001)->update([
  'data' => [
    'modules' => [
      'subscription' => [
        'enabled' => true
      ]
    ]
  ]
]);

Tenant::where('id', 2)->update([
  'data' => [
    'modules' => [
      'subscription' => [
        'enabled' => false
      ]
    ]
  ]
]);

📊 Özet

✅ Seçilen Yaklaşım

  • ✅ tenants.data JSON field
  • ✅ Helper: tenant_module_enabled()
  • ✅ Middleware: TenantModuleEnabled
  • ✅ Route guard
  • ✅ Menu guard
  • ✅ Admin UI

🎯 Sonuç

  • 🎯 Tenant 1001 (Muzibu): Subscription AKTİF
  • 🎯 Tenant 2 (İxtif): Subscription PASİF
  • 🎯 Gelecek tenant'lar: Toggle ile açıp kapayabilir
  • 🎯 Yeni modül eklemek: Sadece JSON'a ekle