Durum Değişimi Tuzakları
Smart Tech Devs’te kurumsal, fintech veya sağlık SaaS platformları geliştirirken, tarihi bağlam mevcut durum kadar önemlidir. Standart CRUD (Create, Read, Update, Delete) mimarisi durum değişimlerine büyük ölçüde bağımlıdır. Örneğin, $user->update(['status' => 'suspended']) kodunu çalıştırıyorsunuz.
İşte mimarideki hata: O güncelleme yapıldığında, önceki durum, değişikliğin tam zaman damgası ve kim tarafından askıya alındığı gibi bilgiler sonsuza dek kaybolur. Bir denetçi, “Bu kurumsal hesap neden geçen Salı askıya alındı ve kim tarafından?” diye sorduğunda, veritabanınız cevap veremez. Kurumsal düzeyde sistemler inşa etmek için verileri geçersiz kılmayı bırakmalı ve Değiştirilemez Denetim İzleri oluşturmalısınız.
Çözüm: Sadece Ekleme Mimarisi
Mevcut durumu değiştirmek yerine, bir Denetim İzinin (Event Sourcing’in hafif bir formu) her bir değişimi değiştirilemez, sadece ekleme yapan bir günlük girişi olarak kaydetmesini sağlayabilirsiniz.
Bir kayıt değiştiğinde, model_type, model_id, causer_id (bunu kim yaptı) ve old_values ile new_values içeren bir JSON yükü saklarsınız. Bu, sisteminizde gerçekleştirilen her eylemin matematiksel olarak mükemmel, zaman damgalı bir defterini sağlar.
Denetim Trait’inin Mimarisi
spatie/laravel-activitylog gibi güçlü paketler kullanabilirsiniz, ancak temel mimariyi anlamak kritik önemdedir. Laravel’in Eloquent Model Olayları kullanarak güçlü bir kendi kendine uygulayan Trait oluşturabiliriz.
namespace App\Models\Traits;
use App\Models\AuditLog;
use Illuminate\Support\Facades\Auth;
trait HasImmutableAuditTrail
{
protected static function bootHasImmutableAuditTrail()
{
// 1. ✅ KURUMSAL PATTERN: 'updated' olay yaşam döngüsüne bağlanın
static::updated(function ($model) {
// Gerçekten değişen özellikleri çıkarın
$changes = $model->getChanges();
// Güncellemeyi zaman damgasına göre kaydetmeye gerek yok
unset($changes['updated_at']);
if (empty($changes)) {
return;
}
// Değişen anahtarlar için orijinal değerleri alın
$original = array_intersect_key($model->getOriginal(), $changes);
// 2. Değiştirilemez günlük kaydını veritabanına yazın
AuditLog::create([
'auditable_type' => get_class($model),
'auditable_id' => $model->id,
'causer_id' => Auth::id() ?? null, // Bunu kim tetikledi?
'event' => 'updated',
'old_values' => json_encode($original),
'new_values' => json_encode($changes),
'ip_address' => request()->ip(),
]);
});
// static::created() ve static::deleted() için tekrar edersiniz
}
}
Uyumu Sağlama
Artık geliştiricileriniz, bu trait’i her önemli modele (ör. Faturalar, Abonelikler, Kullanıcılar) ekleyebilir. Framework, durumsal değişiklikleri en alt seviyede yakalar ve kaydedilmeyen hiçbir durum değişikliğinin olmasını sağlamaz.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Traits\HasImmutableAuditTrail;
class Subscription extends Model
{
// Bu tek satır, bu tablonun SOC2/HIPAA uyumluluğunu garanti eder.
use HasImmutableAuditTrail;
}
Mühendislik ROI’si
Model katmanında sadece ekleme yapan bir denetim izi zorlayarak, “hayalet değişim” sorununu tamamen ortadan kaldırırsınız. Sisteminiz, kurumsal güvenlik denetimlerine doğal olarak uyumlu hale gelir, müşteri destek ekibiniz tam kullanıcı eylemlerini geriye alma ve tanı koyma yeteneği kazanır, ve controller mantığınızı karmaşıklaştırmadan kusursuz bir tarihsel defter oluşturursunuz.
Kaynak: Orijinal Makale


