From 26eb1bcdc36797c7fef6b44c4d6d2112f53b77c8 Mon Sep 17 00:00:00 2001 From: mini Date: Wed, 12 Aug 2026 12:46:40 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20WAITING=5FWORKER=20=EB=8D=B0?= =?UTF-8?q?=EB=AA=A8=20=EC=97=85=EB=AC=B4=EC=B9=B4=EB=93=9C=EC=97=90=20?= =?UTF-8?q?=EC=8A=B9=EC=9D=B8=20=EC=9D=B4=EB=A0=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 여권 사본 제출 대기 등 WAITING_WORKER 상태로 시딩된 업무카드가 실제로는 APPROVED 단계를 거치지 않아 대응하는 ApprovalRequest가 없었고, 그 결과 근로자 보안 링크 발급·재발급이 항상 422(TASK_NOT_APPROVED)로 실패했다. transitionPath에 READY_FOR_REVIEW/APPROVED 단계를 추가하고 해당 업무들의 APPROVED 승인 이력을 시딩해 실제 애플리케이션 흐름과 일치시켰다. Fixes #146 --- .../seed/DemoOperationalSeedCatalog.java | 14 +++++++------- .../seed/DemoTaskWorkflowSeedCatalog.java | 7 ++++++- .../seed/DemoAuthSeedIntegrationTest.java | 12 ++++++------ .../seed/DemoOperationalSeedCatalogTest.java | 10 +++++----- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalog.java b/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalog.java index 5118e480..d60b9395 100644 --- a/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalog.java +++ b/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalog.java @@ -50,8 +50,8 @@ final class DemoOperationalSeedCatalog { UUID.fromString("96000000-0000-0000-0000-000000000027"), UUID.fromString("96000000-0000-0000-0000-000000000028"), UUID.fromString("96000000-0000-0000-0000-000000000045"), - UUID.fromString("96000000-0000-0000-0000-000000000083"), - UUID.fromString("96000000-0000-0000-0000-000000000094") + UUID.fromString("96000000-0000-0000-0000-000000000089"), + UUID.fromString("96000000-0000-0000-0000-000000000100") ); private static final UUID RETIRED_GOLDEN_FLOW_DRAFT_ID = UUID.fromString("94700000-0000-0000-0000-000000000002"); @@ -221,12 +221,12 @@ private void verifyDefinitions() { requireSize(demoDocuments, 83, "Demo Company document"); requireSize(testDocuments, 8, "Test Company document"); requireSize(demoChecklists, 60, "Demo Company checklist item"); - requireSize(demoApprovals, 12, "Demo Company approval request"); - requireSize(demoTransitions, 48, "Demo Company task transition"); + requireSize(demoApprovals, 15, "Demo Company approval request"); + requireSize(demoTransitions, 54, "Demo Company task transition"); requireSize(demoExternalSubmissions, 6, "Demo Company external submission"); requireSize(demoEvidence, 10, "Demo Company completion evidence"); requireSize(demoDocumentRequestDrafts, 4, "Demo Company document request draft"); - requireSize(demoAudits, 88, "Demo Company audit event"); + requireSize(demoAudits, 94, "Demo Company audit event"); requireSize(testAudits, 8, "Test Company audit event"); requireDistribution( demoTasks.stream().map(TaskSeed::taskType).toList(), @@ -264,7 +264,7 @@ private void verifyDefinitions() { demoApprovals.stream().map(ApprovalSeed::status).toList(), Map.of( ApprovalStatus.PENDING, 3L, - ApprovalStatus.APPROVED, 7L, + ApprovalStatus.APPROVED, 10L, ApprovalStatus.REJECTED, 1L, ApprovalStatus.INVALIDATED, 1L ), @@ -283,7 +283,7 @@ private void verifyDefinitions() { requireDistribution( demoAudits.stream().map(AuditSeed::actorType).toList(), Map.of( - ActorType.HR_USER, 77L, + ActorType.HR_USER, 83L, ActorType.AI_AGENT, 2L, ActorType.SYSTEM_RULE, 6L, ActorType.WORKER_LINK, 3L diff --git a/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoTaskWorkflowSeedCatalog.java b/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoTaskWorkflowSeedCatalog.java index 5dea3bd7..caa0e003 100644 --- a/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoTaskWorkflowSeedCatalog.java +++ b/src/main/java/com/fowoco/server/demo/infrastructure/seed/DemoTaskWorkflowSeedCatalog.java @@ -77,7 +77,10 @@ static List demoApprovals(List tasks) { approval(11, tasks, 23, ApprovalStatus.APPROVED, "신청 결과 확인 후 승인"), approval(12, tasks, 9, ApprovalStatus.REJECTED, "필수 고용 정보 보완 필요"), approval(13, tasks, 1, ApprovalStatus.INVALIDATED, - "마감일 변경으로 기존 승인 snapshot을 무효화") + "마감일 변경으로 기존 승인 snapshot을 무효화"), + approval(14, tasks, 3, ApprovalStatus.APPROVED, "여권 사본 요청 전 승인 확인"), + approval(15, tasks, 10, ApprovalStatus.APPROVED, "체류서류 요청 전 승인 확인"), + approval(16, tasks, 11, ApprovalStatus.APPROVED, "외국인등록증 요청 전 승인 확인") ); } @@ -282,6 +285,8 @@ private static List transitionPath(int taskNumber) { case 3, 8, 10, 11 -> List.of( TaskStatus.NEEDS_INFO, TaskStatus.DRAFT, + TaskStatus.READY_FOR_REVIEW, + TaskStatus.APPROVED, TaskStatus.WAITING_WORKER ); case 4, 18, 19 -> List.of( diff --git a/src/test/java/com/fowoco/server/auth/infrastructure/seed/DemoAuthSeedIntegrationTest.java b/src/test/java/com/fowoco/server/auth/infrastructure/seed/DemoAuthSeedIntegrationTest.java index 52b0d679..b2b1e7f1 100644 --- a/src/test/java/com/fowoco/server/auth/infrastructure/seed/DemoAuthSeedIntegrationTest.java +++ b/src/test/java/com/fowoco/server/auth/infrastructure/seed/DemoAuthSeedIntegrationTest.java @@ -120,12 +120,12 @@ class DemoAuthSeedIntegrationTest { Map.entry("worker_document", 83), Map.entry("stored_file", 3), Map.entry("task_checklist_item", 60), - Map.entry("approval_request", 12), - Map.entry("task_transition_history", 48), + Map.entry("approval_request", 15), + Map.entry("task_transition_history", 54), Map.entry("external_submission", 6), Map.entry("task_evidence", 10), Map.entry("document_request_draft", 4), - Map.entry("audit_event", 88) + Map.entry("audit_event", 94) ); private static final Map EXPECTED_TEST_COUNTS = Map.of( "user_account", 3, @@ -271,11 +271,11 @@ private void assertExactCountsAndDistributions() { ); assertThat(distribution("approval_request", "status", COMPANY_ID)) .containsExactlyInAnyOrderEntriesOf( - Map.of("PENDING", 3, "APPROVED", 7, "REJECTED", 1, "INVALIDATED", 1) + Map.of("PENDING", 3, "APPROVED", 10, "REJECTED", 1, "INVALIDATED", 1) ); assertThat(distribution("audit_event", "actor_type", COMPANY_ID)) .containsExactlyInAnyOrderEntriesOf( - Map.of("HR_USER", 77, "AI_AGENT", 2, "SYSTEM_RULE", 6, "WORKER_LINK", 3) + Map.of("HR_USER", 83, "AI_AGENT", 2, "SYSTEM_RULE", 6, "WORKER_LINK", 3) ); assertThat(jdbcTemplate.queryForObject( @@ -952,7 +952,7 @@ private void assertFrontendRelevantApiResultsAndTenantIsolation() throws Excepti HttpResponse testAudits = authorizedGet("/api/v1/audit-events?limit=100", testToken); assertOk(demoAudits); assertOk(testAudits); - assertThat(JsonPath.>read(demoAudits.body(), "$.items")).hasSize(88); + assertThat(JsonPath.>read(demoAudits.body(), "$.items")).hasSize(94); assertThat(JsonPath.>read(testAudits.body(), "$.items")).hasSize(8); assertTenantApiCount(testToken, "/api/v1/workers?size=100", 5); diff --git a/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalogTest.java b/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalogTest.java index 37460b5f..22f3d13e 100644 --- a/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalogTest.java +++ b/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoOperationalSeedCatalogTest.java @@ -69,15 +69,15 @@ void excludesGoldenFlowOperationalDataWithoutRenumberingShowcaseFixtures() { .containsExactlyInAnyOrderElementsOf(idsExcept( "94300000-0000-0000-0000-000000000", 1, - 13, + 16, Set.of(2) )); assertThat(catalog.demoTransitions().stream().map(seed -> seed.transitionId())) .containsExactlyInAnyOrderElementsOf(idsExcept( "94400000-0000-0000-0000-000000000", 1, - 52, - IntStream.rangeClosed(13, 16).boxed().collect(Collectors.toSet()) + 60, + IntStream.rangeClosed(15, 20).boxed().collect(Collectors.toSet()) )); assertThat(catalog.demoDocumentRequestDrafts().stream().map(seed -> seed.draftId())) .containsExactlyInAnyOrderElementsOf(idsExcept( @@ -90,8 +90,8 @@ void excludesGoldenFlowOperationalDataWithoutRenumberingShowcaseFixtures() { .containsExactlyInAnyOrderElementsOf(idsExcept( "96000000-0000-0000-0000-000000000", 1, - 96, - Set.of(24, 25, 26, 27, 28, 45, 83, 94) + 102, + Set.of(24, 25, 26, 27, 28, 45, 89, 100) )); Set activeTaskIds = catalog.demoTasks().stream() From 11bfce2d3656bf3a3caf9cf7d3aa3f9b85568263 Mon Sep 17 00:00:00 2001 From: mini Date: Wed, 12 Aug 2026 12:56:28 +0900 Subject: [PATCH 2/4] =?UTF-8?q?test:=20PostgreSQL=20=EB=8D=B0=EB=AA=A8=20?= =?UTF-8?q?=EC=8B=9C=EB=93=9C=20=ED=86=B5=ED=95=A9=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B9=B4=EC=9A=B4=ED=8A=B8=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WAITING_WORKER 업무 승인 이력 추가로 늘어난 approval_request/ task_transition_history/audit_event 카운트를 반영. --- .../seed/DemoSeedPostgreSqlApplicationIntegrationTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoSeedPostgreSqlApplicationIntegrationTest.java b/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoSeedPostgreSqlApplicationIntegrationTest.java index de5991ae..d6e032a2 100644 --- a/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoSeedPostgreSqlApplicationIntegrationTest.java +++ b/src/test/java/com/fowoco/server/demo/infrastructure/seed/DemoSeedPostgreSqlApplicationIntegrationTest.java @@ -36,12 +36,12 @@ class DemoSeedPostgreSqlApplicationIntegrationTest { Map.entry("worker_document", 83), Map.entry("stored_file", 3), Map.entry("task_checklist_item", 60), - Map.entry("approval_request", 12), - Map.entry("task_transition_history", 48), + Map.entry("approval_request", 15), + Map.entry("task_transition_history", 54), Map.entry("external_submission", 6), Map.entry("task_evidence", 10), Map.entry("document_request_draft", 4), - Map.entry("audit_event", 88) + Map.entry("audit_event", 94) ); @TempDir From c023c9a0f0abdbadbb0f5fd74c3fc4691982ec8d Mon Sep 17 00:00:00 2001 From: Kyoungmin Kim <151009045+BcKmini@users.noreply.github.com> Date: Wed, 12 Aug 2026 16:17:44 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=EA=B7=BC=EB=A1=9C=EC=9E=90=20?= =?UTF-8?q?=EA=B3=B5=EA=B0=9C=20=EB=A7=81=ED=81=AC=20API=203=EA=B0=9C?= =?UTF-8?q?=EC=97=90=20/api/v1=20=EC=A0=91=EB=91=90=EC=82=AC=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=20=EC=88=98=EC=A0=95=20(#149)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WorkerLinkViewController·WorkerLinkDocumentController·WorkerResponseController가 다른 모든 컨트롤러와 달리 /api/v1 접두사 없이 매핑되어 있어, 클라이언트가 실제로 호출하는 /api/v1/public/worker-links/** 경로에서는 SecurityConfig의 permitAll 규칙이 매칭되지 않고 인증이 필요한 규칙으로 떨어졌다. 근로자가 링크로 안내를 조회하거나 서류를 제출하는 흐름 전체가 실제 배포 환경에서 항상 실패하는 상태였다. 세 컨트롤러 매핑과 SecurityConfig의 permitAll 매처에 /api/v1 접두사를 추가하고, 같은 버그를 잡아내지 못했던 통합 테스트의 경로도 실제 API와 일치시켰다. Fixes #148 --- .../server/common/config/SecurityConfig.java | 4 ++-- .../api/WorkerLinkDocumentController.java | 2 +- .../api/WorkerLinkViewController.java | 2 +- .../api/WorkerResponseController.java | 2 +- .../PostgreSqlRestrictedRoleHttpE2ETest.java | 12 +++++------ .../WorkerLinkSecurityIntegrationTest.java | 20 +++++++++---------- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/fowoco/server/common/config/SecurityConfig.java b/src/main/java/com/fowoco/server/common/config/SecurityConfig.java index 4797307b..dbd4e708 100644 --- a/src/main/java/com/fowoco/server/common/config/SecurityConfig.java +++ b/src/main/java/com/fowoco/server/common/config/SecurityConfig.java @@ -109,8 +109,8 @@ public SecurityFilterChain applicationSecurityFilterChain( "/api/v1/auth/password-resets" ).permitAll() .requestMatchers("/error").permitAll() - .requestMatchers(HttpMethod.GET, "/public/worker-links/**").permitAll() - .requestMatchers(HttpMethod.POST, "/public/worker-links/**").permitAll() + .requestMatchers(HttpMethod.GET, "/api/v1/public/worker-links/**").permitAll() + .requestMatchers(HttpMethod.POST, "/api/v1/public/worker-links/**").permitAll() .requestMatchers(HttpMethod.GET, "/api/v1/**") .hasAnyRole("ADMIN", "HR", "VIEWER") .requestMatchers(HttpMethod.HEAD, "/api/v1/**") diff --git a/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkDocumentController.java b/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkDocumentController.java index 18e305ff..dde6990a 100644 --- a/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkDocumentController.java +++ b/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkDocumentController.java @@ -58,7 +58,7 @@ public WorkerLinkDocumentController(WorkerLinkDocumentService workerLinkDocument @ApiResponse(responseCode = "429", description = "요청 과다") }) @PostMapping( - path = "/public/worker-links/{token}/documents", + path = "/api/v1/public/worker-links/{token}/documents", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE ) diff --git a/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkViewController.java b/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkViewController.java index d90f8d17..d698558a 100644 --- a/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkViewController.java +++ b/src/main/java/com/fowoco/server/workerlink/api/WorkerLinkViewController.java @@ -21,7 +21,7 @@ @Tag(name = "Worker Link (Public)", description = "근로자 공개 안내·제출") @RestController -@RequestMapping("/public/worker-links/{token}") +@RequestMapping("/api/v1/public/worker-links/{token}") public class WorkerLinkViewController { private final WorkerLinkViewService workerLinkViewService; diff --git a/src/main/java/com/fowoco/server/workerlink/api/WorkerResponseController.java b/src/main/java/com/fowoco/server/workerlink/api/WorkerResponseController.java index b5572793..23c05fa2 100644 --- a/src/main/java/com/fowoco/server/workerlink/api/WorkerResponseController.java +++ b/src/main/java/com/fowoco/server/workerlink/api/WorkerResponseController.java @@ -53,7 +53,7 @@ public WorkerResponseController(WorkerResponseService workerResponseService) { @ApiResponse(responseCode = "429", description = "요청 과다") }) @PostMapping( - path = "/public/worker-links/{token}/responses", + path = "/api/v1/public/worker-links/{token}/responses", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE ) diff --git a/src/test/java/com/fowoco/server/common/security/PostgreSqlRestrictedRoleHttpE2ETest.java b/src/test/java/com/fowoco/server/common/security/PostgreSqlRestrictedRoleHttpE2ETest.java index b5c77161..d9489444 100644 --- a/src/test/java/com/fowoco/server/common/security/PostgreSqlRestrictedRoleHttpE2ETest.java +++ b/src/test/java/com/fowoco/server/common/security/PostgreSqlRestrictedRoleHttpE2ETest.java @@ -36,7 +36,7 @@ class PostgreSqlRestrictedRoleHttpE2ETest { private static final String COOKIE_NAME = "fowoco_refresh_token"; - private static final String PROBE_PATH = "/public/worker-links/rls-test/probes"; + private static final String PROBE_PATH = "/api/v1/public/worker-links/rls-test/probes"; private static final List RLS_TABLES = List.of( "company", "user_account", @@ -259,7 +259,7 @@ void refreshRejectsUnknownExpiredAndRevokedTokensWithOneSafeContract() @Test void workerLinkBootstrapAcceptsOnlyActiveRegisteredLinks() throws Exception { HttpResponse active = get( - "/public/worker-links/" + "/api/v1/public/worker-links/" + PostgreSqlRestrictedRoleHttpDataFixture.ACTIVE_WORKER_LINK_TOKEN, null ); @@ -277,7 +277,7 @@ void workerLinkBootstrapAcceptsOnlyActiveRegisteredLinks() throws Exception { ); HttpResponse responseWrite = postJson( - "/public/worker-links/" + "/api/v1/public/worker-links/" + PostgreSqlRestrictedRoleHttpDataFixture.ACTIVE_WORKER_LINK_TOKEN + "/responses", """ @@ -298,16 +298,16 @@ void workerLinkBootstrapAcceptsOnlyActiveRegisteredLinks() throws Exception { ); assertThat(get( - "/public/worker-links/" + "/api/v1/public/worker-links/" + PostgreSqlRestrictedRoleHttpDataFixture.EXPIRED_WORKER_LINK_TOKEN, null ).statusCode()).isEqualTo(410); assertThat(get( - "/public/worker-links/" + "/api/v1/public/worker-links/" + PostgreSqlRestrictedRoleHttpDataFixture.REVOKED_WORKER_LINK_TOKEN, null ).statusCode()).isEqualTo(410); - assertThat(get("/public/worker-links/unregistered-rls-http-token", null).statusCode()) + assertThat(get("/api/v1/public/worker-links/unregistered-rls-http-token", null).statusCode()) .isEqualTo(410); } diff --git a/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java b/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java index ff715232..c700df37 100644 --- a/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java +++ b/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java @@ -130,7 +130,7 @@ void fullFlow_issueViewUploadRespond_succeeds() throws Exception { assertThat(rawToken).isNotBlank(); assertThat(workerUrl).isEqualTo("http://localhost:5173/worker-portal/" + rawToken); - HttpResponse viewResponse = getJson("/public/worker-links/" + rawToken, null); + HttpResponse viewResponse = getJson("/api/v1/public/worker-links/" + rawToken, null); assertThat(viewResponse.statusCode()).isEqualTo(200); assertThat(viewResponse.headers().firstValue("Cache-Control")).contains("no-store"); assertThat(JsonPath.read(viewResponse.body(), "$.guidance")) @@ -160,7 +160,7 @@ void fullFlow_issueViewUploadRespond_succeeds() throws Exception { assertThat(retryUploadId).isEqualTo(firstUploadId); HttpResponse responseSubmit = postJson( - "/public/worker-links/" + rawToken + "/responses", + "/api/v1/public/worker-links/" + rawToken + "/responses", """ {"response_type":"DOCUMENT_SUBMITTED","upload_ids":["%s"],"idempotency_key":"key-1"} """.formatted(uploadId), @@ -263,7 +263,7 @@ void activeWorkerLinkWithoutDraftReturnsContentNotReady() throws Exception { String taskId = createApprovedTask(hrToken, workerId); String workerUrl = issueWorkerLink(hrToken, taskId, "content-not-ready-key"); - HttpResponse response = getJson("/public/worker-links/" + workerUrl, null); + HttpResponse response = getJson("/api/v1/public/worker-links/" + workerUrl, null); assertThat(response.statusCode()).isEqualTo(409); assertThat(JsonPath.read(response.body(), "$.code")) @@ -278,7 +278,7 @@ void hrCanListAndMarkWorkerResponsesReviewed() throws Exception { String workerUrl = issueWorkerLink(hrToken, taskId, "response-management-key"); HttpResponse submitResponse = postJson( - "/public/worker-links/" + workerUrl + "/responses", + "/api/v1/public/worker-links/" + workerUrl + "/responses", """ {"response_type":"QUESTION","message":"여권의 어느 면을 제출하나요?","idempotency_key":"question-key"} """, @@ -360,7 +360,7 @@ void hrCanInspectAndAdoptSubmittedFilesThenResumeTask() throws Exception { String contractFileId = JsonPath.read(contractUpload.body(), "$.upload_id"); HttpResponse submitResponse = postJson( - "/public/worker-links/" + rawToken + "/responses", + "/api/v1/public/worker-links/" + rawToken + "/responses", """ { "response_type":"DOCUMENT_SUBMITTED", @@ -873,12 +873,12 @@ void issueRejectsOtherCompanyTask() throws Exception { @Test void viewReturns410ForNonExistentToken() throws Exception { - HttpResponse viewResponse = getJson("/public/worker-links/nonexistenttoken12345", null); + HttpResponse viewResponse = getJson("/api/v1/public/worker-links/nonexistenttoken12345", null); assertThat(viewResponse.statusCode()).isEqualTo(410); } @Test void documentsEndpointAllowsIdempotencyKeyHeaderInCors() throws Exception { - HttpRequest request = HttpRequest.newBuilder(uri("/public/worker-links/test-token/documents")) + HttpRequest request = HttpRequest.newBuilder(uri("/api/v1/public/worker-links/test-token/documents")) .header("Origin", "http://localhost:3000") .header("Access-Control-Request-Method", "POST") .header("Access-Control-Request-Headers", "Idempotency-Key") @@ -1008,7 +1008,7 @@ private HttpResponse uploadFile(String token, String filename, String mi writeFieldPart(out, "clientRequestId", UUID.randomUUID().toString()); out.write(("--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8)); - HttpRequest request = HttpRequest.newBuilder(uri("/public/worker-links/" + token + "/documents")) + HttpRequest request = HttpRequest.newBuilder(uri("/api/v1/public/worker-links/" + token + "/documents")) .header(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=" + BOUNDARY) .POST(HttpRequest.BodyPublishers.ofByteArray(out.toByteArray())) .build(); @@ -1028,7 +1028,7 @@ private HttpResponse uploadFileAsType( writeFieldPart(out, "documentType", documentType); out.write(("--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8)); - HttpRequest request = HttpRequest.newBuilder(uri("/public/worker-links/" + token + "/documents")) + HttpRequest request = HttpRequest.newBuilder(uri("/api/v1/public/worker-links/" + token + "/documents")) .header(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=" + BOUNDARY) .POST(HttpRequest.BodyPublishers.ofByteArray(out.toByteArray())) .build(); @@ -1043,7 +1043,7 @@ private HttpResponse uploadFileWithFixedClientRequestId( writeFieldPart(out, "clientRequestId", clientRequestId); out.write(("--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8)); - HttpRequest request = HttpRequest.newBuilder(uri("/public/worker-links/" + token + "/documents")) + HttpRequest request = HttpRequest.newBuilder(uri("/api/v1/public/worker-links/" + token + "/documents")) .header(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=" + BOUNDARY) .POST(HttpRequest.BodyPublishers.ofByteArray(out.toByteArray())) .build(); From bc20243d97e773f8c1da2a4b53af100bb1eca67f Mon Sep 17 00:00:00 2001 From: mini Date: Wed, 12 Aug 2026 16:58:34 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=EB=B3=91=ED=95=A9=20=EA=B3=BC?= =?UTF-8?q?=EC=A0=95=EC=97=90=EC=84=9C=20=EC=9C=A0=EC=8B=A4=EB=90=9C=20mar?= =?UTF-8?q?kSentResponse=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=8B=A8?= =?UTF-8?q?=EA=B3=84=20=EB=B3=B5=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workerlink/WorkerLinkSecurityIntegrationTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java b/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java index 765a0f9e..b0754b9e 100644 --- a/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java +++ b/src/test/java/com/fowoco/server/workerlink/WorkerLinkSecurityIntegrationTest.java @@ -131,6 +131,12 @@ void fullFlow_issueViewUploadRespond_succeeds() throws Exception { assertThat(rawToken).isNotBlank(); assertThat(workerUrl).isEqualTo("http://localhost:5173/worker-portal/" + rawToken); + HttpResponse markSentResponse = postWithoutBody( + "/api/v1/worker-links/" + workerLinkId + "/sent", + hrToken + ); + assertThat(markSentResponse.statusCode()).isEqualTo(200); + HttpResponse viewResponse = getJson("/api/v1/public/worker-links/" + rawToken, null); assertThat(viewResponse.statusCode()).isEqualTo(200); assertThat(viewResponse.headers().firstValue("Cache-Control")).contains("no-store");