Web Projelerinde Ayarlar Tablosu Nasıl Tasarlanır?
Bir web projesinin ayarları büyüdükçe “site adı” ile “ödeme sağlayıcısının gizli anahtarı”nı aynı yerde tutmanın doğru olmadığı ortaya çıkar. Yönetici panelinden değişebilen tercihler, dağıtım sırasında verilen yapılandırma ve gizli bilgiler farklı yaşam döngülerine sahiptir. Bu rehber, ayarlar tablosunu seçmekten PHP ile güvenli bir güncelleme akışı kurmaya kadar kararları somut örneklerle ele alır. Örnek şema MySQL tarzı SQL ve PDO içindir; başka veritabanlarında veri türü ve söz dizimini uyarlamak gerekir.
Ayarlar tablosu ne işe yarar?
Ayarlar tablosu, uygulamanın davranışını etkileyen ve yetkili kullanıcıların zaman içinde değiştirebildiği değerleri kalıcı tutar. Örneğin bakım modu, varsayılan dil, bildirim tercihi veya herkese açık site adı buraya adaydır. Bir ayarın varlığı tek başına tablo gerektirmez: kodla birlikte sürümlenen, nadiren değişen bir sabit yapılandırma dosyasında kalabilir. Böylece uygulama açılışında kritik bir değeri her istekte veritabanından okumak zorunda kalmaz.
İyi bir tasarım yalnızca anahtar ve değer sütunlarından ibaret değildir. Her ayarın sahibi, kapsamı, beklenen türü, izin verilen aralığı, varsayılanı, kim tarafından değiştirilebileceği ve nasıl geri alınacağı da tanımlanmalıdır. Bunlar belirsizse tablo esnek görünür; fakat yanlış türler, tenantlar arasında veri sızıntısı ve sessizce eskiyen önbellek üretir. Önce ayar envanteri çıkarıp sonra şemayı seçmek, sonraki migrasyon maliyetini düşürür.
Hangi veriyi veritabanında tutmalı?
Karar için üç soru sorun: Değer yönetim arayüzünden değiştirilecek mi? Değişiklik kod dağıtmadan etkili olmalı mı? Her müşteri, ekip veya site için farklı olmalı mı? Bu sorulardan biri evetse veritabanı güçlü bir adaydır. Örneğin çok kiracılı bir içerik platformunda her sitenin logo tercihi veya e-posta bildirim ayarı ayrı bir kayıt olabilir. Uygulama sürümüyle birlikte değişen teknik sabitlerin ise kod deposundaki yapılandırmada kalması daha anlaşılırdır.
Parolaları, imzalama anahtarlarını ve API gizli anahtarlarını sıradan bir settings tablosunda düz metin saklamayın. Erişim denetimi ve rotasyon gerektiren sırlar için uygun sır yöneticisini, en az yetkiyi ve kullanım kaydını değerlendirin. Ortam değişkenleri bazı dağıtımlarda pratik olsa da süreç dökümleri ve günlükler üzerinden sızma riski taşır. Yönetim panelinde böyle bir sır değiştirilmek zorundaysa değer yalnızca yetkili sunucu akışından geçmeli; okunurken maskeleme ve kayıt sırasında şifreleme/anahtar yönetimi ayrıca tasarlanmalıdır. OWASP, sırların yaşam döngüsünü ayrı ele alır.
Sabit sütunlar, anahtar değer ve JSON nasıl seçilir?
Üç yaygın modelin farklı güçlü yanları vardır. Az sayıda, uzun ömürlü ve türü sabit ayar için site_settings(site_id, site_name, timezone, maintenance_enabled) gibi açık sütunlar kullanabilirsiniz. Veritabanı türleri, boş değer kısıtları ve indeksler görünür olur. Buna karşılık yeni ayar eklemek çoğunlukla migrasyon gerektirir. Bu, değişikliklerin kontrollü olduğu sistemlerde kusur değil, beklenen disiplin olabilir.
Eklentilerin ya da modüllerin sık yeni ayar eklediği projede (scope_type, scope_id, setting_key, value_json) biçimindeki anahtar değer modeli esnektir. Ancak tür doğrulaması uygulamaya taşınır. Anahtarların sınırsız serbest metin olması yazım hatalarıyla kopya ayar üretir. Tanımlı anahtar kayıt defteri, benzersiz birleşik indeks ve sunucu tarafı doğrulama gerekir. JSON sütunu, birlikte okunan küçük bir ayar grubunu saklayabilir; tek tek sorgulanan veya ayrı yetki gerektiren ayarlar tek büyük JSON belgesine gömülmemelidir.
Karışık yaklaşım çoğu uygulamada iyi işler: temel kimlik ve sık filtrelenen alanlar açık sütunlarda; modüle özgü, seyrek değişen tercihler anahtar değer tablosunda bulunur. Tasarım kararı için “en esnek olan”ı değil, ayarların gerçek değişim sıklığını, okuma örüntüsünü ve veri bütünlüğü ihtiyacını esas alın. Aşağıdaki görsel sabit sütunlu ve anahtar değerli yaklaşımın temel farkını gösterir.

