Skip to content

[Feat] Application 도메인 구현 - #27

Merged
kosy00 merged 7 commits into
developfrom
feat/23-application-api
Jul 27, 2026
Merged

[Feat] Application 도메인 구현#27
kosy00 merged 7 commits into
developfrom
feat/23-application-api

Conversation

@kosy00

@kosy00 kosy00 commented Jul 4, 2026

Copy link
Copy Markdown
Owner

관련 이슈

closes #23

구현 내용

  • Application 도메인 추가
  • 낙관적 락 구현
  • 상태전이 검증 로직 구현

변경 사항

체크리스트

  • 코드 구현 완료
  • 동작 확인
  • 불필요한 코드/주석 제거

Summary by CodeRabbit

  • New Features
    • 지원(신청/취소) 및 고용주 처리(수락/거절/완료) REST API와 내 지원/지원자 목록 조회 기능이 추가되었습니다.
    • 지원 상태 전이 규칙을 적용해 요청 결과를 표준 응답으로 제공합니다.
  • Bug Fixes
    • 중복 신청, 모집 인원 초과, 잘못된 상태 전이는 사전에 차단됩니다.
    • 동시 처리 충돌 시 409 응답으로 안내되도록 개선되었습니다.

@kosy00 kosy00 self-assigned this Jul 4, 2026
@kosy00 kosy00 added the feat 새 기능 label Jul 4, 2026
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9bf96ae7-9852-4970-a989-43e13ae4b001

📥 Commits

Reviewing files that changed from the base of the PR and between 0d95d74 and 4024c49.

📒 Files selected for processing (1)
  • src/main/java/com/ilson/spotwork/common/exception/GlobalExceptionHandler.java
 ___________________________________________________
< Brace yourself. Winter is coming...for your bugs. >
 ---------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9bf96ae7-9852-4970-a989-43e13ae4b001

📥 Commits

Reviewing files that changed from the base of the PR and between 0d95d74 and 4024c49.

📒 Files selected for processing (1)
  • src/main/java/com/ilson/spotwork/common/exception/GlobalExceptionHandler.java

📝 Walkthrough

Walkthrough

Application 도메인이 추가되었습니다. 엔티티와 상태 전이, 지원 처리 서비스 및 REST API를 구현하고, Job의 수락 인원 관리와 낙관적 락 충돌 응답을 추가했습니다.

Changes

Application 도메인 구현

Layer / File(s) Summary
상태 전이 규칙 및 엔티티 정의
.../application/entity/ApplicationStatus.java, .../application/entity/Application.java, .../common/exception/ErrorCode.java
지원 상태 전이 규칙과 전이 검증, 잘못된 전이에 대한 에러 코드가 정의됩니다.
Job 수락 인원 및 낙관적 락
.../job/entity/Job.java
acceptedCount, @Version, 모집 인원 초과 검증 및 수락 인원 증가 메서드가 추가됩니다.
지원 저장소 및 응답 계약
.../application/repository/ApplicationRepository.java, .../application/dto/ApplicationResponse.java
중복 지원 확인·지원 목록 조회 저장소와 엔티티 변환 응답 DTO가 추가됩니다.
ApplicationService 비즈니스 흐름
.../application/service/ApplicationService.java
지원, 수락, 거절, 완료, 취소, 지원 목록 조회 및 권한 검증을 구현합니다.
Application REST 엔드포인트
.../application/controller/ApplicationController.java
WORKER와 EMPLOYER 역할별 지원 처리 및 조회 API를 제공합니다.
낙관적 락 오류 응답
.../common/exception/GlobalExceptionHandler.java
낙관적 락 충돌을 HTTP 409와 전용 오류 응답으로 처리합니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Worker
  participant ApplicationController
  participant ApplicationService
  participant ApplicationRepository
  participant Job

  Worker->>ApplicationController: POST /api/applications/jobs/{jobId}
  ApplicationController->>ApplicationService: apply(workerId, jobId)
  ApplicationService->>ApplicationRepository: 중복 지원 확인
  ApplicationService->>Job: 공고 상태 및 모집 인원 확인
  ApplicationService->>ApplicationRepository: PENDING 지원 저장
  ApplicationService-->>ApplicationController: ApplicationResponse
  ApplicationController-->>Worker: ApiResponse<ApplicationResponse>

  participant Employer
  Employer->>ApplicationController: PATCH /{applicationId}/accept
  ApplicationController->>ApplicationService: accept(employerId, applicationId)
  ApplicationService->>ApplicationRepository: 지원 조회
  ApplicationService->>Job: acceptedCount 증가
  ApplicationService-->>ApplicationController: ApplicationResponse
  ApplicationController-->>Employer: ApiResponse<ApplicationResponse>
