From 506b5aeedc71fb8cf6023d373ba5d2efbb05dfc6 Mon Sep 17 00:00:00 2001 From: fermatmind <17551046983@163.com> Date: Wed, 1 Jul 2026 21:12:32 +0800 Subject: [PATCH] MBTI-PDF-SNAPSHOT-PRINT-LAYOUT-POLISH-10: add snapshot PDF render version --- .../Controllers/API/V0_3/AttemptReadController.php | 3 +++ .../Report/Pdf/ReportPdfDocumentService.php | 5 +++++ .../V0_3/AttemptPublicReportPdfParityTest.php | 14 +++++++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/app/Http/Controllers/API/V0_3/AttemptReadController.php b/backend/app/Http/Controllers/API/V0_3/AttemptReadController.php index 094641a95..4ee0dfd72 100644 --- a/backend/app/Http/Controllers/API/V0_3/AttemptReadController.php +++ b/backend/app/Http/Controllers/API/V0_3/AttemptReadController.php @@ -3105,6 +3105,7 @@ public function resultPagePdf(Request $request, string $id): Response|JsonRespon 'X-Report-Pdf-Engine' => (string) ($generated['engine'] ?? ReportPdfDocumentService::RESULT_PAGE_EXPORT_ENGINE), 'X-Pdf-Surface' => (string) ($generated['surface'] ?? ReportPdfDocumentService::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE), 'X-Pdf-Surface-Version' => (string) ($generated['surface_version'] ?? ReportPdfDocumentService::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE_VERSION), + 'X-Pdf-Render-Version' => (string) ($generated['render_version'] ?? ReportPdfDocumentService::MBTI_RESULT_PAGE_SNAPSHOT_RENDER_VERSION), 'X-Pdf-Artifact-Cache' => ((bool) ($generated['cached'] ?? false)) ? 'HIT' : 'MISS', 'X-Legacy-Mpdf-Fallback' => 'false', 'X-Gotenberg-Trace' => (string) ($generated['trace_id'] ?? ''), @@ -3123,6 +3124,7 @@ private function resultPagePdfFailureHeaders(Request $request, string $traceId): 'X-Report-Pdf-Engine' => ReportPdfDocumentService::RESULT_PAGE_EXPORT_ENGINE, 'X-Pdf-Surface' => ReportPdfDocumentService::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE, 'X-Pdf-Surface-Version' => ReportPdfDocumentService::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE_VERSION, + 'X-Pdf-Render-Version' => ReportPdfDocumentService::MBTI_RESULT_PAGE_SNAPSHOT_RENDER_VERSION, 'X-Gotenberg-Trace' => $traceId, 'X-Legacy-Mpdf-Fallback' => 'false', 'X-Pdf-Error-Stage' => 'gotenberg.convert_url', @@ -3146,6 +3148,7 @@ private function resultPagePdfCorsHeaders(Request $request): array 'X-Report-Pdf-Engine', 'X-Pdf-Surface', 'X-Pdf-Surface-Version', + 'X-Pdf-Render-Version', 'X-Legacy-Mpdf-Fallback', 'X-Gotenberg-Trace', 'X-Pdf-Error-Stage', diff --git a/backend/app/Services/Report/Pdf/ReportPdfDocumentService.php b/backend/app/Services/Report/Pdf/ReportPdfDocumentService.php index 95d8be2eb..233f19a26 100644 --- a/backend/app/Services/Report/Pdf/ReportPdfDocumentService.php +++ b/backend/app/Services/Report/Pdf/ReportPdfDocumentService.php @@ -22,6 +22,8 @@ final class ReportPdfDocumentService public const MBTI_RESULT_PAGE_SNAPSHOT_SURFACE_VERSION = 'mbti.result_page_snapshot.v4'; + public const MBTI_RESULT_PAGE_SNAPSHOT_RENDER_VERSION = 'mbti.snapshot.print_layout.v1'; + public const RESULT_PAGE_EXPORT_ENGINE = 'gotenberg_chromium'; private const MBTI_LEGACY_RESULT_PAGE_EXPORT_SURFACE_VERSION = 'mbti.result_page_export.v2'; @@ -402,6 +404,7 @@ public function getOrGenerateMbtiResultPageExport(Attempt $attempt, array $gate, 'engine' => self::RESULT_PAGE_EXPORT_ENGINE, 'surface' => self::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE, 'surface_version' => self::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE_VERSION, + 'render_version' => self::MBTI_RESULT_PAGE_SNAPSHOT_RENDER_VERSION, 'trace_id' => $traceId, ]; } @@ -419,6 +422,7 @@ public function getOrGenerateMbtiResultPageExport(Attempt $attempt, array $gate, 'engine' => self::RESULT_PAGE_EXPORT_ENGINE, 'surface' => self::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE, 'surface_version' => self::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE_VERSION, + 'render_version' => self::MBTI_RESULT_PAGE_SNAPSHOT_RENDER_VERSION, 'trace_id' => $traceId, ]; } @@ -437,6 +441,7 @@ private function resolveResultPageExportManifestHash(Attempt $attempt, array $ga return implode('-', [ $baseHash, self::MBTI_RESULT_PAGE_SNAPSHOT_SURFACE_VERSION, + self::MBTI_RESULT_PAGE_SNAPSHOT_RENDER_VERSION, self::RESULT_PAGE_EXPORT_ENGINE, preg_replace('/[^a-z0-9_.-]+/i', '_', $locale) ?: 'locale', $entitlement, diff --git a/backend/tests/Feature/V0_3/AttemptPublicReportPdfParityTest.php b/backend/tests/Feature/V0_3/AttemptPublicReportPdfParityTest.php index 15a6c4307..702d36af0 100644 --- a/backend/tests/Feature/V0_3/AttemptPublicReportPdfParityTest.php +++ b/backend/tests/Feature/V0_3/AttemptPublicReportPdfParityTest.php @@ -309,6 +309,7 @@ public function test_public_mbti_result_page_pdf_uses_strict_gotenberg_surface() $pdf->assertHeader('X-Report-Pdf-Engine', 'gotenberg_chromium'); $pdf->assertHeader('X-Pdf-Surface', 'mbti_result_page_snapshot'); $pdf->assertHeader('X-Pdf-Surface-Version', 'mbti.result_page_snapshot.v4'); + $pdf->assertHeader('X-Pdf-Render-Version', 'mbti.snapshot.print_layout.v1'); $pdf->assertHeader('X-Pdf-Artifact-Cache', 'MISS'); $pdf->assertHeader('X-Legacy-Mpdf-Fallback', 'false'); $this->assertNotSame('', (string) $pdf->headers->get('X-Gotenberg-Trace')); @@ -352,7 +353,7 @@ public function test_public_mbti_result_page_pdf_uses_strict_gotenberg_surface() $this->assertArrayNotHasKey('failOnConsoleExceptions', $payload); Storage::disk('local')->assertExists( - "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v4-gotenberg_chromium-zh-locked-free/report_free.pdf" + "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v4-mbti.snapshot.print_layout.v1-gotenberg_chromium-zh-locked-free/report_free.pdf" ); } @@ -526,6 +527,7 @@ public function test_public_mbti_result_page_pdf_does_not_fallback_to_mpdf_when_ $pdf->assertHeader('X-Report-Pdf-Engine', 'gotenberg_chromium'); $pdf->assertHeader('X-Pdf-Surface', 'mbti_result_page_snapshot'); $pdf->assertHeader('X-Pdf-Surface-Version', 'mbti.result_page_snapshot.v4'); + $pdf->assertHeader('X-Pdf-Render-Version', 'mbti.snapshot.print_layout.v1'); $pdf->assertHeader('X-Legacy-Mpdf-Fallback', 'false'); $pdf->assertHeader('X-Pdf-Error-Stage', 'gotenberg.convert_url'); $this->assertStringContainsString('X-Gotenberg-Trace', (string) $pdf->headers->get('Access-Control-Expose-Headers')); @@ -539,7 +541,7 @@ public function test_public_mbti_result_page_pdf_does_not_fallback_to_mpdf_when_ $pdf->assertJsonPath('request_id', 'pdf-export-request-1'); $this->assertSame($pdf->headers->get('X-Gotenberg-Trace'), $pdf->json('trace')); Storage::disk('local')->assertMissing( - "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v4-gotenberg_chromium-zh-locked-free/report_free.pdf" + "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v4-mbti.snapshot.print_layout.v1-gotenberg_chromium-zh-locked-free/report_free.pdf" ); } @@ -574,6 +576,10 @@ public function test_public_mbti_result_page_pdf_does_not_hit_legacy_mpdf_surfac "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v3-gotenberg_chromium-zh-locked-free/report_free.pdf", '%PDF-1.4 old v3 summary snapshot artifact' ); + Storage::disk('local')->put( + "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v4-gotenberg_chromium-zh-locked-free/report_free.pdf", + '%PDF-1.4 old v4 snapshot artifact without render version' + ); Http::fake([ 'gotenberg:3000/forms/chromium/convert/url' => Http::response('%PDF-1.4 new chromium export', 200, [ @@ -593,6 +599,7 @@ public function test_public_mbti_result_page_pdf_does_not_hit_legacy_mpdf_surfac $this->assertStringNotContainsString('old result-page export artifact', (string) $pdf->getContent()); $this->assertStringNotContainsString('old v2 result-page export artifact', (string) $pdf->getContent()); $this->assertStringNotContainsString('old v3 summary snapshot artifact', (string) $pdf->getContent()); + $this->assertStringNotContainsString('old v4 snapshot artifact without render version', (string) $pdf->getContent()); } public function test_public_mbti_result_page_pdf_cache_hit_preserves_engine_headers(): void @@ -611,7 +618,7 @@ public function test_public_mbti_result_page_pdf_cache_hit_preserves_engine_head $this->createResult($attemptId); Storage::disk('local')->put( - "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v4-gotenberg_chromium-zh-locked-free/report_free.pdf", + "artifacts/pdf/MBTI/{$attemptId}/nohash-mbti.result_page_snapshot.v4-mbti.snapshot.print_layout.v1-gotenberg_chromium-zh-locked-free/report_free.pdf", '%PDF-1.4 cached chromium export' ); @@ -626,6 +633,7 @@ public function test_public_mbti_result_page_pdf_cache_hit_preserves_engine_head $pdf->assertHeader('X-Report-Pdf-Engine', 'gotenberg_chromium'); $pdf->assertHeader('X-Pdf-Surface', 'mbti_result_page_snapshot'); $pdf->assertHeader('X-Pdf-Surface-Version', 'mbti.result_page_snapshot.v4'); + $pdf->assertHeader('X-Pdf-Render-Version', 'mbti.snapshot.print_layout.v1'); $pdf->assertHeader('X-Pdf-Artifact-Cache', 'HIT'); $pdf->assertHeader('X-Legacy-Mpdf-Fallback', 'false'); $this->assertStringContainsString('cached chromium export', (string) $pdf->getContent());