Files
sam-manage/resources/views/trigger-audit/show.blade.php
권혁성 0316c63d3c feat:DB 트리거 감사 로그 관리 화면 구현
- TriggerAuditLog 모델 (casts, accessors, scopes)
- TriggerAuditController (목록/상세/이력/롤백 미리보기/롤백 실행)
- index: 대시보드 통계 + 필터 + 목록 + 파티션 현황
- show: old/new diff 뷰 (변경 컬럼 하이라이트)
- history: 레코드별 변경 타임라인
- rollback-preview: SQL 미리보기 + 확인 후 실행
- 라우트 5개 등록, 메뉴 시더 (시스템 관리 > DB 변경 추적)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 08:55:18 +09:00

123 lines
5.5 KiB
PHP

@extends('layouts.app')
@section('title', '감사 로그 상세 #' . $log->id)
@section('content')
<div class="flex justify-between items-center mb-6">
<div>
<h1 class="text-2xl font-bold text-gray-800">감사 로그 상세 #{{ $log->id }}</h1>
<p class="text-sm text-gray-500 mt-1">{{ $log->table_name }} / Row {{ $log->row_id }}</p>
</div>
<div class="flex gap-2">
<a href="{{ route('trigger-audit.history', [$log->table_name, $log->row_id]) }}"
class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg text-sm"> 레코드 전체 이력</a>
<a href="{{ route('trigger-audit.rollback-preview', $log->id) }}"
class="bg-orange-500 hover:bg-orange-600 text-white px-4 py-2 rounded-lg text-sm">롤백 미리보기</a>
<a href="{{ route('trigger-audit.index') }}"
class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg text-sm">목록</a>
</div>
</div>
@if(session('success'))
<div class="bg-green-100 text-green-700 px-4 py-3 rounded-lg mb-6">{{ session('success') }}</div>
@endif
<!-- 기본 정보 -->
<div class="bg-white rounded-lg shadow-sm p-4 mb-6">
<h3 class="text-sm font-semibold text-gray-700 mb-3">기본 정보</h3>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
<div>
<span class="text-gray-500">DML 타입</span>
<div class="mt-1">
<span class="px-2 py-1 rounded text-xs font-medium
{{ $log->dml_type === 'INSERT' ? 'bg-green-100 text-green-700' : '' }}
{{ $log->dml_type === 'UPDATE' ? 'bg-yellow-100 text-yellow-700' : '' }}
{{ $log->dml_type === 'DELETE' ? 'bg-red-100 text-red-700' : '' }}">
{{ $log->dml_type }}
</span>
</div>
</div>
<div>
<span class="text-gray-500">테넌트 ID</span>
<div class="mt-1 font-medium">{{ $log->tenant_id ?? '-' }}</div>
</div>
<div>
<span class="text-gray-500">DB 사용자</span>
<div class="mt-1 font-medium">{{ $log->db_user ?? '-' }}</div>
</div>
<div>
<span class="text-gray-500">일시</span>
<div class="mt-1 font-medium">{{ $log->created_at->format('Y-m-d H:i:s') }}</div>
</div>
@if($log->actor_id)
<div>
<span class="text-gray-500">Actor ID</span>
<div class="mt-1 font-medium">{{ $log->actor_id }}</div>
</div>
@endif
@if($log->session_info)
<div>
<span class="text-gray-500">IP</span>
<div class="mt-1 font-medium">{{ $log->session_info['ip'] ?? '-' }}</div>
</div>
<div>
<span class="text-gray-500">Route</span>
<div class="mt-1 font-medium text-xs">{{ $log->session_info['route'] ?? '-' }}</div>
</div>
@endif
@if($log->changed_columns)
<div>
<span class="text-gray-500">변경 컬럼</span>
<div class="mt-1">
@foreach($log->changed_columns as $col)
<span class="inline-block bg-yellow-100 text-yellow-700 px-2 py-0.5 rounded text-xs mr-1 mb-1">{{ $col }}</span>
@endforeach
</div>
</div>
@endif
</div>
</div>
<!-- Diff -->
<div class="bg-white rounded-lg shadow-sm overflow-hidden">
<h3 class="text-sm font-semibold text-gray-700 px-4 py-3 bg-gray-50 border-b">데이터 변경 내역</h3>
<table class="w-full text-sm">
<thead class="bg-gray-50 text-gray-600">
<tr>
<th class="px-4 py-2 text-left w-1/5">컬럼</th>
<th class="px-4 py-2 text-left w-2/5">이전 (OLD)</th>
<th class="px-4 py-2 text-left w-2/5">이후 (NEW)</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach($diff as $d)
<tr class="{{ $d['changed'] ? 'bg-yellow-50' : '' }}">
<td class="px-4 py-2 font-medium {{ $d['changed'] ? 'text-yellow-700' : 'text-gray-600' }}">
{{ $d['column'] }}
@if($d['changed']) <span class="text-yellow-500">*</span> @endif
</td>
<td class="px-4 py-2 text-gray-600 break-all text-xs font-mono {{ $d['changed'] ? 'bg-red-50' : '' }}">
@if($d['old'] === null)
<span class="text-gray-400 italic">NULL</span>
@elseif(is_array($d['old']) || is_object($d['old']))
<pre class="whitespace-pre-wrap">{{ json_encode($d['old'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
@else
{{ Str::limit((string) $d['old'], 500) }}
@endif
</td>
<td class="px-4 py-2 text-gray-600 break-all text-xs font-mono {{ $d['changed'] ? 'bg-green-50' : '' }}">
@if($d['new'] === null)
<span class="text-gray-400 italic">NULL</span>
@elseif(is_array($d['new']) || is_object($d['new']))
<pre class="whitespace-pre-wrap">{{ json_encode($d['new'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
@else
{{ Str::limit((string) $d['new'], 500) }}
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endsection