refactor:법인도장 저장소를 GCS로 변경 (로컬/서버 환경 무관)

- 업로드: base64 → 임시파일 → GCS 업로드
- 조회: GCS signed URL 반환 (60분 유효)
- 삭제: GCS 객체 삭제 + tenant_settings 삭제
- 계약 생성 시: GCS에서 다운로드 → 로컬 저장 → signer에 설정
- tenant_settings 값: image_path → gcs_object로 변경

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-13 16:48:18 +09:00
parent 0d00d1c67f
commit 40a9b26861

View File

@@ -12,6 +12,7 @@
use App\Models\ESign\EsignSignField;
use App\Models\ESign\EsignAuditLog;
use App\Models\Tenants\TenantSetting;
use App\Services\GoogleCloudStorageService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -32,24 +33,21 @@ public function getStamp(): JsonResponse
->where('setting_key', 'company_stamp')
->first();
if (!$setting || empty($setting->setting_value['image_path'])) {
if (!$setting || empty($setting->setting_value['gcs_object'])) {
return response()->json(['success' => true, 'data' => null]);
}
$path = $setting->setting_value['image_path'];
if (!Storage::disk('local')->exists($path)) {
$gcs = app(GoogleCloudStorageService::class);
$signedUrl = $gcs->getSignedUrl($setting->setting_value['gcs_object'], 60);
if (!$signedUrl) {
return response()->json(['success' => true, 'data' => null]);
}
$content = Storage::disk('local')->get($path);
$mime = Storage::disk('local')->mimeType($path) ?: 'image/png';
$dataUrl = 'data:' . $mime . ';base64,' . base64_encode($content);
return response()->json([
'success' => true,
'data' => [
'image_path' => $path,
'image_url' => $dataUrl,
'image_url' => $signedUrl,
],
]);
}
@@ -70,14 +68,31 @@ public function uploadStamp(Request $request): JsonResponse
return response()->json(['success' => false, 'message' => '이미지 데이터가 올바르지 않습니다.'], 422);
}
$path = "esign/{$tenantId}/stamps/company_stamp.png";
// 기존 파일이 있으면 삭제
if (Storage::disk('local')->exists($path)) {
Storage::disk('local')->delete($path);
$gcs = app(GoogleCloudStorageService::class);
if (!$gcs->isAvailable()) {
return response()->json(['success' => false, 'message' => 'GCS 설정이 되어 있지 않습니다.'], 500);
}
Storage::disk('local')->put($path, $imageData);
// 기존 GCS 파일 삭제
$existing = TenantSetting::where('tenant_id', $tenantId)
->where('setting_group', 'esign')
->where('setting_key', 'company_stamp')
->first();
if ($existing && !empty($existing->setting_value['gcs_object'])) {
$gcs->delete($existing->setting_value['gcs_object']);
}
// 임시 파일에 저장 후 GCS 업로드
$tmpFile = tempnam(sys_get_temp_dir(), 'stamp_');
file_put_contents($tmpFile, $imageData);
$gcsObject = "esign/{$tenantId}/stamps/company_stamp.png";
$gcsUri = $gcs->upload($tmpFile, $gcsObject);
unlink($tmpFile);
if (!$gcsUri) {
return response()->json(['success' => false, 'message' => 'GCS 업로드에 실패했습니다.'], 500);
}
TenantSetting::updateOrCreate(
[
@@ -86,20 +101,18 @@ public function uploadStamp(Request $request): JsonResponse
'setting_key' => 'company_stamp',
],
[
'setting_value' => ['image_path' => $path],
'setting_value' => ['gcs_object' => $gcsObject],
'updated_by' => auth()->id(),
]
);
$mime = Storage::disk('local')->mimeType($path) ?: 'image/png';
$dataUrl = 'data:' . $mime . ';base64,' . base64_encode($imageData);
$signedUrl = $gcs->getSignedUrl($gcsObject, 60);
return response()->json([
'success' => true,
'message' => '법인도장이 등록되었습니다.',
'data' => [
'image_path' => $path,
'image_url' => $dataUrl,
'image_url' => $signedUrl,
],
]);
}
@@ -116,9 +129,10 @@ public function deleteStamp(): JsonResponse
->first();
if ($setting) {
$path = $setting->setting_value['image_path'] ?? null;
if ($path && Storage::disk('local')->exists($path)) {
Storage::disk('local')->delete($path);
$gcsObject = $setting->setting_value['gcs_object'] ?? null;
if ($gcsObject) {
$gcs = app(GoogleCloudStorageService::class);
$gcs->delete($gcsObject);
}
$setting->delete();
}
@@ -287,22 +301,30 @@ public function store(Request $request): JsonResponse
]);
}
// 법인도장 자동 적용: tenant_settings에 등록된 도장이 있으면 creator signer에 설정
// 법인도장 자동 적용: GCS에서 다운로드 → 로컬 저장 → signer에 설정
$stampSetting = TenantSetting::where('tenant_id', $tenantId)
->where('setting_group', 'esign')
->where('setting_key', 'company_stamp')
->first();
if ($stampSetting && !empty($stampSetting->setting_value['image_path'])) {
if ($stampSetting && !empty($stampSetting->setting_value['gcs_object'])) {
$creatorSigner = EsignSigner::withoutGlobalScopes()
->where('contract_id', $contract->id)
->where('role', 'creator')
->first();
if ($creatorSigner) {
$creatorSigner->update([
'signature_image_path' => $stampSetting->setting_value['image_path'],
]);
$gcs = app(GoogleCloudStorageService::class);
$signedUrl = $gcs->getSignedUrl($stampSetting->setting_value['gcs_object'], 5);
if ($signedUrl) {
$imageData = @file_get_contents($signedUrl);
if ($imageData) {
$localPath = "esign/{$tenantId}/signatures/{$contract->id}_{$creatorSigner->id}_stamp.png";
Storage::disk('local')->put($localPath, $imageData);
$creatorSigner->update(['signature_image_path' => $localPath]);
}
}
}
}