feat:DB 트리거 기반 데이터 변경 추적 시스템 구현
Phase 1: DB 기반 구축 - trigger_audit_logs 테이블 (RANGE 파티셔닝 15개, 3개 인덱스) - 789개 MySQL AFTER 트리거 (263 테이블 × INSERT/UPDATE/DELETE) - SetAuditSessionVariables 미들웨어 (@sam_actor_id, @sam_session_info) Phase 2: 복구 메커니즘 - TriggerAuditLog 모델, TriggerAuditLogService, AuditRollbackService - 6개 API 엔드포인트 (index, show, stats, history, rollback-preview, rollback) - FormRequest 검증 (TriggerAuditLogIndexRequest, TriggerAuditRollbackRequest) Phase 3: 관리 도구 - v_unified_audit VIEW (APP + TRIGGER 통합, COLLATE 처리) - audit:partitions 커맨드 (파티션 추가/삭제, dry-run) - audit:triggers 커맨드 (트리거 재생성, 테이블별/전체) - 월 1회 파티션 자동 관리 스케줄러 등록 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
74
app/Models/Audit/TriggerAuditLog.php
Normal file
74
app/Models/Audit/TriggerAuditLog.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Audit;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TriggerAuditLog extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $table = 'trigger_audit_logs';
|
||||
|
||||
protected $fillable = [
|
||||
'table_name',
|
||||
'row_id',
|
||||
'dml_type',
|
||||
'old_values',
|
||||
'new_values',
|
||||
'changed_columns',
|
||||
'tenant_id',
|
||||
'actor_id',
|
||||
'session_info',
|
||||
'db_user',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'old_values' => 'array',
|
||||
'new_values' => 'array',
|
||||
'changed_columns' => 'array',
|
||||
'created_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* changed_columns에서 NULL 값 필터링
|
||||
*/
|
||||
public function getChangedColumnsAttribute($value): ?array
|
||||
{
|
||||
$decoded = is_string($value) ? json_decode($value, true) : $value;
|
||||
|
||||
if (! is_array($decoded)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array_values(array_filter($decoded, fn ($v) => $v !== null));
|
||||
}
|
||||
|
||||
/**
|
||||
* session_info JSON 디코딩
|
||||
*/
|
||||
public function getSessionInfoAttribute($value): ?array
|
||||
{
|
||||
if (is_string($value)) {
|
||||
return json_decode($value, true);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function scopeForTable($query, string $tableName)
|
||||
{
|
||||
return $query->where('table_name', $tableName);
|
||||
}
|
||||
|
||||
public function scopeForRecord($query, string $tableName, string $rowId)
|
||||
{
|
||||
return $query->where('table_name', $tableName)->where('row_id', $rowId);
|
||||
}
|
||||
|
||||
public function scopeForTenant($query, int $tenantId)
|
||||
{
|
||||
return $query->where('tenant_id', $tenantId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user