Tenant Oluşturma Süreci

Multi-Tenant Mimari - Kapsamlı Teknik Analiz

Central + Tenant DB Plesk Entegrasyonu SSL Sertifikası Storage Yönetimi

Basit Anlatım (Herkes İçin)

Tenant Nedir?

Tenant, sistemde bağımsız çalışan bir "kiracı site"dir. Her tenant'ın kendi veritabanı, dosyaları ve ayarları vardır. Örneğin: muzibu.com bir tenant, ixtif.com başka bir tenant'tır.

Ne Oluyor?

Yeni tenant oluşturulduğunda: veritabanı yaratılır, tablolar oluşturulur, dosya klasörleri hazırlanır, domain Plesk'e kaydedilir ve SSL sertifikası yenilenir.

Ne Kadar Sürer?

Tüm işlemler senkron (anında) çalışır. SSL sertifikası yenileme de dahil - wildcard DNS sayesinde *.tuufi.com subdomain'leri için bekleme gerekmez.

Neden Önemli?

Her site izole çalışır - birinin verileri diğerini etkilemez. Plesk entegrasyonu sayesinde domain yönetimi ve SSL otomatiktir.

Genel Akış Şeması

1. Tenant::create() 2. TenantCreated Event 3. CreateDatabase Job 4. MigrateDatabase Job 5. SeedDatabase Job
6. DatabaseMigrated Event 7. Storage + Plesk DB 8. Domain Ekleme 9. Plesk Alias 10. SSL Yenileme

Detaylı Adımlar

1

Tenant::create() - Central DB'ye Kayıt

Kullanıcı yeni tenant oluşturduğunda başlangıç noktası

Tetikleyen Dosya

// Modules/TenantManagement/App/Http/Controllers/ // TenantManagementController.php:41-91 $tenant = Tenant::create([ 'title' => $validated['title'], 'tenancy_db_name' => $dbName, 'is_active' => true, 'theme_id' => $validated['theme_id'], 'data' => $data, ]);

Central DB - tenants Tablosu

AlanAçıklama
idAuto increment
titleTenant adı
tenancy_db_nametenant_[slug]_[6hex] (unique)
is_activeBoolean
theme_idFK → themes
ai_credits_balanceAI kredi bakiyesi
dataJSON ek veriler

DB Name Oluşturma: tenant_[title_slug]_[6_hex_random] formatında unique isim üretilir. Örnek: tenant_kirmizi_a5f2c1

Otomatik Tema Sistemi (t-{id})

Tema seçiminde "Otomatik (t-{id})" seçildiğinde:

  • Tenant ID'ye göre otomatik tema oluşturulur (örn: t-3)
  • Central DB'de themes tablosuna kayıt eklenir
  • resources/views/themes/t-{id}/ klasörü oluşturulur
  • config.json, layouts/app.blade.php, homepage.blade.php dosyaları üretilir
  • Tema simple temasını extend eder (fallback)
Dosya: Modules/TenantManagement/App/Http/Livewire/TenantComponent.php
Metodlar: createAutoTheme(), createAutoThemeFiles()
2

TenantCreated Event → JobPipeline

Tenant kaydedilince otomatik tetiklenen event ve job'lar

// app/Providers/TenancyServiceProvider.php:27-39 Events\TenantCreated::class => [ JobPipeline::make([ Jobs\CreateDatabase::class, // ✅ 1. Veritabanı oluştur Jobs\MigrateDatabase::class, // ✅ 2. Migration'ları çalıştır Jobs\SeedDatabase::class, // ✅ 3. Seeder'ları çalıştır ])->shouldBeQueued(false), // Senkron çalışır ],
CreateDatabase

MySQL'de yeni veritabanı oluşturur: CREATE DATABASE tenant_xxx

MigrateDatabase

php artisan tenants:migrate ile tüm tenant migration'ları çalıştırır

SeedDatabase

php artisan tenants:seed ile başlangıç verilerini ekler

3

Tenant Database Migration'ları

Tenant DB'de oluşturulan tüm tablolar