Loading

Possibly related PRs

  • kosy00/ilson#6: 상태 전이 예외와 전역 오류 응답 처리 인프라와 연결됩니다.
  • kosy00/ilson#24: ApiResponse.error(...)GlobalExceptionHandler 변경과 연결됩니다.

Poem

깡총깡총 지원서를 접수하네 🐰
상태가 폴짝, 인원수도 착착!
충돌은 409로 살짝 막고
당근밭 코드가 무럭무럭 자라네 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 Application 도메인 구현이라는 주요 변경 사항을 간결하게 잘 요약합니다.
Description check ✅ Passed 관련 이슈, 구현 내용, 변경 사항, 체크리스트 섹션이 모두 있어 템플릿을 대체로 충족합니다.
Linked Issues check ✅ Passed Application 엔티티, 상태 전이 검증, 지원/취소/조회/수락/거절/완료 API가 이슈 #23의 요구사항과 일치합니다.
Out of Scope Changes check ✅ Passed 추가된 DTO, 서비스, 컨트롤러, 오류코드, Job 확장은 모두 Application 기능 구현에 필요한 범위입니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/23-application-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 2

🧹 Nitpick comments (9)
src/main/java/com/ilson/spotwork/domain/application/repository/ApplicationRepository.java (2)

16-20: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

목록 조회 시 N+1 쿼리 발생 가능성.

findByWorkerIdOrderByCreatedAtDescfindByJobIdjob, worker를 fetch join하지 않습니다. ApplicationResponse.from()이 각 항목에서 application.getJob().getTitle(), application.getWorker().getNickname()을 호출하므로(LAZY 연관관계), 목록 항목 수만큼 추가 쿼리가 발생합니다. @QueryJOIN FETCH job, JOIN FETCH worker를 추가하는 것을 권장합니다.

♻️ 제안
+    `@Query`("SELECT a FROM Application a JOIN FETCH a.job JOIN FETCH a.worker WHERE a.worker.id = :workerId ORDER BY a.createdAt DESC")
+    Slice<Application> findByWorkerIdOrderByCreatedAtDesc(`@Param`("workerId") Long workerId, Pageable pageable);
🤖 Prompt for 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.

In
`@src/main/java/com/ilson/spotwork/domain/application/repository/ApplicationRepository.java`
around lines 16 - 20, The list queries in ApplicationRepository are vulnerable
to N+1 because ApplicationResponse.from() reads application.getJob().getTitle()
and application.getWorker().getNickname() on lazy relations. Update
findByWorkerIdOrderByCreatedAtDesc and findByJobId to fetch the needed
associations eagerly, preferably by adding `@Query` with JOIN FETCH for job and
worker so ApplicationResponse mapping does not trigger per-row extra selects.

22-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

주석 처리된 미사용 코드 제거.

Line 23의 커밋된 countByJobIdAndStatus 메서드는 실제로 사용되지 않습니다. 필요 없다면 제거하는 것이 좋습니다.

🤖 Prompt for 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.

In
`@src/main/java/com/ilson/spotwork/domain/application/repository/ApplicationRepository.java`
around lines 22 - 24, The ApplicationRepository interface contains a
commented-out unused method declaration that should be removed rather than left
as dead code. Delete the commented countByJobIdAndStatus repository method and
keep ApplicationRepository limited to actually used repository contracts,
checking for any references before removing it.
src/main/java/com/ilson/spotwork/common/exception/ErrorCode.java (1)

34-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

INVALID_STATUS_TRANSITIONINVALID_APPLICATION_STATUS가 중복된 개념입니다.

