Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void seed(DocumentSeed seed, DemoOperationalSeedContext context) {
seed.documentId(),
seed.workerId(),
context.companyId(),
null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

taskId 부분은 현재 null인 이유가 있을까요

@chaeliki chaeliki Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 섣불리 건드는 것 보다, 그 부분 체크 하고 싶어서 krestat 리뷰 요청드린건데 demo 머지 충돌 해결하면서 맞춘 임시 처리입니다!
따로 말씀드렸고 확인 픽스 주신다고 하셨습니다. 원래 본문에 추가했어야 했는데 리뷰 포인트로// 확인해주셔서 감사해욥!!

seed.documentType(),
seed.submissionStatus(),
expiryDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public DocumentController(
@PreAuthorize("hasAnyRole('ADMIN', 'HR', 'VIEWER')")
public DocumentPageResponse list(
@Parameter(description = "근로자 ID 필터") @RequestParam(required = false) UUID workerId,
@Parameter(description = "업무 ID 필터") @RequestParam(required = false) UUID taskId,
@Parameter(description = "서류 유형 필터") @RequestParam(required = false) DocumentType documentType,
@Parameter(description = "제출 상태 필터") @RequestParam(required = false) SubmissionStatus status,
@Parameter(description = "이 날짜 이전 만료 필터") @RequestParam(required = false) LocalDate expiryBefore,
Expand All @@ -79,6 +80,7 @@ public DocumentPageResponse list(
ActorContext actor = actorContextProvider.requireCurrentActor();
WorkerDocumentSearchQuery query = new WorkerDocumentSearchQuery(
workerId,
taskId,
documentType,
status,
expiryBefore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public DocumentReadinessResult calculate(UUID taskId, ActorContext actor) {

LocalDate today = LocalDate.now(clock);
WorkerDocumentSearchQuery allDocumentsQuery = new WorkerDocumentSearchQuery(
task.workerId(), null, null, null, 0, 100
task.workerId(), null, null, null, null, 0, 100
);
List<WorkerDocument> workerDocuments = workerDocumentRepository.findPage(companyId, allDocumentsQuery);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public ResponseEntity<WorkerDocumentResponse> register(
ActorContext actor = actorContextProvider.requireCurrentActor();
WorkerDocumentCreateCommand command = new WorkerDocumentCreateCommand(
workerId,
request.getTaskId(),
request.getDocumentType(),
request.getSubmissionStatus(),
request.getExpiryDate(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.LocalDate;
import java.util.UUID;

@Schema(
name = "WorkerDocumentCreateRequest",
Expand Down Expand Up @@ -44,19 +45,24 @@ public final class WorkerDocumentCreateRequest {
@Size(max = 500, message = "note는 500자 이하여야 합니다.")
private final String note;

@Schema(name = "task_id", description = "연결할 업무카드 ID (선택)", format = "uuid")
private final UUID taskId;

@JsonCreator
public WorkerDocumentCreateRequest(
@JsonProperty("document_type") DocumentType documentType,
@JsonProperty("submission_status") SubmissionStatus submissionStatus,
@JsonProperty("expiry_date") LocalDate expiryDate,
@JsonProperty("destination") String destination,
@JsonProperty("note") String note
@JsonProperty("note") String note,
@JsonProperty("task_id") UUID taskId
) {
this.documentType = documentType;
this.submissionStatus = submissionStatus;
this.expiryDate = expiryDate;
this.destination = destination;
this.note = note;
this.taskId = taskId;
}

public DocumentType getDocumentType() {
Expand All @@ -78,4 +84,8 @@ public String getDestination() {
public String getNote() {
return note;
}

public UUID getTaskId() {
return taskId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
public final class WorkerDocumentCreateCommand {

private final UUID workerId;
private final UUID taskId;
private final DocumentType documentType;
private final SubmissionStatus submissionStatus;
private final LocalDate expiryDate;
Expand All @@ -16,13 +17,15 @@ public final class WorkerDocumentCreateCommand {

public WorkerDocumentCreateCommand(
UUID workerId,
UUID taskId,
DocumentType documentType,
SubmissionStatus submissionStatus,
LocalDate expiryDate,
String destination,
String note
) {
this.workerId = workerId;
this.taskId = taskId;
this.documentType = documentType;
this.submissionStatus = submissionStatus;
this.expiryDate = expiryDate;
Expand All @@ -34,6 +37,10 @@ public UUID workerId() {
return workerId;
}

public UUID taskId() {
return taskId;
}

public DocumentType documentType() {
return documentType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public final class WorkerDocumentSearchQuery {
private static final int MAX_SIZE = 100;

private final UUID workerId;
private final UUID taskId;
private final DocumentType documentType;
private final SubmissionStatus status;
private final LocalDate expiryBefore;
Expand All @@ -19,13 +20,15 @@ public final class WorkerDocumentSearchQuery {

public WorkerDocumentSearchQuery(
UUID workerId,
UUID taskId,
DocumentType documentType,
SubmissionStatus status,
LocalDate expiryBefore,
Integer page,
Integer size
) {
this.workerId = workerId;
this.taskId = taskId;
this.documentType = documentType;
this.status = status;
this.expiryBefore = expiryBefore;
Expand All @@ -43,6 +46,10 @@ public UUID workerId() {
return workerId;
}

public UUID taskId() {
return taskId;
}

public DocumentType documentType() {
return documentType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public WorkerDocument register(WorkerDocumentCreateCommand command, ActorContext
uuidGenerator.generate(),
command.workerId(),
actor.companyId(),
command.taskId(),
command.documentType(),
command.submissionStatus(),
command.expiryDate(),
Expand Down Expand Up @@ -115,6 +116,7 @@ public WorkerDocument patch(
existing.workerDocumentId(),
existing.workerId(),
existing.companyId(),
existing.taskId(),
orElseKeep(command.documentType(), existing.documentType()),
orElseKeep(command.submissionStatus(), existing.submissionStatus()),
orElseKeep(command.expiryDate(), existing.expiryDate()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public final class WorkerDocument {
private final UUID workerDocumentId;
private final UUID workerId;
private final UUID companyId;
private final UUID taskId;
private final DocumentType documentType;
private final SubmissionStatus submissionStatus;
private final LocalDate expiryDate;
Expand All @@ -27,6 +28,7 @@ public WorkerDocument(
UUID workerDocumentId,
UUID workerId,
UUID companyId,
UUID taskId,
DocumentType documentType,
SubmissionStatus submissionStatus,
LocalDate expiryDate,
Expand All @@ -40,6 +42,7 @@ public WorkerDocument(
this.workerDocumentId = Objects.requireNonNull(workerDocumentId, "workerDocumentId must not be null");
this.workerId = Objects.requireNonNull(workerId, "workerId must not be null");
this.companyId = Objects.requireNonNull(companyId, "companyId must not be null");
this.taskId = taskId;
this.documentType = Objects.requireNonNull(documentType, "documentType must not be null");
this.submissionStatus = Objects.requireNonNull(submissionStatus, "submissionStatus must not be null");
this.expiryDate = expiryDate;
Expand All @@ -61,6 +64,7 @@ public static WorkerDocument create(
UUID workerDocumentId,
UUID workerId,
UUID companyId,
UUID taskId,
DocumentType documentType,
SubmissionStatus submissionStatus,
LocalDate expiryDate,
Expand All @@ -73,6 +77,7 @@ public static WorkerDocument create(
workerDocumentId,
workerId,
companyId,
taskId,
documentType,
submissionStatus,
expiryDate,
Expand All @@ -97,6 +102,10 @@ public UUID companyId() {
return companyId;
}

public UUID taskId() {
return taskId;
}

public DocumentType documentType() {
return documentType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ private String buildWhereClause(WorkerDocumentSearchQuery query) {
if (query.workerId() != null) {
where.append(" and document.workerId = :workerId");
}
if (query.taskId() != null) {
where.append(" and document.taskId = :taskId");
}
if (query.documentType() != null) {
where.append(" and document.documentType = :documentType");
}
Expand All @@ -120,6 +123,9 @@ private void bindParameters(Query jpaQuery, UUID companyId, WorkerDocumentSearch
if (query.workerId() != null) {
jpaQuery.setParameter("workerId", query.workerId());
}
if (query.taskId() != null) {
jpaQuery.setParameter("taskId", query.taskId());
}
if (query.documentType() != null) {
jpaQuery.setParameter("documentType", query.documentType());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class WorkerDocumentJpaEntity {
@Column(name = "company_id", nullable = false, updatable = false)
private UUID companyId;

@Column(name = "task_id")
private UUID taskId;

@Enumerated(EnumType.STRING)
@Column(name = "document_type", nullable = false, length = 40)
private DocumentType documentType;
Expand Down Expand Up @@ -66,6 +69,7 @@ private WorkerDocumentJpaEntity(
UUID workerDocumentId,
UUID workerId,
UUID companyId,
UUID taskId,
DocumentType documentType,
SubmissionStatus submissionStatus,
LocalDate expiryDate,
Expand All @@ -79,6 +83,7 @@ private WorkerDocumentJpaEntity(
this.workerDocumentId = workerDocumentId;
this.workerId = workerId;
this.companyId = companyId;
this.taskId = taskId;
this.documentType = documentType;
this.submissionStatus = submissionStatus;
this.expiryDate = expiryDate;
Expand All @@ -96,6 +101,7 @@ public static WorkerDocumentJpaEntity fromDomain(WorkerDocument document) {
document.workerDocumentId(),
document.workerId(),
document.companyId(),
document.taskId(),
document.documentType(),
document.submissionStatus(),
document.expiryDate(),
Expand All @@ -113,6 +119,7 @@ public WorkerDocument toDomain() {
workerDocumentId,
workerId,
companyId,
taskId,
documentType,
submissionStatus,
expiryDate,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ALTER TABLE worker_document
ADD COLUMN task_id UUID;

ALTER TABLE worker_document
ADD CONSTRAINT fk_worker_document_task_company
FOREIGN KEY (task_id, company_id)
REFERENCES task (task_id, company_id) ON DELETE RESTRICT;

CREATE INDEX idx_worker_document_task ON worker_document (task_id, company_id);
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ void seedCompaniesAndUsers() {
@BeforeEach
void resetWorkerDocumentState() throws Exception {
jdbcTemplate.update("DELETE FROM worker_document");
jdbcTemplate.update("DELETE FROM task_checklist_item");
jdbcTemplate.update("DELETE FROM task_transition_history");
jdbcTemplate.update("DELETE FROM approval_request");
jdbcTemplate.update("DELETE FROM external_submission");
jdbcTemplate.update("DELETE FROM task_evidence");
jdbcTemplate.update("DELETE FROM task");
jdbcTemplate.update("DELETE FROM worker");
workerIdInCompanyA = registerWorker(accessToken(login(HR_A_EMAIL)), "서류테스트근로자");
}
Expand Down Expand Up @@ -151,6 +157,24 @@ void patchWithStaleExpectedVersionReturnsConflict() throws Exception {
.isEqualTo("WORKER_DOCUMENT_VERSION_CONFLICT");
}

@Test
void listDocumentsFiltersByTaskId() throws Exception {
String accessToken = accessToken(login(HR_A_EMAIL));
String taskId = createTask(accessToken, workerIdInCompanyA);
String documentIdWithTask = registerDocument(accessToken, workerIdInCompanyA, taskId);
String documentIdWithoutTask = registerDocument(accessToken, workerIdInCompanyA, null);

HttpResponse<String> response = getJson(
"/api/v1/documents?taskId=" + taskId,
accessToken
);

assertThat(response.statusCode()).isEqualTo(200);
java.util.List<String> ids = JsonPath.read(response.body(), "$.items[*].worker_document_id");
assertThat(ids).contains(documentIdWithTask);
assertThat(ids).doesNotContain(documentIdWithoutTask);
}

@Test
void documentFromAnotherCompanyIsReturnedAsNotFoundOnPatch() throws Exception {
String companyAToken = accessToken(login(HR_A_EMAIL));
Expand Down Expand Up @@ -210,6 +234,36 @@ private String registerDocument(String accessToken, String workerId) throws Exce
return JsonPath.read(response.body(), "$.worker_document_id");
}

private String registerDocument(String accessToken, String workerId, String taskId) throws Exception {
String body = """
{"document_type": "PASSPORT_COPY", "submission_status": "MISSING", "task_id": %s}
""".formatted(taskId == null ? "null" : "\"" + taskId + "\"");
HttpResponse<String> response = postJson(
"/api/v1/workers/" + workerId + "/documents",
body,
accessToken
);
assertThat(response.statusCode()).isEqualTo(201);
return JsonPath.read(response.body(), "$.worker_document_id");
}

private String createTask(String accessToken, String workerId) throws Exception {
String body = """
{
"worker_id":"%s",
"task_type":"RECONTRACT",
"workflow_id":"WF-CON-001",
"title":"필터 테스트 업무",
"description":"taskId 필터 검증용",
"due_date":"2026-12-31",
"business_data":{}
}
""".formatted(workerId);
HttpResponse<String> response = postJson("/api/v1/tasks", body, accessToken);
assertThat(response.statusCode()).isEqualTo(201);
return JsonPath.read(response.body(), "$.task_id");
}

private void insertCompany(UUID companyId, String name) {
jdbcTemplate.update(
"""
Expand Down Expand Up @@ -257,6 +311,14 @@ private HttpResponse<String> patchJson(String path, String body, String accessTo
return sendJson(path, body, accessToken, "PATCH");
}

private HttpResponse<String> getJson(String path, String accessToken) throws Exception {
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri(path)).GET();
if (accessToken != null) {
requestBuilder.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
}
return httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString());
}

private HttpResponse<String> sendJson(String path, String body, String accessToken, String method)
throws Exception {
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri(path))
Expand Down
Loading