Örnek tablo şeması ve bütünlük kuralları
Birden çok siteyi yöneten örnek uygulamada kapsamı açıkça kaydedelim. Global ayar için scope_type='global' ve scope_id=0; siteye özel ayar için scope_type='site' ve gerçek site kimliği kullanılır. Bu kural uygulamanın her yerinde aynı uygulanmalıdır. value_json alanını metin olarak saklayan örnekte JSON geçerliliği PHP tarafında denetlenir; kullanılan veritabanı sürümü uygun bir JSON veri türü sunuyorsa onun kısıtlarından da yararlanılabilir.
CREATE TABLE app_settings (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
scope_type VARCHAR(20) NOT NULL,
scope_id BIGINT UNSIGNED NOT NULL,
setting_key VARCHAR(100) NOT NULL,
value_json LONGTEXT NOT NULL,
version INT UNSIGNED NOT NULL DEFAULT 1,
updated_by BIGINT UNSIGNED NULL,
updated_at DATETIME NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_setting_scope (scope_type, scope_id, setting_key)
); Birleşik benzersiz indeks aynı kapsamda aynı anahtarın iki kez oluşmasını engeller. updated_by alanı hızlı inceleme sağlar; ayrıntılı geçmiş için ayrıca denetim tablosu gerekir. version eşzamanlı değişiklikleri yakalamak içindir. Veri tabanı düzeyinde uygun yabancı anahtarlar ve silme davranışı, uygulamanın kullanıcı ve site modeli bilindikten sonra eklenmelidir. Global ve site kapsamını aynı tabloda tutmak zorunlu değildir; kapsam sayısı azsa ayrı tablolar sorguları daha okunur kılabilir.
Her ayar için tanım sözlüğü oluşturun
Veritabanındaki kayıt yalnızca mevcut değeri temsil etsin; ayarın kuralları uygulamada açık bir sözlükte dursun. Örneğin maintenance_mode boolean, items_per_page 1 ile 100 arasında tamsayı, default_locale izinli dillerden biri olabilir. Tanımda varsayılan değer, değiştirilebilen kapsam, hassasiyet, yönetim arayüzündeki açıklama ve gerekli yetki de yer almalıdır. Böylece yanlış anahtarın sessizce eklenmesi ve bir ayarın farklı ekranlarda farklı yorumlanması önlenir.
Basit bir PHP dizisi bile başlangıç için yeterlidir: 'items_per_page' => ['type' => 'integer', 'min' => 1, 'max' => 100, 'default' => 20]. Okuma ve yazma aynı tanımı kullanmalıdır. Bilinmeyen anahtarları varsayılan olarak reddedin. Arayüzdeki seçim listesini bu sözlükten üretebilirsiniz; fakat tarayıcıdaki kısıtların sunucu denetiminin yerini almadığını unutmayın. Yeni ayar eklendiğinde tanım, yönetim formu, test ve gerekirse migrasyon tek değişiklik paketi olarak gözden geçirilmelidir.
Ayarları okurken varsayılan ve kapsam önceliği
Okuma akışında önce talep edilen sitenin ayarını arayıp yoksa global değere, o da yoksa uygulama tanımındaki varsayılana geçebilirsiniz. Bu sıralama belgelendiğinde bir yöneticinin “ayar neden değişmedi?” sorusu yanıtlanabilir. Bazı ayarlar için globalden miras alınması doğru değildir; örneğin yasal bildirim veya müşteri gizlilik tercihi için açık bir değer zorunlu olabilir. Bu nedenle miras davranışı da anahtar bazında tanımlanmalıdır.
Yok kaydı ile JSON null değerini eşitlemeyin. “Kayıt bulunamadı”, “miras al” ve “bilerek boşaltıldı” farklı durumlar olabilir. Özellikle çok kiracılı uygulamalarda bir sitenin kaydını sorgularken hem scope_type hem scope_id koşulunu kullanın. Kullanıcının erişebileceği site kimliğini yalnızca form alanından almak güvenli değildir. İstek bağlamı, oturum ve sunucu tarafındaki üyelik kaydı birlikte doğrulanmalıdır.
Güvenli güncelleme akışı: yetki, doğrulama, kayıt
Ayar değiştirme isteğini bir işlem hattı olarak düşünün. Önce kullanıcının oturumunu ve ilgili kapsamdaki yetkisini denetleyin. Sonra istenen anahtarın sözlükte bulunduğunu ve o kapsamda yazılabildiğini doğrulayın. Değeri beklenen türe dönüştürürken belirsiz dönüşümlerden kaçının: "false" metnini PHP’de doğrudan boolean’a çevirmek istenmeyen sonuç verebilir. Sayısal aralık, uzunluk, izinli seçenek ve URL biçimi gibi kuralları alanın anlamına göre kontrol edin. Son aşamada hazırlanan sorguyla kaydedin ve sonucu gözlemleyin.
PDO hazırlanan sorgularda parametreler veri değerlerine bağlanır; tablo adı, sütun adı ya da SQL anahtar sözcüğü için parametre kullanılamaz. Bu yüzden setting_key bilinen değerlerden seçilmeli ve SQL şablonu sunucu kodunda sabit kalmalıdır. PHP belgeleri parametre bağlamanın SQL enjeksiyonunu önlemede rolünü açıklar. Hazırlanmış sorgu tek başına yetkilendirme, CSRF koruması, doğrulama veya doğru tenant seçimi sağlamaz; bunlar ayrı kontrollerdir.
// $pdo: PDO; $siteId ve $actorId sunucuda doğrulanmış kimlikler.
// $key sözlükte izin verilen anahtarlardan biri; $value doğrulanmış değer.
$json = json_encode($value, JSON_THROW_ON_ERROR);
$stmt = $pdo->prepare(
'UPDATE app_settings
SET value_json = :value, version = version + 1,
updated_by = :actor, updated_at = CURRENT_TIMESTAMP
WHERE scope_type = :scope AND scope_id = :scope_id
AND setting_key = :setting_key AND version = :expected_version'
);
$stmt->execute([
':value' => $json,
':actor' => $actorId,
':scope' => 'site',
':scope_id' => $siteId,
':setting_key' => $key,
':expected_version' => $expectedVersion,
]);
if ($stmt->rowCount() !== 1) {
throw new RuntimeException('Ayar değişti veya bulunamadı; yeniden yükleyin.');
} Bu örnek var olan tek kaydı günceller; ilk kayıt ekleme yolunu ayrıca tasarlayın. rowCount() sonucu sıfırsa kaydın bulunmaması ile sürüm çakışması ayırt edilmeden kullanıcıya yeniden yükleme önerilir; daha ayrıntılı hata mesajı için yetkili bir yeniden okuma yapılabilir. Bazı veritabanı sürücülerinde etkilenen satır semantiği değişebilir; sürümün her başarılı güncellemede artması bu örneği belirgin kılar. Hata veya ağ kesintisi senaryoları için işlemin tekrar edilip edilmeyeceği ürün kararına bağlıdır.
Eşzamanlı düzenlemelerde sürüm numarası
İki yönetici aynı formu açtığında son kaydedenin ilk değişikliği görünmeden ezmesi yaygın bir sorundur. Form açılırken mevcut version değerini gönderin; kaydederken SQL koşulunda beklenen sürümü karşılaştırın. Eşleşirse sürümü artırın. Eşleşmezse arayüzde yeni değeri gösterip kullanıcının karşılaştırarak yeniden denemesini isteyin. Bu yönteme iyimser eşzamanlılık denetimi denir; kısa süreli yönetim işlemleri için çoğu zaman uzun veritabanı kilidinden daha kullanışlıdır.
Sürüm denetimi yalnızca aynı kaydın üzerine yazılmasını yönetir. Birbiriyle ilişkili iki ayarın birlikte geçerli olması gerekiyorsa ikisini tek işlem içinde doğrulayıp kaydetmek gerekir. Örneğin bir e-posta sağlayıcısını etkinleştirme anahtarı ile gönderici adresi ayrı kaydediliyorsa ara durumda sistem geçersiz kalabilir. Böyle durumlarda birlikte doğrulanan bir ayar grubu veya tek belge daha uygun olabilir. İşlem sınırı iş kuralından çıkarılmalıdır.
Denetim kaydı ve geri alma planı
updated_by son yazanı söyler, geçmişi anlatmaz. Kritik ayarlar için ayrı bir setting_audit tablosunda kapsam, anahtar, önceki ve sonraki değer özeti, aktör, zaman, istek kimliği ve işlem nedeni tutulabilir. Denetim kaydına parola veya API anahtarının eski ve yeni düz metin değerini yazmayın; hassas alanlarda değer yerine “değiştirildi” bilgisi yeterli olabilir. Kişisel veri saklama süresi ve erişim yetkisi ayrıca belirlenmelidir.
Değişiklik ile denetim satırını aynı veritabanı işleminde kaydetmek, ayarın değişip kaydının kaybolması riskini azaltır. Kayıt başarısızsa işlem geri alınmalıdır. Harici bir günlük sistemine de olay gönderiliyorsa doğrudan ağ çağrısını işlemin içine koymak gecikme ve kısmi başarısızlık yaratabilir; güvenilir bir olay kuyruğu veya outbox yaklaşımı değerlendirilebilir. Bu karar sistemin ölçeğine bağlıdır. Site içinde etkinlik geçmişi tasarlamak için Activity Log sistemi rehberine de bakabilirsiniz.
Geri alma düğmesi koymadan önce “geri almak” ne demek netleştirin. Eski değeri otomatik yazmak, arada yapılmış yeni bir değişikliği ezebilir. Geri alma da yeni bir sürüm ve yeni bir denetim olayı olmalıdır. Önce kullanıcının yetkisini ve mevcut sürümü kontrol edin; ardından hedef değeri bugünkü doğrulama kurallarına göre tekrar inceleyin. Artık desteklenmeyen eski ayarları zorla geri getirmek uygulamayı bozabilir.
Önbellek ne zaman temizlenir?
Ayarlar sık okunup seyrek değiştiğinde önbellek yararlıdır. Önbellek anahtarı kapsamı içermelidir; yalnızca maintenance_mode kullanmak farklı sitelerin değerlerini karıştırabilir. Örneğin settings:site:42 gibi bir anahtar seçin. Yazma işlemi başarıyla tamamlandıktan sonra ilgili anahtarı geçersiz kılın. İşlem geri alınırsa önbelleği temizlemiş olmak çoğunlukla yalnızca ek bir okuma maliyeti yaratır; fakat yanlış değeri önbelleğe yazmak daha ciddi bir tutarsızlıktır.
Çok sunuculu bir sistemde her makinenin bellek içi önbelleği varsa yalnızca güncelleme yapan sunucuyu temizlemek yetmez. Ortak bir önbellek, kısa TTL veya olay yayını gerekebilir. Kritik ayarlar için “en fazla kaç saniye eski değer kabul edilir?” sorusunu ürün ve operasyon ekipleriyle yanıtlayın. Örneğin arayüz rengi için dakikalar kabul edilebilirken güvenlik davranışını etkileyen bir ayarın gecikmeli yayılması uygun olmayabilir. Önbellek stratejisi, ayarın önemine göre değişmelidir.