동일한 "잘못된 상태 전이" 상황에 대해 두 개의 유사한 에러코드가 존재합니다(Line 34, 36). Application.transitionTo()INVALID_APPLICATION_STATUS를, ApplicationService.cancel()의 수동 상태 체크는 INVALID_STATUS_TRANSITION을 사용하는 것으로 보여, 클라이언트가 동일한 유형의 오류에 대해 서로 다른 코드를 받게 됩니다. 하나로 통합하는 것을 권장합니다.

🤖 Prompt for 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.

In `@src/main/java/com/ilson/spotwork/common/exception/ErrorCode.java` around
lines 34 - 36, `ErrorCode` contains two overlapping “invalid status transition”
codes, so unify `INVALID_STATUS_TRANSITION` and `INVALID_APPLICATION_STATUS`
into a single shared error code. Update the callers in
`Application.transitionTo()` and `ApplicationService.cancel()` to use the same
`ErrorCode` symbol, and remove the duplicate enum entry so clients receive one
consistent code for the same failure case.
src/main/java/com/ilson/spotwork/domain/job/entity/Job.java (2)

64-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

@Builder 사용 시 필드 초기값이 무시되는 Lombok 특성 주의

@Builder가 적용된 클래스에서 private int acceptedCount = 0;처럼 필드 초기화 값을 지정해도, @Builder.Default가 없으면 빌더로 객체를 생성할 때 해당 초기값은 무시되고 자바 기본값(int의 경우 0)이 사용됩니다. 현재는 초기값과 기본값이 동일(0)해서 문제가 드러나지 않지만, 추후 초기값이 바뀌면 조용히 깨지는 함정이 될 수 있습니다.

♻️ 제안 diff
+    `@Builder.Default`
     `@Column`(nullable = false)
     private int acceptedCount = 0;
🤖 Prompt for 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.

In `@src/main/java/com/ilson/spotwork/domain/job/entity/Job.java` around lines 64
- 65, `Job` 클래스의 `acceptedCount`는 `@Builder`로 생성할 때 필드 초기화가 무시될 수 있으므로, 현재의
`private int acceptedCount = 0;`를 `@Builder.Default`와 함께 사용하도록 수정하세요. `Job`의 빌더
생성 경로에서 기본값이 항상 유지되도록 `acceptedCount` 선언을 명확히 하고, 나중에 초기값이 변경되어도 빌더가 이를 반영하도록
맞춰주세요.

61-73: 🗄️ Data Integrity & Integration | 🔵 Trivial

신규 컬럼 추가에 따른 DB 마이그레이션 영향 검토 필요

jobs 테이블에 이미 데이터가 존재하는 상태에서 @Version(NOT NULL 암묵적 요구)과 acceptedCount(nullable = false)를 추가하면, 기존 로우들의 값이 NULL로 남아있을 경우 첫 업데이트 시 버전 비교(WHERE version = ?)가 실패하거나 NOT NULL 제약을 위반할 수 있습니다. Flyway/Liquibase 등 마이그레이션 스크립트에서 기존 로우에 대한 backfill(version=0, acceptedCount=0) 처리가 되어 있는지 확인이 필요합니다.

🤖 Prompt for 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.

In `@src/main/java/com/ilson/spotwork/domain/job/entity/Job.java` around lines 61
- 73, Existing rows in jobs may break after adding the `@Version` field and the
non-null acceptedCount column in Job. Update the DB migration (Flyway/Liquibase)
to backfill all existing jobs with version = 0 and acceptedCount = 0 before
enforcing NOT NULL/optimistic locking, and ensure the Job entity’s
acceptedCount/default behavior stays aligned with the migration.
src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java (4)

82-86: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

모집인원 초과 검증 로직 중복 (DRY 위반)

job.getAcceptedCount() >= application.getJob().getHeadcount() 체크는 Job.increaseAcceptedCount() (src/main/java/com/ilson/spotwork/domain/job/entity/Job.java 라인 68) 내부에 이미 동일한 검증이 존재합니다. 여기서 별도로 재검증할 필요 없이 job.increaseAcceptedCount()를 먼저 호출해 예외를 위임받고, 성공 시에만 application.transitionTo(ACCEPTED)를 호출하는 순서로 단순화할 수 있습니다.

