SettingManagement Modülü - Detaylı Analiz

📅 Tarih: 2025-11-23 | 🎯 Analiz Kapsamı: Veritabanı, Modeller, Seeders | 👤 Hedef: Yeni Setting Grubu Oluşturma

📊 Genel Özeti

SettingManagement Nedir?

SettingManagement, sistemdeki tüm yapılandırma (ayar/setting) değerlerini merkezi şekilde yönetmeyi sağlayan bir Laravel modülüdür.

  • Settings Groups (Ayar Grupları) - Ayarları kategorilere böler (örn: AI Ayarları, Site Ayarları)
  • Settings (Ayarlar) - Her gruptaki bireysel ayarlar (örn: Site Adı, AI Asistan İsmi)
  • Settings Values (Ayar Değerleri) - Tenant'a özgü gerçek değerler

Mimari Yapı - Multi-Tenant Deseni

Settings Groups & Settings 📍 CENTRAL DATABASE (Tüm tenant'lar tarafından paylaşılan)
Settings Values 📍 TENANT DATABASE (Her tenant'ın kendi değerleri)

Bu tasarım sayesinde tüm tenant'larda aynı ayar tanımı kullanılırken her tenant kendi değerini saklar.

🗄️ Veritabanı Şeması

1. settings_groups (CENTRAL DATABASE)

Ayar gruplarını tanımlar. Hiyerarşik yapı destekler (parent_id ile alt gruplar).

Sütun Tür Açıklama
id BigInt Grup ID (Primary Key)
parent_id BigInt (Nullable) Ana grup (NULL = Ana kategorisi)
prefix String (Nullable) Ayar key prefix'i (örn: "site" → site_title, site_logo)
name String Grup adı (Türkçe, örn: "Site Ayarları")
slug String (Unique) URL friendly slug (örn: "site-ayarlari")
description Text (Nullable) Grup açıklaması
icon String (Nullable) FontAwesome icon (örn: "fas fa-cogs")
layout JSON (Nullable) Form layout tanımı (admin panel görünümü)
is_active Boolean Grup aktif mi? (default: true)
created_at, updated_at, deleted_at Timestamp Soft delete ile
💡 Prefix Nedir? Ayar key'lerinin otomatik ön ekidir. Örn: Prefix "site" ise ayar key "site_title", "site_logo" vb. olur. Bu sayede ilişkili ayarları gruplaştırabilirsiniz.

2. settings (CENTRAL DATABASE)

Ayar tanımlarını içerir. Tüm tenant'lar için geçerlidir (Values tenant'a özel).

Sütun Tür Açıklama
id BigInt Setting ID (Primary Key)
group_id BigInt (FK) Ait olduğu grup ID'si
label String Arayüzde gösterilen ad (Türkçe, örn: "Site Adı")
key String (Unique) Ayar anahtarı (örn: "site_title") - Kodda kullanılır
type String Input türü: text, textarea, select, image, file, favicon, json vb.
options JSON (Nullable) Select seçenekleri (örn: {"option1": "Seçenek 1"})
default_value Text (Nullable) Varsayılan değer (Settings Value boşsa kullanılır)
is_required Boolean Zorunlu mu?
is_system Boolean Sistem tarafından mı kontrol ediliyor?
is_active Boolean Aktif mi?
help_text Text (Nullable) Admin panel'de yardım metni

3. settings_values (TENANT DATABASE)

Her tenant'ın ayar değerlerini saklar. Tenant veritabanında yer alır.

Sütun Tür Açıklama
id BigInt Primary Key
setting_id BigInt (Unique) Central DB'deki setting ID'si (Foreign Key yok, manual)
value Text (Nullable) Gerçek ayar değeri
created_at, updated_at Timestamp Oluşturulma ve güncellenme tarihleri
⚠️ Önemli: Tenant database'de settings_values tablosu settings tablosuna Foreign Key'i olmuyor. Çünkü settings central DB'de ama settings_values tenant DB'de. Manual ilişki kurulur.

🔗 Veritabanı İlişkileri

Model Relationships

SettingGroup (Central DB) ├── parent_id → SettingGroup (hiyerarşi) ├── settings → Setting[] (hasMany) └── children → SettingGroup[] (hasMany) Setting (Central DB) ├── group_id → SettingGroup (belongsTo) └── values → SettingValue[] (hasMany) SettingValue (Tenant DB) └── setting_id → Setting (belongsTo - manuel ilişki)

Önemli: SettingValue'dan Setting'e Foreign Key olmuyor çünkü farklı veritabanlarında. Bunun yerine setting_id ile elle ilişkilendirilir.

Veri Akışı: Yazma İşlemi

1. Admin Panel → ValuesComponent Kullanıcı form'u doldurur
2. ValuesComponent SettingValue (Tenant DB) güncelle
3. SettingValue.saved() Event Cache temizle
4. Cache boş Sonraki okuma fresh data alır

Veri Akışı: Okuma İşlemi

1. Kod: setting('site_title') SettingsService.get()
2. Setting.where('key', 'site_title') Central DB'de kayıt bul
3. SettingValue.where('setting_id', ...) Tenant DB'de değer ara
4. Değer varsa Değeri döndür, yoksa default döndür

📋 Mevcut Ayar Grupları

Sistemde halihazırda tanımlı olan ayar grupları:

ID Grup Adı Slug Prefix Ana Grup
1 Genel Sistem genel-sistem - Ana kategori
5 Site site - Ana kategori
6 Site Ayarları site-ayarlari site Genel Sistem (1)
7 Tema tema theme Site (5)
8 SEO Ayarları seo-ayarlari seo Genel Sistem (1)
9 Yapay Zeka yapay-zeka ai Genel Sistem (1)
10 İletişim Bilgileri iletisim-bilgileri - Ana kategori
11 Bildirim Ayarları bildirim-ayarlari - Ana kategori
12 Payment Gateway Ayarları payment-gateway-ayarlari - Ana kategori
18 Blog - Yapay Zeka blog-yapay-zeka blog_ai Genel Sistem (1)

🆕 Yeni Ayar Grubu Oluşturma Adımları

Aşama 1: Seeder Oluşturma

Yeni bir seeder dosyası oluşturun:

Modules/SettingManagement/database/seeders/AuthRegistrationSeeder.php

Seeder içeriğinde yapılacaklar:

  • Adım 1: SettingGroup oluştur (updateOrInsert ile)
  • Adım 2: Ayarları array'de tanımla
  • Adım 3: Form layout JSON'ı oluştur (opsiyonel ama önerilen)
  • Adım 4: Her setting için database'e insert et

Örnek Seeder Yapısı:

namespace Modules\SettingManagement\Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class AuthRegistrationSeeder extends Seeder { public function run(): void { // 1. GRUP OLUŞTUR $groupId = 15; // Yeni ID $existing = DB::table('settings_groups') ->where('id', $groupId)->first(); DB::table('settings_groups')->updateOrInsert( ['id' => $groupId], [ 'name' => 'Kayıt Ayarları', 'slug' => 'kayit-ayarlari', 'parent_id' => 1, // Genel Sistem altında 'icon' => 'fas fa-user-plus', 'prefix' => 'auth_registration', 'is_active' => true, 'layout' => $this->getLayout(), 'created_at' => $existing->created_at ?? now(), 'updated_at' => now(), ] ); // 2. AYARLARI OLUŞTUR $settings = [ [ 'group_id' => $groupId, 'label' => 'Kayıt Formu Aktif', 'key' => 'auth_registration_enabled', 'type' => 'select', 'options' => json_encode(['0' => 'Devre Dışı', '1' => 'Aktif']), 'default_value' => '1', 'is_required' => true, ], // ... diğer ayarlar ]; foreach ($settings as $setting) { $existing = DB::table('settings') ->where('key', $setting['key'])->first(); DB::table('settings')->updateOrInsert( ['key' => $setting['key']], [ 'group_id' => $setting['group_id'], 'label' => $setting['label'], 'type' => $setting['type'], 'options' => $setting['options'] ?? null, 'default_value' => $setting['default_value'], 'is_required' => $setting['is_required'] ?? false, 'is_active' => true, 'help_text' => $setting['help_text'] ?? null, 'created_at' => $existing->created_at ?? now(), 'updated_at' => now(), ] ); } } private function getLayout(): string { // Form layout JSON'ı döndür $layout = [...]; return json_encode($layout); } }

Aşama 2: Seeder Çalıştırma

Seeder'ı database'e eklemek için:

// SettingManagementDatabaseSeeder.php içinde çağır: $this->call(AuthRegistrationSeeder::class); // Sonra: php artisan db:seed --class="Modules\\SettingManagement\\Database\\Seeders\\SettingManagementDatabaseSeeder"

Veya doğrudan:

php artisan db:seed --class="Modules\\SettingManagement\\Database\\Seeders\\AuthRegistrationSeeder"

Aşama 3: Kodda Kullanma

Oluşturduğunuz ayarları kodda kullanın:

// Helper ile $isEnabled = setting('auth_registration_enabled', '1'); // Service ile $isEnabled = app('settings')->get('auth_registration_enabled', '1'); // Model ile $setting = Setting::where('key', 'auth_registration_enabled')->first(); $value = $setting->getValue();

🏷️ Prefix Sistemi Detaylı Açıklaması

Prefix Nedir?

Prefix, SettingGroup'a verilen bir ön ek kodu olup, o grup altındaki tüm ayarların key'lerinin otomatik olarak ön ekine konur.

Örnek 1: Site Ayarları Grubu

Grup: "Site Ayarları" Prefix: "site" Ayarlar: - key: site_title (prefix + _ + ad) - key: site_logo (prefix + _ + ad) - key: site_favicon (prefix + _ + ad) - key: site_slogan (prefix + _ + ad) Kullanım: setting('site_title') setting('site_logo')

Örnek 2: AI Ayarları Grubu

Grup: "Yapay Zeka" Prefix: "ai" Ayarlar: - key: ai_assistant_name - key: ai_company_sector - key: ai_response_tone - key: ai_price_policy Kullanım: setting('ai_assistant_name') setting('ai_company_sector')

Prefix Olmayan Gruplar

Ana kategorilerin (parent_id = NULL) prefix'i olmayabilir. Bu durumda alt gruplar prefix alır:

Ana Grup: "Genel Sistem" (prefix: NULL) └─ Alt Grup: "Site Ayarları" (prefix: "site") └─ Ayarlar: site_title, site_logo, ... └─ Alt Grup: "Yapay Zeka" (prefix: "ai") └─ Ayarlar: ai_assistant_name, ai_company_sector, ...
⚠️ Önemli: Prefix'ler sistemin naming convention'ıdır. Key'leri elle girirken prefix'i düşünmeniz gerekir. Panel otomatik vermez.

📝 Setting Tipleri (Type)

Tip Örnek Açıklama
text site_title Tek satır metin input
textarea ai_custom_instructions Çok satırlı metin alanı
select ai_response_tone Dropdown seçim (options gerekli)
image site_logo_2 Görsel yükleme (Spatie Media Library)
file site_logo Dosya yükleme
favicon site_favicon Favicon yükleme
json ai_knowledge_base JSON verisi
image_multiple gallery_images Çoklu görsel

🎨 Layout Sistemi (Admin Panel Tasarımı)

Layout Nedir?

Layout, admin panel'de form'un nasıl görüneceğini tanımlayan JSON yapısıdır. Her ayarın yerini, sırasını, başlıklarını vb. belirler.

Layout Yapısı

{ "title": "Form Başlığı", "elements": [ // Heading { "type": "heading", "properties": { "content": "Bölüm Başlığı", "size": "h3", "width": 12 } }, // Row (Satır - responsive columns) { "type": "row", "properties": { "columns": [ {"index": 1, "width": 6}, {"index": 2, "width": 6} ] }, "columns": [ { "width": 6, "elements": [ { "type": "text", "properties": { "label": "Alan Adı", "name": "site_title", "setting_id": 1, "placeholder": "Örn: İXTİF", "help_text": "Sitenizin adı" } } ] }, { "width": 6, "elements": [...] } ] }, // Divider { "type": "divider", "properties": {"width": 12} }, // Section { "type": "section", "properties": { "content": "Önemli Bölüm", "width": 12 } } ] }

Layout Kuralları

  • Width: 1-12 arası Bootstrap grid (6 = yarısı, 12 = tam)
  • Elements: Satır içindeki alanlar (columns içinde tanımlanır)
  • setting_id: Settings tablosundaki alan ID'si (form builder'ın hangi setting'i göstereceğini bilmesi için)
  • Responsive: Columns property sayesinde responsive tasarım
💡 İpucu: AISettingsSeeder.php dosyasında harika bir layout örneği var. Karmaşık layout'lar için bu dosyayı inceleyebilirsiniz.

🔄 Migration Gerekli mi?

Evet, Migration Gerekli!

Yeni ayar grubu oluşturmak için migration dosyası gerekmez, ama benzer sistemler için gerekir:

  • ✓ Gerekli değil: Sadece seeder ile ayar grubu + ayarlar eklemek
  • ✓ Gerekli: Yeni tablo oluşturmak (örn: contact_forms tablosu)
  • ✓ Gerekli: Sistem ayarlarını veritabanı şemasına etki eden değişiklikler

Seeder + Database Sync Süreci

1. AuthRegistrationSeeder.php oluştur
2. SettingManagementDatabaseSeeder.php'de çağır
3. php artisan db:seed (veya tenants:seed)
4. Settings panel'de grup + ayarları gör
5. Kodda setting('auth_registration_...') ile kullan

🏢 Tenant-Aware Ayarlar

Multi-Tenant Yapısında Ayarlar Nasıl Çalışır?

Tenant 2 (ixtif.com) site_title = "İXTİF.com"
Tenant 1001 (muzibu.com) site_title = "Muzibu Müzik"

Aynı setting key'i farklı tenant'larda farklı değerlere sahip olabilir.

Tenant'a Özel Setting Tanımlaması

Eğer bir setting sadece belirli bir tenant'a ait olmalıysa:

  • Seeder'da: Condition ile create etmeyin (tüm tenant'lar tarafından accessible olsun)
  • Kodda: tenant() helper ile kontrol edin
  • Admin Panel'de: ValuesComponent'te tenant filtrelemesi yapın

Örnek:

// Kodda tenant-aware kontrol if (tenant() && tenant('id') == 2) { $registrationEnabled = setting('auth_registration_enabled'); }

✅ Best Practices

1. Naming Convention

✓ DOĞRU: - Prefix: auth_registration, payment_gateway, blog_ai - Key: auth_registration_enabled, payment_gateway_type - Slug: auth-registration, payment-gateway ✗ YANLIŞ: - Key: authReg (camelCase) - Key: auth-registration (Key'de dash) - Prefix: auth_registration_ (trailing underscore)

2. Seeder Organizasyonu

  • Her önemli feature için ayrı seeder oluştur (SettingManagement'de)
  • Seeder adını açıklayıcı yap: AuthRegistrationSeeder, PaymentSeeder
  • SettingManagementDatabaseSeeder'da merkezi çağırma yap
  • updateOrInsert ile idempotent yap (re-run edilebildiği gibi olsun)

3. Help Text ve Labels

  • Help text'i Türkçe ve açıklayıcı yaz
  • Örnek değer göster: "(Örn: İXTİF.com)"
  • is_required = true ise kullanıcıya uyarı ver
  • Select options'u açık yaz: "Aktif ⭐ (Önerilen)"

4. Settings Panel'de Görünüm

  • Layout'u logik gruplar halinde yapılandır (Heading, Row, Section)
  • İlişkili alanları aynı satıra (Row) koy
  • Responsive layout kullan (width: 6 = 2 column, width: 4 = 3 column)
  • Divider ile bölümler arasına ayırma koy

5. Kodda Kullanım

// DOĞRU $isEnabled = setting('auth_registration_enabled', '1'); if ($isEnabled === '1') { ... } // Daha iyi $isEnabled = setting('auth_registration_enabled') === '1'; if ($isEnabled) { ... } // Type casting ile $isEnabled = (bool) setting('auth_registration_enabled');

🐛 Sık Hatalar ve Çözümü

Hata 1: "Setting bulunamadı" (NULL döner)

Sebep: Seeder çalıştırılmamış veya key yanlış
  • Seeder'ı çalıştır: php artisan db:seed
  • Key'i kontrol et: SELECT * FROM settings WHERE key = 'xxx'
  • Default value koy: setting('key', 'default')

Hata 2: "settings_groups ID conflict"

Sebep: updateOrInsert kullanmadığında duplicate ID
  • Seeder'da updateOrInsert kullan, insert değil
  • ID'yi unique ve sequential seç
  • Mevcut gruplara bak: SELECT MAX(id) FROM settings_groups

Hata 3: "Layout JSON geçersiz"

Sebep: JSON formatında hata
  • json_encode() kullan
  • JSON validator ile test et (jsonlint.com)
  • Tırnak işaretlerine dikkat et

📌 Yeni Seeder Template

Yeni setting grubu oluşturken şu template'i kullanın:

<?php namespace Modules\SettingManagement\Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class YourFeatureSeeder extends Seeder { public function run(): void { // 1. GRUP OLUŞTUR $groupId = 20; // Yeni ID (önceki max'tan +1) $existing = DB::table('settings_groups') ->where('id', $groupId)->first(); DB::table('settings_groups')->updateOrInsert( ['id' => $groupId], [ 'name' => 'Türkçe Grup Adı', 'slug' => 'slug-adı', 'parent_id' => 1, // Hangi ana kategori altında? 'icon' => 'fas fa-icon-name', 'prefix' => 'prefix_name', 'is_active' => true, 'layout' => $this->getLayout(), 'created_at' => $existing->created_at ?? now(), 'updated_at' => now(), ] ); // 2. AYARLARI OLUŞTUR $settings = [ [ 'group_id' => $groupId, 'label' => 'Ayar Adı', 'key' => 'prefix_name_key', 'type' => 'text', // text, select, textarea, image vb. 'options' => null, 'default_value' => 'default', 'sort_order' => 1, 'is_active' => true, 'is_system' => false, 'is_required' => true, 'help_text' => 'Kullanıcıya gösterilecek yardım metni' ], ]; foreach ($settings as $setting) { $existing = DB::table('settings') ->where('key', $setting['key'])->first(); DB::table('settings')->updateOrInsert( ['key' => $setting['key']], [ 'group_id' => $setting['group_id'], 'label' => $setting['label'], 'type' => $setting['type'], 'options' => $setting['options'] ?? null, 'default_value' => $setting['default_value'], 'sort_order' => $setting['sort_order'] ?? 0, 'is_active' => $setting['is_active'] ?? true, 'is_system' => $setting['is_system'] ?? false, 'is_required' => $setting['is_required'] ?? false, 'help_text' => $setting['help_text'] ?? null, 'created_at' => $existing->created_at ?? now(), 'updated_at' => now(), ] ); } } private function getLayout(): string { $layout = [ 'title' => 'Form Başlığı', 'elements' => [ [ 'type' => 'heading', 'properties' => [ 'content' => 'Bölüm Başlığı', 'size' => 'h3', 'width' => 12, ], ], [ 'type' => 'row', 'columns' => [ [ 'width' => 6, 'elements' => [ [ 'type' => 'text', 'properties' => [ 'label' => 'Alan Adı', 'name' => 'prefix_name_key', 'setting_id' => 1, // Settings tablosundaki ID ], ], ], ], ], ], ], ]; return json_encode($layout); } }

📚 İlgili Dosyalar ve Kaynaklar

Modül Dosya Konumları

Modules/SettingManagement/ ├── app/Models/ │ ├── SettingGroup.php ← Ana grup model │ ├── Setting.php ← Ayar model │ └── SettingValue.php ← Ayar değeri model ├── database/ │ ├── migrations/ │ │ ├── 2024_12_01_000001_create_settings_groups_table.php │ │ ├── 2024_12_01_000002_create_settings_table.php │ │ ├── 2024_12_01_000003_create_settings_values_table.php │ │ └── tenant/ │ │ └── 2024_12_01_000003_create_settings_values_table.php │ └── seeders/ │ ├── SettingManagementDatabaseSeeder.php (ana seeder) │ ├── AISettingsSeeder.php (örnek) │ └── AuthRegistrationSeeder.php (oluşturacağınız) ├── app/Http/Livewire/ │ ├── ValuesComponent.php ← Ayar değerleri edit paneli │ ├── GroupManageComponent.php ← Grup yönetimi │ └── GroupListComponent.php ← Grup listesi └── routes/ └── admin.php ← Admin panel yolları Global Dosyalar: app/Services/SettingsService.php ← Ayarları okuyan service app/Helpers/Functions.php ← setting() helper

Admin Panel Erişim

URL: https://ixtif.com/admin/settingmanagement/groups Buradan: 1. Grupları görüntüle 2. "New Group" ile yeni grup oluştur (test için) 3. Grupo içinde Settings panel'de ayarları edit et 4. Admin panelin layout'unu incele