🔍 Tenant Oluşturma Sistemi - Analiz & Hata Raporu

Multi-tenant mimarisinde tespit edilen kritik hatalar, iyileştirmeler ve öneriler
📅 13 Aralık 2025 🎯 Laravel Multi-Tenant 👤 Sistem Analizi

🚨 Kritik Hatalar (Acil Çözüm Gerekli!)

1

Permission Hatası - Storage Dizinleri Root Owner KRİTİK

Dosya: Modules/TenantManagement/app/Http/Livewire/TenantComponent.php

Satır: 629-670 prepareTenantDirectories()

❌ Sorun:

Yeni tenant oluşturulurken Laravel File::ensureDirectoryExists() kullanıyor. Bu fonksiyon PHP-FPM user'ı (root veya www-data) ile çalıştığında klasörleri root:root owner ile oluşturur.

Nginx/Apache'nin tuufi.com_:psaserv user'ı bu dosyalara erişemez → 403 Forbidden veya 500 Internal Server Error

✅ Çözüm:

Klasör oluşturulduktan HEMEN SONRA owner ve permission düzelt:

// TenantComponent::prepareTenantDirectories() içinde
$tenantPath = storage_path("tenant{$tenantId}");
File::ensureDirectoryExists($tenantPath, 0775, true);

// ✅ ZORUNLU: Owner düzelt!
exec("sudo chown -R tuufi.com_:psaserv {$tenantPath}");
exec("sudo find {$tenantPath} -type d -exec chmod 755 {} \\;");
exec("sudo find {$tenantPath} -type f -exec chmod 644 {} \\;");

Beklenen Sonuç: Tüm tenant storage klasörleri tuufi.com_:psaserv owner ile oluşur, site düzgün çalışır

2

Tenant Silme - Database Ayakta Kalıyor ORTA

Dosya: Modules/TenantManagement/app/Http/Livewire/TenantComponent.php

Satır: 358-389 deleteTenant()

❌ Sorun:

Tenant silinirken sadece Laravel kaydı ve storage dizinleri temizleniyor. MySQL database'i ayakta kalıyor! Bu orphan database'ler disk alanı tüketir.

✅ Çözüm:

Tenant silinirken database'i de DROP et:

// TenantComponent::deleteTenant() içinde
$tenant = Tenant::find($id);
if ($tenant) {
    // Storage temizle
    $this->cleanTenantDirectories($tenant->id);

    // ✅ Database'i DROP et
    $dbName = $tenant->tenancy_db_name;
    DB::statement("DROP DATABASE IF EXISTS `{$dbName}`");

    // Laravel kaydını sil
    $tenant->delete();
}

Beklenen Sonuç: Tenant silindiğinde hem Laravel kaydı, hem storage, hem de database temizlenir

3

JSON Double Encoding - theme_settings ORTA

Dosya: Modules/TenantManagement/app/Http/Livewire/TenantComponent.php

Satır: 265-279, 303-306

❌ Sorun:

theme_settings alanı migration'da json tipinde tanımlanmış.

TenantComponent'te DB::table()->update() ile json_encode($themeSettings) kullanılıyor.

Bu double encoding riski taşıyor çünkü Laravel JSON kolonları otomatik encode eder!

✅ Çözüm:

İKİ SEÇENEK var:

Seçenek 1: Eloquent Kullan (Önerilen)

// JSON cast varsa ARRAY gönder, Laravel otomatik encode eder
$tenant->update([
    'title' => $this->name,
    'theme_settings' => $themeSettings, // ✅ Array olarak
]);

Seçenek 2: DB::table() Kullanırsan Cast'i Devre Dışı Bırak

// DB::table() ile cast yok, manuel encode et
DB::table('tenants')->where('id', $id)->update([
    'theme_settings' => json_encode($themeSettings) // ✅ JSON string
]);

Beklenen Sonuç: theme_settings doğru JSON formatında saklanır, double encoding önlenir

