[FEATURE] 디자이너 대시보드 외주 조회 기능 구현#108
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthrough디자이너 대시보드의 3개 조회 API가 추가되었고, 이를 위한 프로젝션·레포지토리 쿼리·응답 DTO·서비스·컨트롤러가 연결되었다. 동시에 강사 대시보드의 조회 타입들은 Instructor 접두사로 변경되었고, 관련 테스트도 함께 갱신되었다. Changes디자이너 대시보드 신규 기능
강사 대시보드 Instructor 접두사 리네이밍
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant DesignerDashboardController
participant DesignerDashboardService
participant DashboardCommissionRepository
participant CommissionPricePolicy
Client->>DesignerDashboardController: GET /draft-submissions
DesignerDashboardController->>DesignerDashboardService: getDraftSubmissions(designerId)
DesignerDashboardService->>DashboardCommissionRepository: findDesignerDraftSubmissionViews(designerId)
DashboardCommissionRepository-->>DesignerDashboardService: List<DesignerDraftSubmissionView>
DesignerDashboardService->>CommissionPricePolicy: calculateFinalPayout(category, level)
CommissionPricePolicy-->>DesignerDashboardService: maxAmount
DesignerDashboardService-->>DesignerDashboardController: DesignerDraftSubmissionCommissionResponse
DesignerDashboardController-->>Client: ApiResponse.onSuccess(...)
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/main/java/ditda/backend/domain/commission/dashboard/repository/DashboardCommissionRepository.java (1)
84-101: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win정렬 우선순위와
AnnouncementResult매핑 간 중복 동기화 위험.
ORDER BY CASE우선순위(PENDING=0, ASSIGNED=1, APPLICATION_REJECTED=2)가AnnouncementResult.MAPPING의 순서와 별개로 하드코딩되어 있습니다. 주석에도 "동기화 필요"라고 명시되어 있는데, 향후 상태가 추가/변경될 때 두 곳 중 한 곳만 수정되면 정렬 순서와 응답 값이 어긋날 수 있습니다.정렬을 DB 쿼리 대신 서비스 계층에서
AnnouncementResult의 ordinal 기준Comparator로 처리하면 단일 소스로 관리할 수 있습니다.♻️ 정렬 로직을 서비스 계층으로 이전하는 예시
`@Query`("SELECT c AS commission, ca.status AS applicationStatus " + "FROM CommissionApplication ca " + "JOIN ca.commission c " + "WHERE ca.designer.id = :designerId " + "AND ca.status IN :applicationStatuses " - + "ORDER BY " - + "CASE " - + "WHEN ca.status = ApplicationStatus.PENDING THEN 0 " - + "WHEN ca.status = ApplicationStatus.ASSIGNED THEN 1 " - + "WHEN ca.status = ApplicationStatus.APPLICATION_REJECTED THEN 2 " - + "ELSE 3 END, " + "c.applicationDeadline ASC") List<DesignerAnnouncementView> findDesignerAnnouncementViews(그리고 서비스에서
AnnouncementResult.from(view.getApplicationStatus()).ordinal()기준으로 재정렬합니다.🤖 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/ditda/backend/domain/commission/dashboard/repository/DashboardCommissionRepository.java` around lines 84 - 101, The sorting priority in findDesignerAnnouncementViews is duplicated and hardcoded in the query, which can drift from AnnouncementResult mapping order. Move the ordering responsibility out of the `@Query` on DashboardCommissionRepository and sort the returned DesignerAnnouncementView list in the service layer using AnnouncementResult.from(...), so the priority is managed from a single source and stays aligned when statuses change.src/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerDraftSubmissionCommissionResponse.java (1)
21-30: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value
maxAmountMap과views의 결합이 느슨하여 잠재적 NPE 위험
maxAmountMap.get(...)이null을 반환하면CommissionItem.from(view, int maxAmount)의 primitiveint언박싱 과정에서 NPE가 발생합니다. 현재는DesignerDashboardService가 동일한views로부터 map을 구성하므로 실제 문제는 없지만, 두 값이 별도로 전달되는 구조는 향후 리팩터링 시 깨지기 쉽습니다.Map.getOrDefault(id, 0)을 사용하거나, view와 maxAmount를 하나의 튜플/레코드로 묶어 전달하는 방식을 고려해보세요.💡 방어적 코드 제안
List<CommissionItem> items = views.stream() - .map(view -> CommissionItem.from(view, maxAmountMap.get(view.getCommission().getId()))) + .map(view -> CommissionItem.from(view, maxAmountMap.getOrDefault(view.getCommission().getId(), 0))) .toList();🤖 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/ditda/backend/domain/commission/dashboard/dto/response/DesignerDraftSubmissionCommissionResponse.java` around lines 21 - 30, The nullable lookup in DesignerDraftSubmissionCommissionResponse.of can unbox to a primitive int inside CommissionItem.from and throw an NPE if maxAmountMap does not contain the commission id. Update the mapping in of to use a safe default such as getOrDefault for the commission id, or refactor the API so each DesignerDraftSubmissionView is paired with its max amount before calling CommissionItem.from, keeping the coupling explicit and avoiding null-driven unboxing.
🤖 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.
Nitpick comments:
In
`@src/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerDraftSubmissionCommissionResponse.java`:
- Around line 21-30: The nullable lookup in
DesignerDraftSubmissionCommissionResponse.of can unbox to a primitive int inside
CommissionItem.from and throw an NPE if maxAmountMap does not contain the
commission id. Update the mapping in of to use a safe default such as
getOrDefault for the commission id, or refactor the API so each
DesignerDraftSubmissionView is paired with its max amount before calling
CommissionItem.from, keeping the coupling explicit and avoiding null-driven
unboxing.
In
`@src/main/java/ditda/backend/domain/commission/dashboard/repository/DashboardCommissionRepository.java`:
- Around line 84-101: The sorting priority in findDesignerAnnouncementViews is
duplicated and hardcoded in the query, which can drift from AnnouncementResult
mapping order. Move the ordering responsibility out of the `@Query` on
DashboardCommissionRepository and sort the returned DesignerAnnouncementView
list in the service layer using AnnouncementResult.from(...), so the priority is
managed from a single source and stays aligned when statuses change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: d56c25dc-df9a-456d-995f-34eb8482913a
📒 Files selected for processing (19)
src/main/java/ditda/backend/domain/commission/dashboard/controller/DesignerDashboardController.javasrc/main/java/ditda/backend/domain/commission/dashboard/controller/InstructorDashboardController.javasrc/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerAnnouncementCommissionResponse.javasrc/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerDraftSubmissionCommissionResponse.javasrc/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerRevisingCommissionResponse.javasrc/main/java/ditda/backend/domain/commission/dashboard/dto/response/InstructorDraftSubmissionCommissionResponse.javasrc/main/java/ditda/backend/domain/commission/dashboard/dto/response/InstructorMatchingCommissionResponse.javasrc/main/java/ditda/backend/domain/commission/dashboard/dto/response/InstructorRevisingCommissionResponse.javasrc/main/java/ditda/backend/domain/commission/dashboard/dto/response/enums/AnnouncementResult.javasrc/main/java/ditda/backend/domain/commission/dashboard/repository/DashboardCommissionRepository.javasrc/main/java/ditda/backend/domain/commission/dashboard/repository/projection/DesignerAnnouncementView.javasrc/main/java/ditda/backend/domain/commission/dashboard/repository/projection/DesignerDraftSubmissionView.javasrc/main/java/ditda/backend/domain/commission/dashboard/repository/projection/DesignerRevisingView.javasrc/main/java/ditda/backend/domain/commission/dashboard/repository/projection/InstructorDraftSubmissionView.javasrc/main/java/ditda/backend/domain/commission/dashboard/repository/projection/InstructorMatchingView.javasrc/main/java/ditda/backend/domain/commission/dashboard/repository/projection/InstructorRevisingView.javasrc/main/java/ditda/backend/domain/commission/dashboard/service/DesignerDashboardService.javasrc/main/java/ditda/backend/domain/commission/dashboard/service/InstructorDashboardService.javasrc/test/java/ditda/backend/domain/commission/dashboard/service/InstructorDashboardServiceTest.java
Jong0128
left a comment
There was a problem hiding this comment.
수고하셨습니다!
아래 커멘트 확인해주시면 감사하겠습니다 👍
| List<DesignerAnnouncementView> views = dashboardCommissionRepository.findDesignerAnnouncementViews( | ||
| designerId, | ||
| AnnouncementResult.supportedStatuses() | ||
| ); |
There was a problem hiding this comment.
지금 ApplicationStatus가 PENDING, ASSIGNED, APPLICATION_REJECTED를 조회하여 불러오는 걸로 파악했는데, 사실 PENDING -> ASSIGNED -> DRAFT_SUBMITTED 로 상태가 전이되는데 그러면 시간이 지나면 결국 APPLICATION_REJECTED만 조회되지 않을까요 ㅠㅠ..? 이 부분은 좀 논의가 필요할 꺼 같습니다!
There was a problem hiding this comment.
이 부분은 디자인팀에서 발표 결과가 메일함처럼 누적되길 원해서 의도적으로 APPLICATION_REJECTED를 계속 노출하도록 한 것입니다. 그래서 "시간이 지나면 미선정이 쌓인다"는 건 의도된 동작입니다 🙏
다만 짚어주신 부분을 보니, 선정됨(ASSIGNED)은 1차 시안 제출 시 DRAFT_SUBMITTED로 전이되어 메일함에서 빠져나가는 문제점이 있는 것 같습니다.
제가 이해한 바로는, 선정되면 계속 "선정됨"으로 남길 원하는 것 같아서, ASSIGNED, DRAFT_SUBMITTED, DRAFT_MISSED, DRAFT_SELECTED, DRAFT_REJECTED를 모두 "선정됨"으로 하려고 하는데, 어떨까요...?
There was a problem hiding this comment.
넵! 그렇게 하면 좋을꺼같아요! 다만 프론트팀한테도 해당 부분 전달이 필요할꺼같습니다!!
| ); | ||
|
|
||
| // 디자이너 발표 대기 외주: commission + 지원 상태 | ||
| // ORDER BY CASE 우선순위는 AnnouncementResult 순서와 동기화 필요 |
There was a problem hiding this comment.
해당 부분 AnnouncementResult 순서와 동기화 보다는 repository에서는
// CASE 삭제 후
+ "WHERE ca.designer.id = :designerId "
+ "AND ca.status IN :applicationStatuses "
+ "ORDER BY c.applicationDeadline ASC"
하고 DesignerAnnouncementCommissionResponse에서
public static DesignerAnnouncementCommissionResponse of(List<DesignerAnnouncementView> views) {
List<CommissionItem> items = views.stream()
.map(CommissionItem::from)
.sorted(Comparator.comparing(item -> item.status().ordinal()))
.toList();
return new DesignerAnnouncementCommissionResponse(items);
}
ordinal()로 선언하여 하면 동일한 로직이지 않을까요?
There was a problem hiding this comment.
결과는 동일합니다!
제가 한 방식은 DB단에서 정렬을 하는 것이고, 제안해주신 방법은 인메모리에서 정렬을 하는 방식입니다.
제가 이렇게 한 이유는 추후 페이지네이션이 들어올 경우, 따로 쿼리를 변경하지 않아도 쉽게 페이지네이션을 적용할 수 있기 때문입니다. 또한, DB에서 정렬을 하기 때문에, 전체 값들을 모두 가져와서 하는것보다 조끔이라도 성능이 좋고요.
그 때, 얘기했듯이 이 부분은 따로 페이지네이션을 당장은 하지 않기로 해서, 실제 페이지네이션을 적용하지는 않았지만, 제 생각에는 메일함처럼 쌓이는 방식이 계속 유지된다면 페이지네이션이 추후에 필요할 것 같기는 합니다...
🚀 Related issue
Closes #103
#️⃣ Summary
🔧 Changes
GET /api/v1/designers/dashboards/draft-submissions)GET /api/v1/designers/dashboards/announcements)GET /api/v1/designers/dashboards/revisions)AnnouncementResult(대기/선정/미선정) 추가📸 Test Evidence
💬 Reviewer Notes
AnnouncementResult발표 대기 응답은 내부
ApplicationStatus를 그대로 노출하지 않고, 화면에 필요한 3개 값만AnnouncementResult로 내보냅니다.발표 대기 외주 API는
AWAITING(대기중) →SELECTED(선정) →NOT_SELECTED(미선정) 순으로 정렬해 내보냅니다.Summary by CodeRabbit