♻️ 제안 diff
-            if (job.getAcceptedCount() >= application.getJob().getHeadcount()) {
-                throw new CustomException(ErrorCode.JOB_CLOSED);
-            }
-            application.transitionTo(ApplicationStatus.ACCEPTED);
-            job.increaseAcceptedCount();
+            job.increaseAcceptedCount();
+            application.transitionTo(ApplicationStatus.ACCEPTED);
🤖 Prompt for 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.

In
`@src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java`
around lines 82 - 86, In ApplicationService.accept flow, the 모집인원 초과 check is
duplicated because Job.increaseAcceptedCount already enforces the same limit.
Remove the explicit `job.getAcceptedCount() >=
application.getJob().getHeadcount()` guard in the ApplicationService logic, call
`job.increaseAcceptedCount()` first so it can throw
`CustomException(ErrorCode.JOB_CLOSED)` itself, and only after that succeeds
call `application.transitionTo(ApplicationStatus.ACCEPTED)`; use
`ApplicationService` and `Job.increaseAcceptedCount` as the key locations when
updating the order.

132-150: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

목록 조회 시 N+1 쿼리 발생 가능성

getMyApplications/getApplicants가 호출하는 ApplicationRepository.findByWorkerIdOrderByCreatedAtDesc, findByJobId(관련 스니펫 기준 단순 파생 쿼리, fetch join 없음)로 조회한 Application 목록을 ApplicationResponse.from으로 매핑할 때, 각 엔티티의 지연 로딩된 job/worker 연관관계에 접근하면서 목록 크기만큼 추가 쿼리가 발생할 수 있습니다. 지원자/지원 목록이 많아질수록 성능에 영향을 줄 수 있으니, 해당 리포지토리 메서드에 JOIN FETCH를 적용하는 것을 권장합니다.

🤖 Prompt for 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.

In
`@src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java`
around lines 132 - 150, The application list queries in
ApplicationService#getMyApplications and ApplicationService#getApplicants can
trigger N+1 when ApplicationResponse.from touches lazy Application associations.
Update the repository methods used here, especially
ApplicationRepository.findByWorkerIdOrderByCreatedAtDesc and findByJobId, to
fetch the needed relations with JOIN FETCH (or an equivalent entity graph) so
job/worker are loaded in the initial query. Make sure the returned Application
entities already include the associations required by ApplicationResponse.from
to avoid per-row extra queries.

58-73: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

apply()의 낙관적 락 try-catch는 사실상 도달하지 않는 코드일 가능성

이 메서드에서 Job은 조회만 하고 변경하지 않으며, 새로 생성되는 Application은 이번 요청에서 처음 INSERT되는 엔티티입니다(버전 충돌이 발생할 대상이 없음, ApplicationStatus.java 스니펫 기준 Application 엔티티에 @Version이 추가되었다는 근거도 없음). 따라서 ObjectOptimisticLockingFailureException을 잡는 이 catch 블록은 실제로 트리거될 가능성이 낮아 보입니다. accept()에서 복사돼 온 방어 코드라면 제거하거나, 실제로 의도한 시나리오(예: 중복 지원 방지)에 맞는 예외 처리로 교체하는 것이 좋습니다.

🤖 Prompt for 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.

In
`@src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java`
around lines 58 - 73, `ApplicationService.apply()`의
`ObjectOptimisticLockingFailureException` catch는 현재 흐름에서 거의 발생하지 않는 방어 코드로 보입니다.
`apply()`에서는 `Job`을 조회만 하고 새 `Application`을 생성해
`applicationRepository.save(...)`로 INSERT하므로 낙관적 락 충돌 대상이 없고, `Application`에
`@Version` 근거도 없습니다. 따라서 이 `try-catch`를 제거하거나, 정말 필요한 의도가 중복 지원 방지라면
`applicationRepository.save` 전에/후에 실제 중복을 감지하는 예외 처리로 바꾸고
`ApplicationService.apply`, `applicationRepository.save`,
`ApplicationResponse.from` 기준으로 흐름을 정리하세요.

