Skip to content

[FEATURE] 디자이너 대시보드 외주 조회 기능 구현#108

Merged
fervovita merged 5 commits into
devfrom
feat/#103-designer-dashboard
Jul 9, 2026
Merged

[FEATURE] 디자이너 대시보드 외주 조회 기능 구현#108
fervovita merged 5 commits into
devfrom
feat/#103-designer-dashboard

Conversation

@fervovita

@fervovita fervovita commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

🚀 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)
  • 응답 전용 enum AnnouncementResult(대기/선정/미선정) 추가
  • 대시보드 projection/DTO에 역할 구분 위해 Instructor/Designer prefix 적용

📸 Test Evidence

image image image

💬 Reviewer Notes

  • AnnouncementResult

발표 대기 응답은 내부 ApplicationStatus를 그대로 노출하지 않고, 화면에 필요한 3개 값만 AnnouncementResult로 내보냅니다.

발표 대기 외주 API는 AWAITING(대기중) → SELECTED(선정) → NOT_SELECTED(미선정) 순으로 정렬해 내보냅니다.

Summary by CodeRabbit

  • New Features
    • 디자이너 대시보드에서 시안 제출 예정, 발표 대기, 수정 중 커미션을 조회할 수 있도록 API가 추가되었습니다.
    • 역할별 응답 DTO를 분리해, 더 구조화된 커미션 상세 정보를 제공합니다.
  • Bug Fixes
    • 발표 결과 표시를 위한 상태 매핑 로직을 추가해 결과/마감일/제출 여부 정보가 더 정확히 반영됩니다.
  • Tests
    • 강사 대시보드 서비스 테스트가 변경된 응답 구조에 맞게 업데이트되었습니다.

@fervovita fervovita self-assigned this Jul 7, 2026
@fervovita fervovita requested a review from Jong0128 as a code owner July 7, 2026 14:29
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: e370d741-73ab-4626-a763-a0f41c73fce0

📥 Commits

Reviewing files that changed from the base of the PR and between 83a4cfe and cb27ed8.

📒 Files selected for processing (3)
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/enums/AnnouncementResult.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/DashboardCommissionRepository.java
  • src/main/java/ditda/backend/domain/commission/dashboard/service/DesignerDashboardService.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/ditda/backend/domain/commission/dashboard/service/DesignerDashboardService.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/DashboardCommissionRepository.java

📝 Walkthrough

Walkthrough

디자이너 대시보드의 3개 조회 API가 추가되었고, 이를 위한 프로젝션·레포지토리 쿼리·응답 DTO·서비스·컨트롤러가 연결되었다. 동시에 강사 대시보드의 조회 타입들은 Instructor 접두사로 변경되었고, 관련 테스트도 함께 갱신되었다.

Changes

디자이너 대시보드 신규 기능

Layer / File(s) Summary
디자이너 프로젝션 및 레포지토리 쿼리
.../projection/DesignerAnnouncementView.java, .../projection/DesignerDraftSubmissionView.java, .../projection/DesignerRevisingView.java, .../DashboardCommissionRepository.java
디자이너용 조회 프로젝션 인터페이스 3개와 findDesignerDraftSubmissionViews, findDesignerAnnouncementViews, findDesignerRevisingViews 쿼리가 추가되었다.
디자이너 응답 DTO와 결과 매핑
.../dto/response/enums/AnnouncementResult.java, .../DesignerDraftSubmissionCommissionResponse.java, .../DesignerAnnouncementCommissionResponse.java, .../DesignerRevisingCommissionResponse.java
디자이너 조회 결과를 응답 레코드로 변환하는 of/from 매핑과 발표 결과 열거형이 추가되었다.
디자이너 서비스
.../service/DesignerDashboardService.java
세 개의 조회 메서드가 레포지토리 결과를 응답 DTO로 변환하고, 초안 제출 조회에서는 최대 수령액을 계산한다.
디자이너 컨트롤러
.../controller/DesignerDashboardController.java
/draft-submissions, /announcements, /revisions GET 엔드포인트가 추가되었다.

강사 대시보드 Instructor 접두사 리네이밍

Layer / File(s) Summary
강사 프로젝션 및 레포지토리 메서드
.../projection/InstructorDraftSubmissionView.java, .../InstructorMatchingView.java, .../InstructorRevisingView.java, .../DashboardCommissionRepository.java
강사 대시보드 조회 프로젝션과 레포지토리 메서드명이 Instructor 접두사로 변경되었다.
강사 응답 DTO
.../dto/response/InstructorDraftSubmissionCommissionResponse.java, .../InstructorMatchingCommissionResponse.java, .../InstructorRevisingCommissionResponse.java
응답 레코드와 팩토리 메서드의 입력/출력 타입이 새 Instructor 프로젝션에 맞게 바뀌었다.
강사 서비스, 컨트롤러, 테스트
.../service/InstructorDashboardService.java, .../controller/InstructorDashboardController.java, .../test/.../InstructorDashboardServiceTest.java
서비스와 컨트롤러가 새 타입을 사용하도록 갱신되고, 매칭 조회 테스트가 이에 맞게 수정되었다.

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(...)
Loading

Possibly related PRs