⚡ İyileştirmeler (Önerilen)

1

Admin Panel'den Tenant Oluşturma - Seed Çalışmıyor

⚠️ Tutarsızlık:

readme/documentation/tenant-olusturma.md → Tinker örneğinde seeder çalıştırılıyor

Admin Panel (TenantComponent) → Seeder çalıştırmıyor!

✅ Öneri:

// TenantComponent::saveTenant() içinde
$tenant = Tenant::create([...]);

// Tenant database'ini seed et
$tenant->run(function () {
    Artisan::call('db:seed', [
        '--class' => 'TenantDatabaseSeeder',
        '--force' => true
    ]);
});

Beklenen Sonuç: Admin panel'den oluşturulan tenant'lar da otomatik seed edilir

2

Modül Migration Path'i Test Edilmemiş

⚠️ Risk:

config/tenancy.php'--path' => ['Modules/*/database/migrations/tenant']

Joker karakter (*) kullanıldığı için tüm modüllerin tenant migration'ları otomatik yüklenmeli ama test edilmemiş!

✅ Öneri:

Yeni bir test tenant oluştur ve migration'ları kontrol et:

php artisan tenants:migrate --tenant=test_tenant_id

# Modül migration'larının yüklenip yüklenmediğini kontrol et
# Eğer sorun varsa path'i manuel listele:
'--path' => [
    'database/migrations/tenant',
    'Modules/Shop/database/migrations/tenant',
    'Modules/Blog/database/migrations/tenant',
    // ...
]
3

Döküman Eksiklikleri

⚠️ Eksik Konular:

  • Database CREATE yetkisi kontrolü nasıl yapılır?
  • Admin panel'den tenant oluşturma adımları eksik
  • Tenant silme sürecinde database DROP işlemi yok
  • Permission (owner/chmod) düzeltme zorunlu olduğu belirtilmemiş
  • Domain normalization (www kaldırma) mantığı açıklanmamış

✅ Öneri:

readme/documentation/tenant-olusturma.md dosyasını güncelle:

  • Admin panel tenant oluşturma bölümü ekle
  • Database CREATE permission test komutu ekle
  • Tenant silme için DROP DATABASE adımı ekle
  • Permission düzeltme komutlarını ekle
  • Domain normalization mantığını açıkla

✅ Doğru Çalışan Sistemler

✅ ID Generator Tutarlı

UUID devre dışı (id_generator: null), integer ID kullanılıyor ($incrementing = true). Migration ve model tutarlı.

✅ Domain Normalization

normalizeDomain() fonksiyonu www prefix'ini, http/https protocol'ünü ve trailing slash'i otomatik temizliyor.

✅ Primary Domain Auto-Set

İlk eklenen domain otomatik olarak primary yapılıyor (setPrimaryDomain()). Tenant başına sadece 1 primary domain olması garanti ediliyor.

✅ Storage Path Isolation

Her tenant için ayrı storage klasörü (storage/tenant{id}/) ve public storage linki (public/storage/tenant{id}/) oluşturuluyor.

✅ Database Manager Config

MySQLDatabaseManager aktif, CREATE permission granted. Tenant database'leri otomatik oluşuyor.

✅ Bootstrappers Doğru

Database, Redis, Storage, Queue, Session bootstrapper'ları aktif. Her tenant izole çalışıyor.

🎯 Öncelik Sıralaması

1

Storage Permission Hatası - HEMEN Düzelt!

prepareTenantDirectories() içine owner/chmod komutları ekle

2

Database DROP İşlemi - Tenant Silme

deleteTenant() içine DROP DATABASE ekle

3

JSON Double Encoding - theme_settings

Eloquent kullan veya json_encode() kaldır

4

Admin Panel Seeder Eksikliği

saveTenant() içine TenantDatabaseSeeder ekle

5

Dokümantasyon Güncelle

tenant-olusturma.md dosyasına eksik bölümleri ekle