[FEATURE] 외주 상세 정보 조회 기능 구현#65
Conversation
📝 WalkthroughWalkthrough외주 상세 조회 API( Changes외주 상세 조회 기능
Sequence Diagram(s)sequenceDiagram
participant Client
participant CommissionController
participant CommissionFacade
participant CommissionService
participant DesignerService
participant CommissionDetailMapper
participant S3PresignedUrlGenerator
Client->>CommissionController: GET /api/v1/commissions/{commissionId}
CommissionController->>CommissionFacade: getCommissionDetail(userId, commissionId)
CommissionFacade->>CommissionService: getDetail(commissionId)
CommissionService-->>CommissionFacade: CommissionDetail
CommissionFacade->>DesignerService: findById(userId) [DESIGNER인 경우]
CommissionFacade->>CommissionFacade: getPriceDetail(categoryType, level)
CommissionFacade->>CommissionDetailMapper: toResponse(detail, priceDetail)
CommissionDetailMapper->>S3PresignedUrlGenerator: generatePrivateGetUrl(file)
S3PresignedUrlGenerator-->>CommissionDetailMapper: presigned URL
CommissionDetailMapper-->>CommissionFacade: CommissionDetailResponse
CommissionFacade-->>CommissionController: CommissionDetailResponse
CommissionController-->>Client: ApiResponse
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
|
@coderabbitai review |
✅ Action performedReview finished.
|
4584a79 to
3b1ee45
Compare
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/main/java/ditda/backend/domain/commission/core/dto/response/CommissionDetailResponse.java (1)
33-43: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win실제 응답 계약이 OpenAPI 스키마에 충분히 드러나지 않을 수 있습니다.
이 필드는 런타임에
categoryDetail은 카테고리별 구체 DTO가 내려가고,priceInfo는 역할에 따라null이 됩니다. 지금 선언만으로는 generated OpenAPI가oneOf/nullable을 놓쳐서 SDK 생성이나 스키마 검증이 실제 응답과 어긋날 수 있으니, 필드/인터페이스 쪽에 이를 명시하는 편이 안전합니다.🤖 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/core/dto/response/CommissionDetailResponse.java` around lines 33 - 43, The OpenAPI annotations on CommissionDetailResponse do not fully describe the runtime response shape, so update the schema metadata for categoryDetail and priceInfo to reflect the actual contract. Mark categoryDetail as a polymorphic field using the concrete category DTO variants via oneOf (or equivalent interface-level schema metadata), and mark priceInfo as nullable since it can be null by role. Use the existing CommissionDetailResponse, CategoryDetailResponse, and PriceInfo symbols to place the schema hints where the generated OpenAPI will pick them up.
🤖 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/ditda/backend/domain/commission/category/textbook/handler/TextbookCategoryHandler.java`:
- Around line 74-77: `TextbookCategoryHandler.loadDetail` currently throws
`IllegalStateException` when `textbookRepository.findById(commissionId)` returns
empty, which bypasses the domain error handling used elsewhere. Update this path
to throw `GeneralException` with the appropriate not-found error code/message so
`CommissionService`-style exception handling is consistent and the missing
category detail is treated as a domain exception.
In
`@src/main/java/ditda/backend/domain/commission/core/mapper/CommissionDetailMapper.java`:
- Around line 74-81: `CommissionDetailMapper`의 그룹핑 로직에서 같은 `FileKind`를
`groupedFiles`로 묶은 뒤 `getFirst()`의 `description`만 사용해 나머지 파일 설명이 사라지고 있습니다.
`CommissionCreateRequest.FileInfo`와 `FileInfo` 생성 흐름을 기준으로, 응답이 파일 단위 설명을 유지하도록
`map(...)`에서 각 파일의 description을 보존해 반환하거나, `groupedFiles`를 만들기 전에 `FileKind`당 단일
description만 허용하도록 저장/검증 로직을 정리하세요.
In
`@src/main/java/ditda/backend/domain/commission/core/service/CommissionService.java`:
- Around line 47-48: `CommissionService`의 `handler.loadDetail(commissionId)`
경로에서 카테고리별 구현이 던지는 예외가 그대로 밖으로 노출되고 있으니, `CommissionCategoryHandler` 계약에 맞게 도메인
예외로 통일하세요. 특히 `resolve(...)`로 얻은 `handler`가 `TextbookCategoryHandler`처럼
`IllegalStateException`을 던질 수 있는 경우를 `GeneralException`/`CommissionErrorCode` 기반
예외로 변환하거나, 각 handler 구현에서 동일한 도메인 예외를 던지도록 맞춰서 `loadDetail` 호출부가 일관된 응답을 반환하게
하세요.
---
Nitpick comments:
In
`@src/main/java/ditda/backend/domain/commission/core/dto/response/CommissionDetailResponse.java`:
- Around line 33-43: The OpenAPI annotations on CommissionDetailResponse do not
fully describe the runtime response shape, so update the schema metadata for
categoryDetail and priceInfo to reflect the actual contract. Mark categoryDetail
as a polymorphic field using the concrete category DTO variants via oneOf (or
equivalent interface-level schema metadata), and mark priceInfo as nullable
since it can be null by role. Use the existing CommissionDetailResponse,
CategoryDetailResponse, and PriceInfo symbols to place the schema hints where
the generated OpenAPI will pick them up.
🪄 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: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 922e98d8-ebe6-4cf6-880f-7d2bf467d31e
📒 Files selected for processing (18)
src/main/java/ditda/backend/domain/commission/category/textbook/dto/TextbookCategoryDetail.javasrc/main/java/ditda/backend/domain/commission/category/textbook/dto/response/TextbookDetailResponse.javasrc/main/java/ditda/backend/domain/commission/category/textbook/handler/TextbookCategoryHandler.javasrc/main/java/ditda/backend/domain/commission/category/textbook/repository/TextbookPageRepository.javasrc/main/java/ditda/backend/domain/commission/core/controller/CommissionController.javasrc/main/java/ditda/backend/domain/commission/core/dto/CommissionDetail.javasrc/main/java/ditda/backend/domain/commission/core/dto/response/CategoryDetailResponse.javasrc/main/java/ditda/backend/domain/commission/core/dto/response/CommissionDetailResponse.javasrc/main/java/ditda/backend/domain/commission/core/facade/CommissionFacade.javasrc/main/java/ditda/backend/domain/commission/core/handler/CategoryDetail.javasrc/main/java/ditda/backend/domain/commission/core/handler/CommissionCategoryHandler.javasrc/main/java/ditda/backend/domain/commission/core/mapper/CommissionDetailMapper.javasrc/main/java/ditda/backend/domain/commission/core/repository/CommissionColorRepository.javasrc/main/java/ditda/backend/domain/commission/core/repository/CommissionConceptRepository.javasrc/main/java/ditda/backend/domain/commission/core/repository/CommissionFileRepository.javasrc/main/java/ditda/backend/domain/commission/core/service/CommissionService.javasrc/main/java/ditda/backend/domain/designer/exception/DesignerErrorCode.javasrc/main/java/ditda/backend/domain/designer/service/DesignerService.java
…tails # Conflicts: # src/main/java/ditda/backend/domain/designer/exception/DesignerErrorCode.java # src/main/java/ditda/backend/domain/designer/service/DesignerService.java
Jong0128
left a comment
There was a problem hiding this comment.
수고하셨습니다!
따로 커멘트는 없습니다!!
다만, 마지막으로 커밋한거 확인해주시고 merge 해주시면 감사하겠습니다 👍
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/java/ditda/backend/domain/commission/core/dto/response/CommissionListResponse.java (1)
33-36: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value
priceDetails에 매핑이 없을 경우 NPE 가능성에 유의하세요.
priceDetails.get(c.getId())가null을 반환하면CommissionResponse.from내부의priceDetail.baseAmount()호출에서 NPE가 발생합니다. 현재 호출부(DesignerCommissionFacade)에서는 동일한 커미션 목록으로 맵을 구성하므로 안전하지만, 호출부가 바뀌면 깨지기 쉬운 암묵적 결합입니다. 향후 재사용을 대비해 누락 시 방어 처리를 고려해 보세요.Also applies to: 69-77
🤖 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/core/dto/response/CommissionListResponse.java` around lines 33 - 36, `CommissionListResponse.from` currently assumes `priceDetails.get(c.getId())` is always present, which can propagate null into `CommissionResponse.from` and cause an NPE. Update the mapping in `CommissionListResponse.from` (and any similar `from`/factory path used by `CommissionResponse`) to handle missing `PriceDetail` defensively, either by skipping, defaulting, or explicitly validating with a clear error before calling `CommissionResponse.from`. Keep the behavior consistent with the current `DesignerCommissionFacade` usage but make the DTO conversion safe for future callers.
🤖 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/core/dto/response/CommissionListResponse.java`:
- Around line 33-36: `CommissionListResponse.from` currently assumes
`priceDetails.get(c.getId())` is always present, which can propagate null into
`CommissionResponse.from` and cause an NPE. Update the mapping in
`CommissionListResponse.from` (and any similar `from`/factory path used by
`CommissionResponse`) to handle missing `PriceDetail` defensively, either by
skipping, defaulting, or explicitly validating with a clear error before calling
`CommissionResponse.from`. Keep the behavior consistent with the current
`DesignerCommissionFacade` usage but make the DTO conversion safe for future
callers.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 8ff77a20-9975-4cff-b3b2-c6e32870ec51
📒 Files selected for processing (7)
src/main/java/ditda/backend/domain/commission/core/dto/PriceDetail.javasrc/main/java/ditda/backend/domain/commission/core/dto/response/CommissionDetailResponse.javasrc/main/java/ditda/backend/domain/commission/core/dto/response/CommissionListResponse.javasrc/main/java/ditda/backend/domain/commission/core/facade/CommissionFacade.javasrc/main/java/ditda/backend/domain/commission/core/facade/DesignerCommissionFacade.javasrc/main/java/ditda/backend/domain/commission/core/mapper/CommissionDetailMapper.javasrc/main/java/ditda/backend/domain/commission/core/policy/CommissionPricePolicy.java
🚧 Files skipped from review as they are similar to previous changes (2)
- src/main/java/ditda/backend/domain/commission/core/facade/CommissionFacade.java
- src/main/java/ditda/backend/domain/commission/core/mapper/CommissionDetailMapper.java
|
@Jong0128 한번만 확인 부탁드립니다! |
@fervovita |
🚀 Related issue
Closes #53
#️⃣ Summary
GET /api/v1/commissions/{commissionId}API 구현🔧 Changes
GET /api/v1/commissions/{commissionId})📸 Test Evidence
💬 Reviewer Notes
Spring Boot에서 sealed interface는 같은 패키지 내의 구현체만 permits할 수 있습니다.
CategoryDetail은commission/core/handler에,TextbookCategoryDetail은commission/category/textbook/dto에 위치하여 패키지가 다르므로 sealed를 사용할 수 없었습니다.대신 일반 interface + instanceof 패턴 매칭으로 구현했으며, 이로 인해 textbook 패키지에 대한 의존성이 존재합니다.
CommissionCreateRequest에 현재 textbook만 받도록 하드코딩되어 있는데, 이 부분의 적용은 이 PR의 범위를 벗어나 수정하지 않았습니다.각 카테고리마다 상세 정보가 다르므로,
CategoryDetail.toResponse()를 통해 각 카테고리 핸들러가 각자 다른 응답 구조를 반환하도록 구현했습니다. 새 카테고리 추가 시CategoryDetail구현체와CategoryDetailResponse구현체만 추가하면 됩니다.현재
@AuthenticationPrincipal에userId만 포함되어 있어,UserRole까지 추가하려면 인증 구조 변경과 함께 모든 API의 시그니처를 수정해야 합니다. 이 영향 범위가 너무 커서,UserService.findById()로 역할을 조회하는 방식으로 구현했습니다.Summary by CodeRabbit
New Features
Bug Fixes