Suggested reviewers: Jong0128

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 디자이너 대시보드 외주 조회 기능 추가라는 핵심 변경을 명확하고 간결하게 요약합니다.
Linked Issues check ✅ Passed 링크된 이슈의 3개 조회 API(draft-submissions, announcements, revisions)를 모두 구현했습니다.
Out of Scope Changes check ✅ Passed 인스트럭터 쪽 DTO·프로젝션 정리는 역할 구분을 위한 지원 변경으로 보이며, 주요 범위를 벗어난 변경은 보이지 않습니다.
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/#103-designer-dashboard

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.

🧹 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

maxAmountMapviews의 결합이 느슨하여 잠재적 NPE 위험

maxAmountMap.get(...)null을 반환하면 CommissionItem.from(view, int maxAmount)의 primitive int 언박싱 과정에서 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

📥 Commits

Reviewing files that changed from the base of the PR and between 85b993c and 83a4cfe.

📒 Files selected for processing (19)
  • src/main/java/ditda/backend/domain/commission/dashboard/controller/DesignerDashboardController.java
  • src/main/java/ditda/backend/domain/commission/dashboard/controller/InstructorDashboardController.java
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerAnnouncementCommissionResponse.java
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerDraftSubmissionCommissionResponse.java
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/DesignerRevisingCommissionResponse.java
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/InstructorDraftSubmissionCommissionResponse.java
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/InstructorMatchingCommissionResponse.java
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/InstructorRevisingCommissionResponse.java
  • src/main/java/ditda/backend/domain/commission/dashboard/dto/response/enums/AnnouncementResult.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/DashboardCommissionRepository.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/projection/DesignerAnnouncementView.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/projection/DesignerDraftSubmissionView.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/projection/DesignerRevisingView.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/projection/InstructorDraftSubmissionView.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/projection/InstructorMatchingView.java
  • src/main/java/ditda/backend/domain/commission/dashboard/repository/projection/InstructorRevisingView.java
  • src/main/java/ditda/backend/domain/commission/dashboard/service/DesignerDashboardService.java
  • src/main/java/ditda/backend/domain/commission/dashboard/service/InstructorDashboardService.java
  • src/test/java/ditda/backend/domain/commission/dashboard/service/InstructorDashboardServiceTest.java

@Jong0128 Jong0128 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

수고하셨습니다!
아래 커멘트 확인해주시면 감사하겠습니다 👍

Comment on lines +53 to +56
List<DesignerAnnouncementView> views = dashboardCommissionRepository.findDesignerAnnouncementViews(
designerId,
AnnouncementResult.supportedStatuses()
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

지금 ApplicationStatusPENDING, ASSIGNED, APPLICATION_REJECTED를 조회하여 불러오는 걸로 파악했는데, 사실 PENDING -> ASSIGNED -> DRAFT_SUBMITTED 로 상태가 전이되는데 그러면 시간이 지나면 결국 APPLICATION_REJECTED만 조회되지 않을까요 ㅠㅠ..? 이 부분은 좀 논의가 필요할 꺼 같습니다!

@fervovita fervovita Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

이 부분은 디자인팀에서 발표 결과가 메일함처럼 누적되길 원해서 의도적으로 APPLICATION_REJECTED를 계속 노출하도록 한 것입니다. 그래서 "시간이 지나면 미선정이 쌓인다"는 건 의도된 동작입니다 🙏

다만 짚어주신 부분을 보니, 선정됨(ASSIGNED)은 1차 시안 제출 시 DRAFT_SUBMITTED로 전이되어 메일함에서 빠져나가는 문제점이 있는 것 같습니다.
제가 이해한 바로는, 선정되면 계속 "선정됨"으로 남길 원하는 것 같아서, ASSIGNED, DRAFT_SUBMITTED, DRAFT_MISSED, DRAFT_SELECTED, DRAFT_REJECTED를 모두 "선정됨"으로 하려고 하는데, 어떨까요...?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

넵! 그렇게 하면 좋을꺼같아요! 다만 프론트팀한테도 해당 부분 전달이 필요할꺼같습니다!!

);

// 디자이너 발표 대기 외주: commission + 지원 상태
// ORDER BY CASE 우선순위는 AnnouncementResult 순서와 동기화 필요

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

해당 부분 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()로 선언하여 하면 동일한 로직이지 않을까요?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

결과는 동일합니다!
제가 한 방식은 DB단에서 정렬을 하는 것이고, 제안해주신 방법은 인메모리에서 정렬을 하는 방식입니다.
제가 이렇게 한 이유는 추후 페이지네이션이 들어올 경우, 따로 쿼리를 변경하지 않아도 쉽게 페이지네이션을 적용할 수 있기 때문입니다. 또한, DB에서 정렬을 하기 때문에, 전체 값들을 모두 가져와서 하는것보다 조끔이라도 성능이 좋고요.

그 때, 얘기했듯이 이 부분은 따로 페이지네이션을 당장은 하지 않기로 해서, 실제 페이지네이션을 적용하지는 않았지만, 제 생각에는 메일함처럼 쌓이는 방식이 계속 유지된다면 페이지네이션이 추후에 필요할 것 같기는 합니다...

@fervovita fervovita merged commit 146d2cc into dev Jul 9, 2026
2 checks passed
@fervovita fervovita deleted the feat/#103-designer-dashboard branch July 9, 2026 15:20
@fervovita fervovita mentioned this pull request Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] 디자이너 대시보드 외주 조회 기능 구현

2 participants