Skip to content

[✨Feat] 자기소개서 제출 및 최초 첨삭 Job 생성#41

Merged
yong203 merged 1 commit into
devfrom
feat/#40
Jun 20, 2026
Merged

[✨Feat] 자기소개서 제출 및 최초 첨삭 Job 생성#41
yong203 merged 1 commit into
devfrom
feat/#40

Conversation

@yong203

@yong203 yong203 commented Jun 20, 2026

Copy link
Copy Markdown
Member

작업 내용

  • POST /cover-letters/{coverLetterId}/submit API를 구현했습니다.
  • 필수 step 데이터를 검증하고 최초 첨삭용 PENDING LLM Job을 생성합니다.
  • DRAFT, REVIEW_FAILED, REVIEWING, REVIEWED 상태별 제출 정책을 적용했습니다.
  • 비관적 행 잠금으로 동시 제출 시 중복 Job 생성을 방지했습니다.
  • 진행 중 다른 LLM Job이 있으면 LLM_JOB_ALREADY_RUNNING을 반환합니다.
  • API 계약, 설계 결정, 진행 상태 문서를 실제 구현과 맞게 갱신했습니다.

스크린샷

1. coverLetter submit 이전에, coverLetter.status 가 DRAFT 인 것 확인 및 비어있는 llm jobs table 확인

스크린샷 2026-06-21 오전 3 50 03 스크린샷 2026-06-21 오전 3 53 13 스크린샷 2026-06-21 오전 3 49 51

2. @PostMapping("/cover-letters/{coverLetterId}/submit") 실행 결과 확인

스크린샷 2026-06-21 오전 3 54 11

llm job 생성 확인
스크린샷 2026-06-21 오전 3 54 59

coverLetters.status 가 REVIEWING 으로 바뀐것 확인
스크린샷 2026-06-21 오전 3 54 59

관련 이슈

문서 반영

  • 반영한 문서:
    • docs/api/README.md
    • docs/api/cover-letters.md
    • docs/decisions/cover-letters.md
    • docs/status.md

확인 결과

  • ./gradlew test
  • ./gradlew check
  • git diff --check

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 자기소개서 제출 API 구현 완료
    • 제출 시 누락된 정보를 필드별로 상세 검증하여 반환
    • 다른 종류의 작업이 진행 중일 때 중복 제출 방지 (409 Conflict)
    • 제출 성공 시 작업 ID와 리뷰 버전 정보 응답
  • 문서화

    • API 상태 및 응답 형식 명확화
    • 검증 오류 메시지 및 정책 정리

@yong203 yong203 linked an issue Jun 20, 2026 that may be closed by this pull request
7 tasks
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

POST /cover-letters/{coverLetterId}/submit(API-014) 엔드포인트를 구현한다. 비관적 쓰기 잠금 쿼리, 상태별 분기 서비스 로직, LlmJob 생성, 유효성 검사 details 반환, LLM_JOB_ALREADY_RUNNING 에러 코드가 추가되고, 관련 컨트롤러·레포지토리·서비스 테스트 및 API/결정/진행 문서가 갱신된다.

Changes

자기소개서 제출 및 최초 첨삭 LLM Job 생성