Çok kiracılı projelerde sınırları koruyun
Bir SaaS ürününde aynı ayar anahtarı farklı müşteriler için bulunabilir. Her okumada ve yazmada tenant kimliğinin koşula girmesi gerekir. Ön yüzde bir tenant seçici olması sunucu yetkisi sayılmaz. Kullanıcının seçilen tenantla ilişkisini, işlem yapma rolünü ve ilgili ayarın o tenantta değiştirilebilir olup olmadığını ayrı denetleyin. OWASP, yetkiyi varsayılan olarak reddetmeyi ve her istekte doğrulamayı önerir.
Global ayarların site ayarını geçersiz kılıp kılmadığı açık olmalıdır. Bazı durumlarda global değer yalnızca varsayılandır; bazılarında merkezî politika nedeniyle her tenant için zorunludur. Bu farkı bir locked veya politika kavramıyla temsil etmek gerekebilir. Uygulama, “siteye özel değer var” diye merkezî güvenlik sınırını aşmamalıdır. Testlerde başka tenant kimliğiyle okuma ve yazma denemeleri bulunmalı; yalnızca mutlu yol testleri yeterli değildir.
Taşıma, sürüm yükseltme ve varsayılanlar
Yeni bir ayar eklendiğinde iki yol vardır: kaydı migrasyonla önceden eklemek veya okurken kodda tanımlı varsayılana dönmek. Önceden ekleme, raporlama ve yönetim ekranında açık kayıt göstermeyi kolaylaştırır. Kod varsayılanı ise eski kurulumlarda eksik kayıt yüzünden hata çıkmasını önler. Hangisi seçilirse seçilsin aynı anahtarın birden çok sürümde ne anlama geldiği belgelenmelidir. Varsayılanı değiştirmek, mevcut kaydı olan kullanıcıları otomatik değiştirmeyebilir.
İsim değiştirme veya değer biçimini dönüştürme gerektiğinde aşamalı migrasyon planlayın. Önce yeni okuyucunun eski biçimi tanıması, sonra verinin dönüştürülmesi, ardından eski biçimin kaldırılması kesintisiz dağıtım için güvenlidir. Uzun yaşayan uygulamalarda “eski ayar satırları ne zaman temizlenir?” sorusu da önemlidir. Silmeden önce kullanım araması, yedek ve geri dönüş planı yapılmalıdır. PHP tabanlı projede tema ve modül seçeneklerini düzenleme yaklaşımı için PHP tema sistemi yazısı yardımcı olabilir.
Yönetim panelinde anlaşılır deneyim
Formdaki açıklamalar teknik sütun adlarını tekrar etmemelidir. “Bakım modu” seçeneği için hangi ziyaretçilerin ne göreceğini, değişikliğin ne zaman etkili olacağını ve geri alma yolunu yazın. Tehlikeli işlemlerde uygun bir uyarı gösterin. Kaydın başarılı olduğunu bildirin; sürüm çakışmasında kullanıcının girdiği değeri kaybetmeyin. Her ayarı aynı ekrana doldurmak yerine konuya göre gruplandırın. Bu düzenleme, yanlış seçeneği değiştirme olasılığını azaltır.
Görünürlük ile yetki farklıdır: menüyü saklamak hassas güncelleme uç noktasını korumaz. Sunucu tarafı denetimi hem klasik form isteğinde hem API çağrısında çalışmalıdır. Form tabanlı oturumlarda CSRF koruması ekleyin; API’de kimlik doğrulama ve yetkilendirme tasarımını tutarlı yürütün. Kritik bir ayarın değişmesi için yeniden kimlik doğrulama veya ikinci onay gerekip gerekmediğini iş etkisine göre belirleyin. Bu gereklilik her ayara aynı sertlikle uygulanmak zorunda değildir.
Yayına almadan önce kontrol listesi
- Her ayar için anahtar, tür, kapsam, varsayılan, açıklama ve gerekli yetki tanımlı mı?
- Aynı kapsam ve anahtar için benzersiz veritabanı kısıtı var mı?
- Gizli bilgiler normal ayar tablosundan ve denetim günlüklerinden ayrıldı mı?
- Okuma ve yazma sorguları doğrulanmış tenant kimliğini kullanıyor mu?
- Sunucu tarafında izinli değer, uzunluk, aralık ve iş kuralı denetleniyor mu?
- Eşzamanlı güncellemede sürüm çakışması kullanıcıya gösteriliyor mu?
- İlgili önbellek, başarılı kayıt sonrasında doğru kapsam için geçersiz kılınıyor mu?
- Yeni sürümün migrasyonu, eski verisi ve geri dönüşü denendi mi?
Bu listeyi örnek birkaç ayar üzerinde uygulayın: kolay bir görünüm tercihi, tenant bazlı bir seçenek ve operasyonel etkisi yüksek bir ayar. Üçünün farklı gereksinimleri şemanızın sınırlarını açığa çıkarır. Yük testinde ayar okumalarının sorgu sayısını ve önbellek isabetini izleyin. Güvenlik testinde yetkisiz kullanıcı, başka tenant, bilinmeyen anahtar, hatalı JSON ve eski sürüm numarası senaryolarını deneyin. Bir tasarımın güvenilirliği yalnızca normal akışta çalışmasıyla ölçülmez.
Sık sorulan sorular
Tek bir JSON sütunu yeterli mi?
Küçük, birlikte okunan ve birlikte güncellenen bir ayar grubu için yeterli olabilir. Fakat ayrı yetkiler, bağımsız denetim kayıtları ve farklı güncelleme sıklıkları varsa büyük JSON belgesi gereksiz çakışma yaratır. Arama ve raporlama gerektiren alanları da tamamen JSON içine saklamak yerine açık sütun olarak değerlendirin.
Eksik ayarı otomatik oluşturmalı mıyım?
Okuma sırasında her eksik ayarı otomatik yazmak, yanlış yazılmış anahtarları kalıcı kayda dönüştürebilir. Önce bilinen anahtar sözlüğüne bakın. Eksik değer için tanımlı varsayılana dönmek veya kontrollü migrasyonla satır eklemek daha izlenebilir seçeneklerdir. Hangi yolu kullandığınızı testlerde sabitleyin.
Ayar tablosuna API anahtarı koyabilir miyim?
Düz metin ve geniş erişimli genel ayar tablosu doğru yer değildir. Yönetilen sır deposu, erişim sınırı, rotasyon ve denetim gereksinimlerini değerlendirin. Ürünün gereği olarak veritabanında tutulacaksa güçlü şifreleme ve ayrı anahtar yönetimi gerekir; yönetim ekranı değeri tekrar açıkça göstermemelidir.
Önbellek kullanmak zorunlu mu?
Hayır. Küçük ve düşük trafikli uygulamada indeksli bir sorgu yeterli olabilir. Önce ölçüm yapın. Önbellek ekliyorsanız kapsamı, TTL’yi, temizleme anını ve çok sunuculu davranışı açıkça tasarlayın; aksi halde performans kazanımı karşılığında beklenmedik eski değerler görebilirsiniz.
Sonuç
Ayarlar tablosu tasarımının merkezinde “değeri nerede saklayacağım?” sorusundan çok “kim, hangi kapsamda, hangi kurallarla değiştirebilir?” sorusu vardır. Sabit sütun, anahtar değer ve JSON arasında seçim yaparken değişim sıklığı ile veri bütünlüğünü karşılaştırın. Yetki, doğrulama, sürüm denetimi, denetim izi ve önbellek yaşam döngüsünü ilk tasarıma dahil edin. Küçük bir ayar sözlüğü ve açık varsayılanlar, ileride büyüyen projeyi anlaşılır tutar.