Base Migrations (database/migrations/tenant/)

  • users - Kullanıcılar
  • cache - Cache tablosu
  • jobs - Queue jobs
  • sessions - Session'lar
  • media - Medya dosyaları
  • activity_log - Activity log
  • module_tenant_settings
  • tenant_usage_logs
  • tags, taggables

Modül Migrations (Modules/*/database/migrations/tenant/)

  • UserManagement: permissions, roles
  • LanguageManagement: tenant_languages
  • MenuManagement: menus, menu_items
  • Page: pages
  • Blog: blog_categories, blogs
  • Portfolio: portfolio_categories, portfolios
  • Shop: 30+ tablo (products, orders vb.)
  • Cart, Payment, Coupon, AI...

Toplam: ~100+ migration dosyası, tüm modüllerin tenant tabloları otomatik oluşturulur.

4

TenantDatabaseSeeder - Başlangıç Verileri

Tenant DB'ye eklenen varsayılan veriler

// database/seeders/TenantDatabaseSeeder.php 1. seedLanguages() // 100 dil kopyala (sadece TR aktif) 2. seedModuleTenants() // Central'dan aktif modülleri al 3. seedPermissions() // Central'dan permission'ları kopyala 4. seedRoles() // root, admin, editor, user rolleri 5. assignPermissionsToRoles() // Rol-permission ilişkileri 6. seedUsers() // 2 varsayılan kullanıcı 7. seedMenu() // Central'dan header menüsünü kopyala 8. seedHomePage() // Anasayfa oluştur 9. seedAIKnowledgeBase() // AI bilgi bankası
Varsayılan Kullanıcılar
  • nurullah@nurullah.net / g0nulcelen → root
  • info@turkbilisim.com.tr / gonu1celen → admin
Varsayılan Roller
  • root - Tüm yetkiler
  • admin - view, create, update (delete hariç)
  • editor - view, create, update
  • user - Sadece view
5

DatabaseMigrated Event → Storage + Plesk DB

Migration tamamlanınca tetiklenen işlemler

// app/Listeners/RegisterTenantDatabaseToPlesk.php Events\DatabaseMigrated::class => [ \App\Listeners\RegisterTenantDatabaseToPlesk::class, ],

Storage Klasörleri Oluşturma

storage/tenant{ID}/
├── framework/
│   ├── cache/
│   ├── sessions/
│   └── views/
├── app/
│   └── public/
└── logs/

Symlink: public/storage/tenant{ID}storage/tenant{ID}/app/public

Plesk Veritabanı Kaydı

// Plesk data_bases tablosuna INSERT 1. Domain ID bul (tuufi.com → 1) 2. DB Server ID bul (localhost → 1) 3. INSERT INTO data_bases: - name: tenant_xxx - type: mysql - dom_id: 1 - db_server_id: 1

3 deneme, 2 saniye bekleme (retry logic)

6

Domain Ekleme → Central DB

Tenant'a domain eklendiğinde tetiklenen işlemler

// Central DB - domains tablosu $domain = Domain::create([ 'domain' => 'yenisite.com', 'tenant_id' => $tenant->id, ]);
AlanAçıklama
idAuto increment
tenant_idFK → tenants.id (cascade delete)
domainDomain adı (unique)
is_primaryPrimary domain flag
7

DomainCreated Event → Otomatik WWW + Plesk Alias

Domain oluşturulunca tetiklenen listener'lar

// app/Providers/TenancyServiceProvider.php:56-59 Events\DomainCreated::class => [ \App\Listeners\CreateTenantDomains::class, // ✅ Otomatik www.domain \App\Listeners\RegisterDomainAliasInPlesk::class, // ✅ Plesk alias ],
CreateTenantDomains

Dosya: app/Listeners/CreateTenantDomains.php

  • yenisite.com eklenince
  • • Otomatik www.yenisite.com eklenir
  • • Central tenant'lara ekleme yapmaz
RegisterDomainAliasInPlesk

Dosya: app/Listeners/RegisterDomainAliasInPlesk.php

sudo /usr/sbin/plesk bin domalias \ --create yenisite.com \ -domain tuufi.com \ -web true -mail true -dns true \ -seo-redirect false

Önemli: Tüm domain'ler tuufi.com'a alias olarak bağlanır. Plesk alias oluşturulunca www subdomain'i otomatik eklenir.

8

SSL Sertifikası Yenileme (Let's Encrypt)

Yeni domain eklenince SSL sertifikası otomatik ve senkron olarak yenilenir

// app/Jobs/ReissueLetsEncryptCertificate.php // Senkron çalışır - dispatchSync() ile ReissueLetsEncryptCertificate::dispatchSync(); // Plesk Let's Encrypt komutu sudo /usr/sbin/plesk bin extension --exec letsencrypt cli.php \ -d tuufi.com -d www.tuufi.com \ -d yenisite.com -d www.yenisite.com \ -d eskisite.com -d www.eskisite.com \ ... (tüm domain'ler) \ -m ssl@tuufi.com
Job Özellikleri
  • $tries = 2 - 2 deneme
  • $timeout = 120 - 2 dakika timeout
  • $backoff = 30 - 30 sn retry bekleme
  • Senkron - Tenant kayıt bitmeden SSL hazır
Çalışma Mantığı
  • 1. Central DB'den tüm domain'leri al
  • 2. Her domain için -d parametresi ekle
  • 3. www. subdomain'leri de ekle
  • 4. Plesk Let's Encrypt CLI çalıştır

Wildcard DNS: *.tuufi.com wildcard DNS kaydı sayesinde subdomain'ler (örn: panjur.tuufi.com) için DNS propagation beklemeye gerek kalmaz.

Rate Limit: Let's Encrypt rate limit'e takılırsa warning log yazılır ve daha sonra tekrar denenir.

9

TenancyInitialized Event - Runtime Konfigürasyonu

Tenant context'e geçildiğinde yapılan ayarlar

// app/Providers/TenancyServiceProvider.php:88-146 Events\TenancyInitialized::class => [ // 1. Log yapılandırması config(['logging.channels.tenant.path' => storage_path('logs/tenant.log')]); // 2. Session lifetime (tenant setting'den) config(['session.lifetime' => setting('auth_session_lifetime', 525600)]); // 3. Session prefix (Redis için) config(['database.redis.session.options.prefix' => "tenant_{$tenantId}_session_"]); // 4. Cookie domain (.domain.com formatında) config(['session.domain' => '.yenisite.com']); ],

Tenant/Domain Silme İşlemleri

Tenant Silindiğinde

Events\TenantDeleted::class => [ SafeDeleteDatabase::class, // DB sil UnregisterDatabaseFromPlesk::class, // Plesk'ten kaldır ],
  • Veritabanı güvenli silinir
  • Plesk data_bases kaydı silinir
  • Domain'ler cascade delete ile silinir

Domain Silindiğinde

Events\DeletingDomain::class => [ UnregisterDomainAliasFromPlesk::dispatchSync(), ],
  • Plesk alias silinir (domalias --delete)
  • Senkron çalışır (domain silinmeden önce)
  • SSL'den otomatik çıkar (bir sonraki yenilemede)

Kritik Dosyalar Özet

Dosya Rol Açıklama
app/Models/Tenant.php Model Tenant modeli, relationships, AI helpers
app/Models/Domain.php Model Domain modeli (stancl/tenancy)
app/Providers/TenancyServiceProvider.php Provider Tüm event → listener mapping'leri
app/Listeners/RegisterTenantDatabaseToPlesk.php Listener Storage oluşturma + Plesk DB kaydı
app/Listeners/RegisterDomainAliasInPlesk.php Listener Plesk domain alias oluşturma
app/Listeners/CreateTenantDomains.php Listener Otomatik www.domain ekleme
app/Jobs/ReissueLetsEncryptCertificate.php Job SSL sertifikası yenileme (queue)
app/Jobs/UnregisterDomainAliasFromPlesk.php Job Plesk domain alias silme
app/Jobs/UnregisterDatabaseFromPlesk.php Job Plesk DB kaydı silme
database/seeders/TenantDatabaseSeeder.php Seeder Tenant başlangıç verileri
Modules/TenantManagement/.../Controller.php Controller CRUD API endpoints

Plesk Komutları Özet

Oluşturma Komutları

Domain Alias Oluştur:

sudo /usr/sbin/plesk bin domalias --create {domain} -domain tuufi.com -web true -mail true -dns true -seo-redirect false

DB Kaydı (SQL):

sudo /usr/sbin/plesk db "INSERT INTO data_bases (name, type, dom_id, db_server_id) VALUES ('{dbName}', 'mysql', {domainId}, {serverId})"

SSL Yenile:

sudo /usr/sbin/plesk bin extension --exec letsencrypt cli.php -d domain1 -d domain2 ... -m ssl@tuufi.com

Silme Komutları

Domain Alias Sil:

sudo /usr/sbin/plesk bin domalias --delete {domain}

DB Kaydı Sil (SQL):

sudo /usr/sbin/plesk db "DELETE FROM data_bases WHERE name = '{dbName}'"

Alias Kontrol:

sudo /usr/sbin/plesk bin domalias --info {domain}

Özet: Tüm Oluşturulan Kaynaklar

Central DB

  • • tenants tablosu
  • • domains tablosu
  • • module_tenants

Tenant DB

  • • MySQL database
  • • 100+ tablo
  • • Başlangıç verileri

Dosya Sistemi

  • • storage/tenant{ID}/
  • • public symlink
  • • logs klasörü

Plesk

  • • data_bases kaydı
  • • Domain alias
  • • SSL sertifikası

Yeni Tenant Oluşturma TODO Checklist

Otomatik Yapılanlar (Sistem)

Central DB - tenants tablosuna kayıt

id, title, tenancy_db_name, theme_id, is_active...

MySQL veritabanı oluştur

tenant_[slug]_[6hex] formatında unique isim

Tenant migration'ları çalıştır

php artisan tenants:migrate (100+ tablo)

Seeder çalıştır (başlangıç verileri)

Diller, roller, kullanıcılar, menü, anasayfa

Storage klasörleri oluştur

storage/tenant{ID}/ (cache, sessions, views, logs, app/public)

Public symlink oluştur

public/storage/tenant{ID} → storage/tenant{ID}/app/public

Plesk veritabanı kaydı

INSERT INTO data_bases (tuufi.com domain'ine bağlı)

Otomatik tema oluştur (opsiyonel)

"Otomatik (t-{id})" seçildiyse: t-{id} teması + dosyaları oluşturulur

Domain Eklendiğinde (Otomatik)

Central DB - domains tablosuna kayıt

domain (unique), tenant_id (FK)

Otomatik www. subdomain ekle

yenisite.com → www.yenisite.com otomatik eklenir

Plesk domain alias oluştur

plesk bin domalias --create (web, mail, dns enabled)

SSL sertifikası yenile (Let's Encrypt)

Senkron çalışır - tenant kaydı bitmeden SSL hazır olur

Manuel Kontroller (Opsiyonel)

DNS kayıtları kontrol et

Domain'in tuufi.com sunucusuna yönlendirildiğinden emin ol

SSL sertifikası kontrolü

https://yenisite.com açılıyor mu? Sertifika geçerli mi?

Tenant CSS oluştur (gerekirse)

npm run prod veya npm run css:tenant{ID}

Admin panele giriş test et

nurullah@nurullah.net / g0nulcelen ile giriş yap

Hızlı Kontrol Komutları

# Plesk alias kontrol:

sudo /usr/sbin/plesk bin domalias --info yenisite.com

# SSL sertifika kontrol:

curl -vI https://yenisite.com 2>&1 | grep -i "SSL\|expire"

# Tenant DB kontrol:

mysql -e "SHOW DATABASES LIKE 'tenant_%'"

# Storage symlink kontrol:

ls -la public/storage/ | grep tenant

Oluşturma Akışı Özeti

1. Tenant::create() 2. Auto Theme (t-{id}) 3. CreateDatabase 4. MigrateDatabase 5. SeedDatabase 6. Storage + Plesk DB 7. Domain Ekle 8. Plesk Alias 9. SSL (Senkron) ✓ HAZIR