LaraFoundry, kullanılabilir bir Laravel SaaS çekirdeği, kamuya açık bir şekilde geliştiriliyor. Mevcut bir CRM’den çıkarılarak üretimde çalışıyor ve faz faz dağıtılıyor. Bu yazı, 5.3 aşamasını ele alıyor; bu aşamada yasal ve GDPR katmanı oluşturuluyor. Düzenlenebilir yasal sayfalar, çerez onayı, bir şartlar kapısı, kişisel veri dışa aktarma ve hesap silme entegre edilmiştir.
GDPR ile ilgili çalışmalar genellikle bir SaaS’ın en az sevilen kısmıdır. Genellikle sona eklenir ve bir müşterinin AB’den talep ettiği zaman ‘onay kutusu’ gibi yapılır. Ancak ben bunu ilk günden itibaren bir yapı olarak planladım ve bu şekilde inşa etmek, beklemediğim bir durumu ortaya çıkardı: erişim hakkı ve unutulma hakkı aynı yapıya sahip.
5.3 Fazında Ne Gönderildi
5.3 Fazında Ne Gönderildi
Her biri kendi gözden geçirmesi olan beş parça:
- Yasal sayfalar: veritabanında saklanan, versiyonlama ve genel bir
/legal/{slug}yoluna sahip, Şartlar, Gizlilik ve Çerez politikasını düzenlemek için bir süper-admin editörü. - Çerez onayı: varsayılan olarak kapalı bir banner, misafirler ve kimlik doğrulama kullanıcıları için bir karar kaydetmek için gerekli olan altyapı.
- Şartlar kapısı: yayımlanmış Şartlar versiyonu değiştiğinde bir kullanıcının tekrar kabul etmesini isteyen bir middleware.
- Veri dışa aktarma: uygulamanın bir kullanıcı hakkında tuttuğu her şeyin senkron JSON indirmesi.
- Hesap silme: unutulma hakkı, bir grace dönemi soft-delete ile sona ermeden önce geri dönüştürülemez bir anonimleştirme.
Dışa aktarma ve silme çifti ilgi çekici olanıdır, bu yüzden bu makalenin çoğunu oluşturuyor.
Dışa Aktarma ve Silme Aynı Yapıda
Dışa Aktarma ve Silme Aynı Yapıda
Aynı ekleyici sağlayıcı idiom’u LaraFoundry’nin her yerinde karşımıza çıkıyor. Menü, menü sağlayıcılarından, kontrol paneli ise widget sağlayıcılarından oluşturulmakta. GDPR konusunda da aynı fikri iki kez uyguladım.
Kullanıcı verilerini elinde bulunduran bir modül, onu dışa aktarmak için tek bir sözleşme uygular:
interface ExportsUserDataProvider
{
// Bu sağlayıcının belirli bir kullanıcı için dışa aktarılabilir verisi.
public function exportFor(Authenticatable $user): array;
// Bu verinin dosyalandığı benzersiz bölüm anahtarı (örneğin, 'profil', 'biletler').
public function key(): string;
public function priority(): int;
}
Ve silmek için ayna sözleşmesi:
interface PurgesUserData
{
// Bu silici tarafından sahip olunan veriyi sil veya anonimleştir. Idempotent olmalıdır.
public function purgeFor(Authenticatable $user): void;
public function key(): string;
public function priority(): int;
}
Yan yana bakın. exportFor() bir dilim döner, purgeFor() bir dilimi yok eder ve her şey diğer yönlere benziyor. Aynı imzaya sahip iki yöntem, zıt yönlere işaret eden. Çekirdek, sahip olduğu kimlikler için sağlayıcıları gönderiyor (profil, oturumlar, ayarlar, onay). Bildirimler modülü gelen kutusu için bir sağlayıcı gönderiyor. Bilet modülü biletler için bir tanesi var. Hiçbiri birbirinin varlığından haberdar değil ve hem dışa aktarma akışı hem de silme akışı tam listeyi bilmiyor.
O simetri, tüm amacın kendisidir. Daha sonra bir sipariş modülü eklediğimde, bir dışa aktarıcı ve bir silici kaydı yapıyorum ve her iki GDPR hakkı da siparişler için bir anda aktif hale geliyor. Güncellenmesi gereken tek bir merkez yok, unutulacak bir kontrol listesi de yok. Uygulama genişledikçe uyum alanı otomatik olarak büyüyor; çünkü erişim ve unutma aynı şekilde bağlanıyor.
Her iki tarafı toplayan bir kayıt:
public function exportFor(Authenticatable $user): array
{
$sections = [];
foreach ($this->sortedProviders() as $provider) {
$sections[$provider->key()] = $provider->exportFor($user);
}
return $sections;
}
Dışa aktarma uç noktası bunu bir JSON dosyası olarak akıtır ve ezilme sınırları ile sınırlıdır. Silme kaydı ayni şekilde çalışır.
Silme, bir Grace Dönemi, DELETE Değil
Silme, bir Grace Dönemi, DELETE Değil
Hesabınızdaki bir satırı silmek, bir user_deleted_at zaman damgası ayarlamak, sizi oturumdan çıkarmak ve her yerde gizlemek anlamına gelir. Bu, geri alınabilir bir soft-delete’idir ve bir zaman başlatır. Bir süper-admin, bu süre içinde sizi geri yükleyebilir; bu, Salı günü pişman olduğunuz bir öfkeyle ilgili bir ayrılma ile kalıcı bir kaybın arasındaki farktır.
Gerçek silme, daha sonra bir günlük cron üzerinden gerçekleşir:
$model::query()
->whereNotNull('user_deleted_at')
->whereNull('user_purged_at')
->where('user_deleted_at', '<'now()->subDays($graceDays))
->chunkById(100, function ($users) use ($registry): void {
foreach ($users as $user) {
DB::transaction(function () use ($registry, $user): void {
$registry->purge($user);
$user->forceFill(['user_purged_at' => now()])->save();
});
}
});
Burada üç şey önemlidir.
Anonimleştirir, satırı zorla silmez. Temel silici, ismi boş bırakır, e-postayı ulaşılmaz bir hesaba yeniden yazar, şifreyi, iki faktörlü sırları, OAuth belirteçlerini iptal eder ve oturumları ve kişisel erişim belirteçlerini kaldırır. Satır, kimliksiz kalır. Bu, yabancı anahtarların bütünlüğünü korur ve hayatta kalması gereken yasal kayıtların (faturalar gibi) anonimleştirilmiş bir kimlikle ilişkili kalmasına olanak tanır.
Idempotent’dir. Temizlenmiş bir hesap, user_purged_at ile damgalanır ve kalıcı olarak sorgudan çıkarılır. Temizleme, yarıda kalmışsa, damgasız kalır ve bir sonraki çalıştırmada yeniden denenir; her temizleyicinin, iki kez çalıştırmaya güvenli olacak şekilde yazıldığı için yeniden deneme sadece işi tamamlar.
Ve her sağlayıcı silme ile anonimleştirme konusunda kendisi karar verir. Kullanıcıya ait kişisel veriler tamamen silinir. Hayatta kalması gereken kayıtlar anonimleştirilir ve saklanır. Sözleşme herkese tek bir politika uygulamaz.
İsteği İle Silmediğim Tek Şey
İsteği İle Silmediğim Tek Şey
Etkinlik kaydı.
Bir silme sırasında kullanıcının her izini temizlemek düzenli olurdu. Ancak bu, yanlış bir hamle olurdu. Ne olduğu ve bir silmenin gerçekleştirildiğine dair kanıt olarak tam şekilde kalması gereken denetim kaydı, talebi yerine getirdiğinizi göstermek için gereken kanıt. Kimliği her yerde anonimleştirirken, hareketler kaydı güvende kalır. Kimi anonimleştir, ne olduğunu tut; bu, belirlenen sınırdır ve bir karar süreciydi, dikkatsizlik değil.
Yasal Sayfalar, Şartlar Kapısı ve Sakin Kalan Bir Banner
Yasal Sayfalar, Şartlar Kapısı ve Sakin Kalan Bir Banner
Yasal sayfalar, önceki bir aşamadan tekrar kullanılmaktadır. Admin konsolunda düzenlenir, dizi şeklinde veritabanında saklanır ve e-posta şablon editörü tarafından kullanılan aynı HTML temizleyici aracılığıyla işlenir, böylece saklanan bir yasal sayfa halka açık bir sayfaya script sokamaz. Her kaydetme, bir versiyonu artırır.
Bu versiyon, Şartlar kapısını besler. Bir middleware’dır ve önemli olan özellik, fail-open (açıkta kalması) olmasıdır. Yalnızca yayımlanan bir Şartlar sayfası ile açık bir versiyon olduğunda yeniden kabul talep eder. Bunun dışında hiçbir şey yapmaz. Henüz mevcut olmayan bir Şartlar sayfasına bir yönlendirme döngüsüne girmesi söz konusu değildir ve yenilikler, yapılandırılmamış hiçbir özelliğe tutsak edilmeyecektir. Yayınladığınızda ve daha sonra versiyonu artırdığınızda, her oturum açmış kullanıcı bir kez daha onay talep edilir ve daha sonra tam olarak nereye devam ediyorlarsa oradan devam ederler.
Çerez banner’ı sessizce kapalıdır. Temel çerezleri (oturum, CSRF, dil, görünüm değiştirme) ayarlayan yalnızca çekirdek vardır ve GDPR gereği onay gerektirmez. Dolayısıyla, yalnızca kendiniz analitik veya pazarlama çerezleri eklediğiniz zaman bir soruyla karşılaşacaksınız. Banner, kayıtlı karar ve onay durumu tümü bağlıdır; yalnızca bir yapılandırma bayrağını açmanız yeterlidir. Karakter üzerinde hiçbir karanlık desen yok; çerezleriniz olmadığında hiç kimseyi rahatsız etmiyoruz.
Testler, Çünki Bu Kanıttır
Testler, Çünki Bu Kanıttır
Her aşama, yeşil testleri ve bir karşıt gözden geçirme aşaması ile birlikte gönderilir. 5.3 aşaması, Pest ile 743 arka uç testi ve 164 ön yüz testi toplamına ulaştı. Sonra bütün katman, ana uygulamaya entegre edildi ve kendi entegrasyon testi ile kaplandı: yayımlanan bir yasal sayfa kamuya açık, Şartlar kapısı, gerçek bir rotada bir geçersiz kullanıcının yönlendirilmesini sağlıyor, kayıt, yalnızca Şartlar yayımlandığında onay kutusunu gerektirir, erime cron’u grace penceresinin ötesinde anonimleştirir ve onay durumu ön tarafa ulaşır.
GDPR, “bitti gibi görünmek” ve “doğru” arasındaki uç nokta olduğu için burada testler süs değil; bir kontrol kutusu ile bir özellik arasında belirleyici bir farktadır.
Ücretsiz Çekirdek Ücretsiz Kalır
Ücretsiz Çekirdek Ücretsiz Kalır
LaraFoundry’nin çekirdeği açıktır. Bu yazıda yer alan her şey, paket içerisinde, kesitler dahil mevcuttur. Hedef, ayrılma muayene ücreti olarak kendini finanse eden ayrı bir ücretli eklentiyi içerecek şekilde, tamamen ücretsiz bir çekirdek yapımını sağlamaktadır; temel yapı taşları ücretli hale getirilmez bu nedenle. GDPR temelleri, en temel şeylerden biridir ve bu nedenle uygun bir yere yerleştirilmiştir.
Takipte Kal
Takipte Kal
Kaynak: Orijinal Makale