114-130: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift

지원 취소를 물리 삭제(hard delete)로 처리 - 이력 유실 가능성

cancel()applicationRepository.delete(application)으로 레코드를 완전히 삭제합니다. ApplicationStatus enum(관련 스니펫 기준)에는 CANCELLED 상태가 없어, 취소된 지원 이력이 통계/분쟁 대응 등에 필요할 경우 복구가 불가능합니다. 상태 전이 기반의 소프트 삭제(CANCELLED 상태 추가 후 transitionTo)를 고려해 볼 만합니다. 다만 이는 이미 별도 레이어에서 확정된 ApplicationStatus/Application 엔티티 설계에 영향을 주므로 팀 논의가 필요합니다.

🤖 Prompt for 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.

In
`@src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java`
around lines 114 - 130, The cancel() flow in ApplicationService currently
performs a hard delete via applicationRepository.delete(application), which
removes the application history entirely. Update the logic to use a status-based
cancellation path instead: add a CANCELLED state to ApplicationStatus if needed,
and switch cancel() to transition the Application entity to that state through
its existing status change method (for example, a transitionTo-style domain
method) and persist the update. Keep the worker ownership and PENDING-only
checks in place, and use the ApplicationService, ApplicationStatus, and
ApplicationRepository symbols to locate the affected flow.
🤖 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/ilson/spotwork/domain/application/entity/Application.java`:
- Around line 18-30: The Application entity currently has no optimistic locking,
so concurrent status updates can overwrite each other. Add a version field
annotated with `@Version` in Application, or move a shared version field into
BaseEntity if that is the intended common pattern, and ensure Application’s
status transitions use this versioned entity state. Use the Application class
and its BaseEntity inheritance point to place the new version tracking cleanly.

In
`@src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java`:
- Around line 76-94: The optimistic-lock handling in ApplicationService.accept
is incomplete because the Job `@Version` conflict may only surface at flush/commit
time and escape the local try-catch. Update the flow around
getApplicationWithEmployerCheck, application.transitionTo, and
job.increaseAcceptedCount so the conflict is forced inside this method by using
an explicit flush/saveAndFlush pattern, or add a GlobalExceptionHandler for
ObjectOptimisticLockingFailureException. Make sure the caught conflict is
consistently mapped to ErrorCode.OPTIMISTIC_LOCK_CONFLICT instead of leaking as
a 500.

---

Nitpick comments:
In `@src/main/java/com/ilson/spotwork/common/exception/ErrorCode.java`:
- Around line 34-36: `ErrorCode` contains two overlapping “invalid status
transition” codes, so unify `INVALID_STATUS_TRANSITION` and
`INVALID_APPLICATION_STATUS` into a single shared error code. Update the callers
in `Application.transitionTo()` and `ApplicationService.cancel()` to use the
same `ErrorCode` symbol, and remove the duplicate enum entry so clients receive
one consistent code for the same failure case.

In
`@src/main/java/com/ilson/spotwork/domain/application/repository/ApplicationRepository.java`:
- Around line 16-20: The list queries in ApplicationRepository are vulnerable to
N+1 because ApplicationResponse.from() reads application.getJob().getTitle() and
application.getWorker().getNickname() on lazy relations. Update
findByWorkerIdOrderByCreatedAtDesc and findByJobId to fetch the needed
associations eagerly, preferably by adding `@Query` with JOIN FETCH for job and
worker so ApplicationResponse mapping does not trigger per-row extra selects.
- Around line 22-24: The ApplicationRepository interface contains a
commented-out unused method declaration that should be removed rather than left
as dead code. Delete the commented countByJobIdAndStatus repository method and
keep ApplicationRepository limited to actually used repository contracts,
checking for any references before removing it.

In
`@src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java`:
- Around line 82-86: In ApplicationService.accept flow, the 모집인원 초과 check is
duplicated because Job.increaseAcceptedCount already enforces the same limit.
Remove the explicit `job.getAcceptedCount() >=
application.getJob().getHeadcount()` guard in the ApplicationService logic, call
`job.increaseAcceptedCount()` first so it can throw
`CustomException(ErrorCode.JOB_CLOSED)` itself, and only after that succeeds
call `application.transitionTo(ApplicationStatus.ACCEPTED)`; use
`ApplicationService` and `Job.increaseAcceptedCount` as the key locations when
updating the order.
- Around line 132-150: The application list queries in
ApplicationService#getMyApplications and ApplicationService#getApplicants can
trigger N+1 when ApplicationResponse.from touches lazy Application associations.
Update the repository methods used here, especially
ApplicationRepository.findByWorkerIdOrderByCreatedAtDesc and findByJobId, to
fetch the needed relations with JOIN FETCH (or an equivalent entity graph) so
job/worker are loaded in the initial query. Make sure the returned Application
entities already include the associations required by ApplicationResponse.from
to avoid per-row extra queries.
- Around line 58-73: `ApplicationService.apply()`의
`ObjectOptimisticLockingFailureException` catch는 현재 흐름에서 거의 발생하지 않는 방어 코드로 보입니다.
`apply()`에서는 `Job`을 조회만 하고 새 `Application`을 생성해
`applicationRepository.save(...)`로 INSERT하므로 낙관적 락 충돌 대상이 없고, `Application`에
`@Version` 근거도 없습니다. 따라서 이 `try-catch`를 제거하거나, 정말 필요한 의도가 중복 지원 방지라면
`applicationRepository.save` 전에/후에 실제 중복을 감지하는 예외 처리로 바꾸고
`ApplicationService.apply`, `applicationRepository.save`,
`ApplicationResponse.from` 기준으로 흐름을 정리하세요.
- Around line 114-130: The cancel() flow in ApplicationService currently
performs a hard delete via applicationRepository.delete(application), which
removes the application history entirely. Update the logic to use a status-based
cancellation path instead: add a CANCELLED state to ApplicationStatus if needed,
and switch cancel() to transition the Application entity to that state through
its existing status change method (for example, a transitionTo-style domain
method) and persist the update. Keep the worker ownership and PENDING-only
checks in place, and use the ApplicationService, ApplicationStatus, and
ApplicationRepository symbols to locate the affected flow.

In `@src/main/java/com/ilson/spotwork/domain/job/entity/Job.java`:
- Around line 64-65: `Job` 클래스의 `acceptedCount`는 `@Builder`로 생성할 때 필드 초기화가 무시될 수
있으므로, 현재의 `private int acceptedCount = 0;`를 `@Builder.Default`와 함께 사용하도록 수정하세요.
`Job`의 빌더 생성 경로에서 기본값이 항상 유지되도록 `acceptedCount` 선언을 명확히 하고, 나중에 초기값이 변경되어도 빌더가
이를 반영하도록 맞춰주세요.
- Around line 61-73: Existing rows in jobs may break after adding the `@Version`
field and the non-null acceptedCount column in Job. Update the DB migration
(Flyway/Liquibase) to backfill all existing jobs with version = 0 and
acceptedCount = 0 before enforcing NOT NULL/optimistic locking, and ensure the
Job entity’s acceptedCount/default behavior stays aligned with the migration.
🪄 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 Plus

Run ID: ba4c1335-8528-4403-b427-2da5182c1fc3

📥 Commits

Reviewing files that changed from the base of the PR and between 21c2892 and 0d95d74.

📒 Files selected for processing (8)
  • src/main/java/com/ilson/spotwork/common/exception/ErrorCode.java
  • src/main/java/com/ilson/spotwork/domain/application/controller/ApplicationController.java
  • src/main/java/com/ilson/spotwork/domain/application/dto/ApplicationResponse.java
  • src/main/java/com/ilson/spotwork/domain/application/entity/Application.java
  • src/main/java/com/ilson/spotwork/domain/application/entity/ApplicationStatus.java
  • src/main/java/com/ilson/spotwork/domain/application/repository/ApplicationRepository.java
  • src/main/java/com/ilson/spotwork/domain/application/service/ApplicationService.java
  • src/main/java/com/ilson/spotwork/domain/job/entity/Job.java

@kosy00
kosy00 merged commit dab75f8 into develop Jul 27, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 새 기능

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] Application 도메인 구현

1 participant