Layer / File(s) Summary
DTO·결과 레코드·에러 코드 정의
src/main/java/com/daon/rewrite/coverletter/dto/SubmitCoverLetterResponse.java, src/main/java/com/daon/rewrite/coverletter/service/SubmitCoverLetterResult.java, src/main/java/com/daon/rewrite/global/exception/ErrorCode.java
SubmitCoverLetterResult(CoverLetter, LlmJob) 레코드, SubmitCoverLetterResponse DTO(from 팩토리 메서드 포함), LLM_JOB_ALREADY_RUNNING(409) 에러 코드가 추가된다.
비관적 잠금 쿼리 및 running job 조회 메서드
src/main/java/com/daon/rewrite/coverletter/repository/CoverLetterRepository.java, src/main/java/com/daon/rewrite/llmjob/repository/LlmJobRepository.java
CoverLetterRepositoryPESSIMISTIC_WRITE 잠금을 사용하는 findActiveByIdAndOwnerIdForUpdate가 추가되고, LlmJobRepository에 targetType·targetId·상태 목록으로 최신 실행 중 job을 조회하는 파생 쿼리 메서드가 추가된다.
CoverLetter.startReview 및 CoverLetterService.submit 핵심 로직
src/main/java/com/daon/rewrite/coverletter/entity/CoverLetter.java, src/main/java/com/daon/rewrite/coverletter/service/CoverLetterService.java
CoverLetter.startReview(Instant)가 추가되어 상태를 REVIEWING으로 전환하고 submittedAt을 최초 1회만 기록한다. CoverLetterService.submitREVIEWED·REVIEWING·그 외 상태별로 분기하고, 다른 running job 존재 시 LLM_JOB_ALREADY_RUNNING을 던지며, validateSubmit으로 필드·질문 누락 및 maxAnswerLength 범위를 검증한 뒤 pendingReview LlmJob을 저장한다. findRunningJob·addMissingDetail 헬퍼도 포함된다.
POST /cover-letters/{coverLetterId}/submit 엔드포인트
src/main/java/com/daon/rewrite/coverletter/controller/CoverLetterController.java
coverLetterService.submit 호출 결과를 SubmitCoverLetterResponse.from으로 래핑해 반환하는 엔드포인트가 추가된다.
서비스·컨트롤러·레포지토리 테스트
src/test/java/com/daon/rewrite/coverletter/service/CoverLetterServiceTest.java, src/test/java/com/daon/rewrite/coverletter/controller/CoverLetterControllerTest.java, src/test/java/com/daon/rewrite/coverletter/repository/CoverLetterRepositoryTest.java, src/test/java/com/daon/rewrite/llmjob/repository/LlmJobRepositoryTest.java
서비스 테스트에 submit 시나리오 8종(드래프트, 검증 실패, REVIEWING 중복, REVIEWED 반환, INTERNAL_ERROR, REVIEW_FAILED 재시도, LLM_JOB_ALREADY_RUNNING, NOT_FOUND), 컨트롤러 테스트에 submit 응답 5종, 레포지토리 동시성 차단 테스트(CountDownLatch·TimeoutException 기반), LlmJob 레포지토리 최신 running job 조회 테스트가 추가된다.
API 문서·결정 문서·진행 현황 갱신
docs/api/README.md, docs/api/cover-letters.md, docs/decisions/cover-letters.md, docs/status.md
API-014 상태가 Implemented로 갱신되고, latestReviewVersionId 필드·409 규칙·VALIDATION_ERROR 메시지가 API 문서에 반영된다. Decision 053의 details 구조가 field+reason으로 수정되어 step 필드가 제거된다. docs/status.md의 REQ-005 증빙이 확장된다.

Possibly related PRs

  • Rewrite-Team/Rewrite-BE#19: 본 PR의 CoverLetterService.submit·CoverLetter.startReview가 의존하는 기본 CoverLetter 모델, createDraft, 컨트롤러·레포지토리 스켈레톤을 도입한 PR이다.
  • Rewrite-Team/Rewrite-BE#37: 본 PR의 validateSubmit이 검증 대상으로 사용하는 question·originalAnswer·maxAnswerLength 문항 필드 저장 API와 엔티티를 추가한 PR이다.
  • Rewrite-Team/Rewrite-BE#39: 본 PR의 CoverLetterService.submit이 생성·저장하는 LlmJob 레코드와 LlmJobRepository가 연결되는 GET /llm-jobs/{jobId} 스켈레톤을 도입한 PR이다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 자기소개서 제출 및 최초 첨삭 Job 생성이라는 PR의 핵심 변경사항을 명확하고 간결하게 요약합니다.
Description check ✅ Passed PR 설명은 템플릿의 필수 섹션(작업 내용, 관련 이슈, 문서 반영, 확인 결과)을 모두 포함하며 자세하게 작성되었습니다.
Linked Issues check ✅ Passed PR의 코드 변경사항은 #40의 모든 주요 요구사항을 충족합니다: API-014 구현, 상태 전환, Job 생성, 검증 로직, 동시성 처리, 문서 갱신 등이 모두 포함되어 있습니다.
Out of Scope Changes check ✅ Passed PR의 모든 변경사항은 #40의 명시된 작업 범위와 일치하며, 제외 대상(실제 LLM 호출, SSE, ReviewVersion 생성 등)은 포함되지 않았습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@yong203 yong203 self-assigned this Jun 20, 2026
@yong203 yong203 added the ✨ Feature 새로운 기능 구현 label Jun 20, 2026
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.42424% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ewrite/coverletter/service/CoverLetterService.java 90.19% 1 Missing and 4 partials ⚠️

