feat:서명 완료 시 계약서 이메일 발송 및 감사 로그 추가

- EsignCompletedMail Mailable 생성 (완료 알림 + PDF 다운로드 링크)
- completed.blade.php 이메일 뷰 템플릿 생성 (초록색 테마)
- submitSignature에 contract_completed 감사 로그 추가
- 모든 서명자에게 완료 이메일 발송 + completion_email_sent 감사 로그
- 이메일 발송 실패 시 try-catch로 계약 완료 보호

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-13 06:25:01 +09:00
parent f050be52fe
commit 8f7a441900
3 changed files with 176 additions and 1 deletions

View File

@@ -8,7 +8,9 @@
use App\Models\ESign\EsignSigner;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Mail\EsignCompletedMail;
use App\Mail\EsignRequestMail;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use App\Services\ESign\PdfSignatureService;
use Illuminate\Support\Facades\Storage;
@@ -250,11 +252,49 @@ public function submitSignature(Request $request, string $token): JsonResponse
$pdfService = new PdfSignatureService();
$pdfService->mergeSignatures($contract);
} catch (\Throwable $e) {
\Illuminate\Support\Facades\Log::error('PDF 서명 합성 실패', [
Log::error('PDF 서명 합성 실패', [
'contract_id' => $contract->id,
'error' => $e->getMessage(),
]);
}
// 계약 완료 감사 로그
EsignAuditLog::create([
'tenant_id' => $contract->tenant_id,
'contract_id' => $contract->id,
'signer_id' => $signer->id,
'action' => 'contract_completed',
'ip_address' => $request->ip(),
'user_agent' => $request->userAgent(),
'metadata' => ['total_signers' => $allSigners->count()],
'created_at' => now(),
]);
// 모든 서명자에게 완료 이메일 발송
foreach ($allSigners as $completedSigner) {
try {
Mail::to($completedSigner->email)->send(
new EsignCompletedMail($contract, $completedSigner, $allSigners)
);
EsignAuditLog::create([
'tenant_id' => $contract->tenant_id,
'contract_id' => $contract->id,
'signer_id' => $completedSigner->id,
'action' => 'completion_email_sent',
'ip_address' => $request->ip(),
'user_agent' => $request->userAgent(),
'metadata' => ['email' => $completedSigner->email],
'created_at' => now(),
]);
} catch (\Throwable $e) {
Log::error('계약 완료 이메일 발송 실패', [
'contract_id' => $contract->id,
'signer_id' => $completedSigner->id,
'error' => $e->getMessage(),
]);
}
}
} else {
$contract->update(['status' => 'partially_signed']);