diff --git a/app/Http/Controllers/Api/V1/Documents/DocumentController.php b/app/Http/Controllers/Api/V1/Documents/DocumentController.php index 729ed46..d63bdf9 100644 --- a/app/Http/Controllers/Api/V1/Documents/DocumentController.php +++ b/app/Http/Controllers/Api/V1/Documents/DocumentController.php @@ -74,6 +74,22 @@ public function destroy(int $id): JsonResponse }, __('message.deleted')); } + /** + * rendered_html 스냅샷 저장 (Lazy Snapshot) + * PATCH /v1/documents/{id}/snapshot + */ + public function patchSnapshot(int $id, UpdateRequest $request): JsonResponse + { + return ApiResponse::handle(function () use ($id, $request) { + $renderedHtml = $request->validated()['rendered_html'] ?? null; + if (! $renderedHtml) { + throw new \Symfony\Component\HttpKernel\Exception\BadRequestHttpException('rendered_html is required'); + } + + return $this->service->patchSnapshot($id, $renderedHtml); + }, __('message.updated')); + } + // ========================================================================= // FQC 일괄생성 (제품검사) // ========================================================================= diff --git a/app/Services/DocumentService.php b/app/Services/DocumentService.php index 2fef635..82783b6 100644 --- a/app/Services/DocumentService.php +++ b/app/Services/DocumentService.php @@ -718,6 +718,28 @@ public function fqcStatus(int $orderId, int $templateId): array ]; } + // ========================================================================= + // Snapshot (Lazy Snapshot) + // ========================================================================= + + /** + * rendered_html만 업데이트 (상태 무관, canEdit 체크 없음) + * Lazy Snapshot: 조회 시 rendered_html이 없으면 프론트에서 캡처 후 저장 + */ + public function patchSnapshot(int $id, string $renderedHtml): Document + { + $tenantId = $this->tenantId(); + + $document = Document::query() + ->where('tenant_id', $tenantId) + ->findOrFail($id); + + $document->rendered_html = $renderedHtml; + $document->save(); + + return $document; + } + // ========================================================================= // Resolve/Upsert (React 연동용) // ========================================================================= diff --git a/app/Services/WorkOrderService.php b/app/Services/WorkOrderService.php index ee5d342..ba39c09 100644 --- a/app/Services/WorkOrderService.php +++ b/app/Services/WorkOrderService.php @@ -2431,11 +2431,26 @@ public function resolveInspectionDocument(int $workOrderId, array $params = []): ->latest() ->first(); + // Lazy Snapshot 대상: rendered_html이 없는 문서 (상태 무관) + $snapshotDocumentId = null; + $snapshotCandidate = Document::query() + ->where('tenant_id', $tenantId) + ->where('template_id', $templateId) + ->where('linkable_type', 'work_order') + ->where('linkable_id', $workOrderId) + ->whereNull('rendered_html') + ->latest() + ->value('id'); + if ($snapshotCandidate) { + $snapshotDocumentId = $snapshotCandidate; + } + return [ 'work_order_id' => $workOrderId, 'template_id' => $templateId, 'template' => $formattedTemplate, 'existing_document' => $existingDocument, + 'snapshot_document_id' => $snapshotDocumentId, 'work_order_info' => $this->buildWorkOrderInfo($workOrder), ]; } diff --git a/routes/api/v1/documents.php b/routes/api/v1/documents.php index ae56c70..2044ab4 100644 --- a/routes/api/v1/documents.php +++ b/routes/api/v1/documents.php @@ -33,6 +33,7 @@ Route::get('/{id}', [DocumentController::class, 'show'])->whereNumber('id')->name('v1.documents.show'); Route::post('/', [DocumentController::class, 'store'])->name('v1.documents.store'); Route::patch('/{id}', [DocumentController::class, 'update'])->whereNumber('id')->name('v1.documents.update'); + Route::patch('/{id}/snapshot', [DocumentController::class, 'patchSnapshot'])->whereNumber('id')->name('v1.documents.snapshot'); Route::delete('/{id}', [DocumentController::class, 'destroy'])->whereNumber('id')->name('v1.documents.destroy'); // 결재 워크플로우