📢 Thoughts on this report? Let us know!

@yong203 yong203 marked this pull request as ready for review June 20, 2026 19:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/daon/rewrite/coverletter/controller/CoverLetterController.java`:
- Around line 97-101: The submit method with `@PostMapping` annotation at line 97
is missing OpenAPI contract annotations required by controller guidelines. Add
OpenAPI documentation annotations to the submit method to specify: the operation
description and summary using `@Operation`, the successful response (HTTP 200)
with SubmitCoverLetterResponse DTO using `@ApiResponse`, and error responses for
common failure cases (400, 404, 409) using `@ApiResponses`. Ensure the annotations
match the actual behavior and response types of the endpoint to maintain API
contract documentation consistency.

In `@src/main/java/com/daon/rewrite/coverletter/service/CoverLetterService.java`:
- Around line 207-213: The findRunningJob method at line 207 retrieves the most
recent running job without filtering by type, which can cause incorrect error
handling when multiple running jobs of different types exist for the same cover
letter. When a coverLetter is in REVIEWING status, the validation at line 211
should specifically check for a COVER_LETTER_REVIEW type job, not just any
running job. Modify the findRunningJob call to explicitly filter by
COVER_LETTER_REVIEW type, or create a separate method that fetches only
COVER_LETTER_REVIEW type running jobs. This ensures that the type validation
logic correctly identifies if the appropriate review job exists, preventing the
INTERNAL_ERROR from being thrown incorrectly when other types of running jobs
are present.

In
`@src/test/java/com/daon/rewrite/coverletter/repository/CoverLetterRepositoryTest.java`:
- Around line 161-178: The current test does not guarantee that the second task
has actually reached the point of executing the locked query before checking for
TimeoutException. The timeout might pass due to scheduling delays rather than
lock contention. Add a new CountDownLatch (for example, secondStarted) and have
the second task count it down just before calling
findActiveByIdAndOwnerIdForUpdate, then await this latch in the main test thread
before asserting on second.get(). This ensures the second task has actually
reached the lock acquisition attempt when the timeout check occurs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e911f892-f43c-4038-b3d0-48c3892d4d7f

📥 Commits

Reviewing files that changed from the base of the PR and between cc589e6 and d2ea21f.

📒 Files selected for processing (16)
  • docs/api/README.md
  • docs/api/cover-letters.md
  • docs/decisions/cover-letters.md
  • docs/status.md
  • src/main/java/com/daon/rewrite/coverletter/controller/CoverLetterController.java
  • src/main/java/com/daon/rewrite/coverletter/dto/SubmitCoverLetterResponse.java
  • src/main/java/com/daon/rewrite/coverletter/entity/CoverLetter.java
  • src/main/java/com/daon/rewrite/coverletter/repository/CoverLetterRepository.java
  • src/main/java/com/daon/rewrite/coverletter/service/CoverLetterService.java
  • src/main/java/com/daon/rewrite/coverletter/service/SubmitCoverLetterResult.java
  • src/main/java/com/daon/rewrite/global/exception/ErrorCode.java
  • src/main/java/com/daon/rewrite/llmjob/repository/LlmJobRepository.java
  • src/test/java/com/daon/rewrite/coverletter/controller/CoverLetterControllerTest.java
  • src/test/java/com/daon/rewrite/coverletter/repository/CoverLetterRepositoryTest.java
  • src/test/java/com/daon/rewrite/coverletter/service/CoverLetterServiceTest.java
  • src/test/java/com/daon/rewrite/llmjob/repository/LlmJobRepositoryTest.java

@yong203 yong203 merged commit 40db14a into dev Jun 20, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능 구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[✨Feat] 자기소개서 제출 및 최초 첨삭 Job 생성

1 participant