AB’de kişisel verileri (isimler, e-postalar, telefon numaraları, adresler) yönetmek için bir CRM inşa etmek, GDPR’yi bir kenara atmanın mümkün olmadığını gösteriyor. Biz, Laravel 12 ile geliştirdiğimiz çok kiracılı CRM’miz WB-CRM’de bunu nasıl uyguladık.
1. Database-per-Tenant Mimarisi
1. Database-per-Tenant Mimarisi
Her bir kiracıya kendi MySQL veritabanı (tenant_acme, tenant_demo, vb.) tahsis eden stancl/tenancy v3 kullanıyoruz.
// Merkez modellerinin bağlantıları açıkça ayarlandı
protected $connection = 'central';
// Kiracı modeller merkezi bir geçişe bağlı — $connection özelliği yok
// stancl/tenancy varsayılan bağlantıyı otomatik olarak değiştirir
Neden paylaşımlı veritabanı ve satır seviyesinde güvenlik değil?
Paylaşımlı bir veritabanında, eksik bir WHERE tenant_id = ? koşulu, verilerin şirketler arasında sızmasına sebep olur. DB-per-tenant yapısında bu mimari olarak imkansızdır.
2. PII için Alan Seviyesi Şifreleme
2. PII için Alan Seviyesi Şifreleme
Laravel’in encrypted tipi, bireysel veritabanı alanlarını AES-256 ile şifreler:
protected function casts(): array
{
return [
'name' => 'encrypted',
'email' => 'encrypted',
'phone' => 'encrypted',
'address' => 'encrypted',
'ip_address' => 'encrypted',
];
}
Bu durumun dezavantajı: Şifreli alanları WHERE email = ? ile sorgulamak mümkün değildir. Bunu, eşlik eden hash sütunları ile çözüyoruz:
// email_hash, arama yapmak için HMAC-SHA256 hashini saklar
$contact = Contact::where('email_hash', hash_hmac(, $email, config()))->first();
3. GDPR Veri Sahibi Hakları
3. GDPR Veri Sahibi Hakları
15-21. maddeler sadece onay kutuları değildir — gerçek uç noktalar gerektirir:
| Hak | Madde | Uygulama |
|---|---|---|
| Erişim | Madde 15 | JSON/CSV dışa aktarma uç noktası ile yeniden kimlik doğrulama |
| Düzeltme | Madde 16 | Profil düzenleme işlevi |
| Silme | Madde 17 | Hesap silme + veri tabanı temizliği |
| Kısıtlama | Madde 18 | Hesap dondurma (silmeden devre dışı bırak) |
| Taşınabilirlik | Madde 20 | Makine tarafından okunur dışa aktarma (JSON) |
| İtiraz | Madde 21 | Pazarlama opt-out |
Her GDPR işlemi, kim, ne zaman, hangi kiracı, eski değerler, yeni değerler ile birlikte bir denetim kaydı oluşturur.
4. Denetim Kaydı
4. Denetim Kaydı
Her durum değiştiren işlem bir denetim kaydı oluşturur. Bu, GDPR Madde 30 (işlem kayıtlarının) için zorunludur:
TenantAuditLog::create([
'uuid' => Str::uuid(),
'auditable_type' => get_class($model),
'auditable_id' => (string) $model->uuid,
'event' => 'gdpr_data_export',
'old_values' => null,
'new_values' => [=> ,
=> $exportedFields],
'user_type' => TenantUser::class,
'user_id' => $tenantUser->id,
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
]);
5. Keşke Daha Önce Bilseydim
5. Keşke Daha Önce Bilseydim
- Herd/CLI bcrypt uyumsuzluğu: CLI PHP ve Herd PHP macOS’ta uyumsuz bcrypt hashleri üretir. Şifreleri her zaman web bağlamında ayarlayın.
- Oturum bağlantısı
centralolmalıdır: Database-per-tenant yapısında, kiracı DB’sinde saklanan oturumlar kiracı değiştirildiğinde kaybolur. - ENUM sütunları migration’larda tehlikelidir: Bir değer eklemek, MySQL’de sütunun yeniden oluşturulmasını gerektirir. Bunun yerine, doğrulama ile string sütunları kullanın.
-
getCustomColumns()stancl/tenancy’de: Kiracı tablosuna bir sütun eklediğinizde ancakgetCustomColumns()içinde kaydetmeyi unuttuysanız, bu sütun sessizce JSONdatasütununa düşer. Saatlerce hata ayıklamanıza neden olabilir.
Bu prensiplerle WB-CRM‘i geliştirdik. Ücretsiz bir ONE plan mevcut (500 kişi, 1 kullanıcı). Almanya’da inşa edildi ve barındırılıyor.
Kaynak: Orijinal Makale


