[FEAT] 사용자 프로필 조회 및 관리 API 구현 - #47
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough인증 사용자의 프로필 조회·온보딩 등록·수정 API가 추가되었습니다. 관련 DTO, 저장소, 오류 상태, 사용자 통계 조합, PIANO 악기 시딩 및 컨트롤러 테스트가 함께 구현되었습니다. Changes사용자 프로필 관리
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant UserProfileController
participant UserProfileService
participant UserRepository
participant StudentRepository
participant SubscriptionRepository
Client->>UserProfileController: GET/POST/PATCH /api/users/me/profile
UserProfileController->>UserProfileService: 프로필 요청 DTO 전달
UserProfileService->>UserRepository: 사용자 조회·닉네임 중복 확인
UserProfileService->>StudentRepository: 학생 조회 또는 생성
UserProfileService->>SubscriptionRepository: 활성 구독 조회 또는 생성
UserProfileService-->>UserProfileController: 프로필 응답 DTO 반환
UserProfileController-->>Client: ApiResponse 반환
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 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.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/main/java/com/mr/domain/user/service/UserProfileService.java (1)
46-49: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win미결정 예외는
GeneralException+BaseCode패턴으로 전환해 주세요.
getUser,getStudent,ensureNicknameNotTaken는 잘못된 요청 상태를ERROR_XXX코드와 HTTP 상태 기반으로 처리하므로, 대표 악기/구독 정보/PIANO 시드 미존재 역시 동일하게 처리해 주세요.IllegalStateException은 전역Exception예외 핸들러로 내려가 일관되지 않은 500 응답이 됩니다.UserErrorStatus또는StudentErrorStatus에 각 사례에 맞는 신규 코드를 추가하고getMyProfile()/onboarding 경로의orElseThrow에서new GeneralException(...)로 연결해 주세요. (예: 대표 악기 미존재 →STUDENT_NOT_FOUND를 재사용하거나 별도 코드를 추가하는 것이 적절합니다.)🤖 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/mr/domain/user/service/UserProfileService.java` around lines 46 - 49, Replace the IllegalStateException fallbacks in UserProfileService.getMyProfile() and the onboarding path at UserProfileService lines 46-49, 51-53, and 79-80 with GeneralException using the appropriate UserErrorStatus or StudentErrorStatus BaseCode. Add dedicated error codes where needed, or reuse STUDENT_NOT_FOUND for missing representative instrument, subscription, and PIANO seed cases, while preserving each existing orElseThrow condition.
🤖 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/mr/domain/subscriptions/repository/SubscriptionRepository.java`:
- Line 10: Update SubscriptionRepository.findFirstByUserOrderByStartDateDesc to
filter for currently active subscriptions according to Subscription.isActive(),
rather than returning expired history; then update
UserProfileService.getMyProfile() to call the new active-subscription query
while preserving the existing latest-start-date ordering.
In `@src/main/java/com/mr/domain/user/config/InstrumentSeeder.java`:
- Around line 23-24: Update InstrumentSeeder’s PIANO seeding flow to be safe
across concurrent application instances: enforce a database-level unique
constraint on Instrument.code and use an idempotent duplicate-key-ignore or
database-native upsert approach instead of the current findByCode/orElseGet
check-then-act pattern. Preserve successful retrieval or creation of the single
PIANO instrument.
In `@src/main/java/com/mr/domain/user/repository/UserRepository.java`:
- Around line 6-10: Merge the duplicate UserRepository definitions before
integration by removing the empty counterpart and retaining a single repository
interface with the existsByNicknameAndUserIdNot method. Ensure the resulting
UserRepository keeps the JpaRepository<User, Long> contract and avoids duplicate
FQCN definitions.
In `@src/main/java/com/mr/domain/user/service/UserProfileService.java`:
- Around line 74-75: In UserProfileService, update both registerProfile (lines
74-75) and updateProfile (lines 104-106) to validate nickname availability with
ensureNicknameNotTaken before calling user.updateNickname(request.nickname()).
Preserve the existing NICKNAME_DUPLICATED business exception behavior and apply
the same ordering at both sites.
- Around line 65-96: Update registerProfile to finalize onboarding only after
Student, primary StudentInstrument, and Subscription creation succeeds: if
onboarding state is stored as a User flag, call user.completeOnboarding() before
the transaction completes; otherwise check for an existing Student by user and
throw ONBOARDING_ALREADY_COMPLETED before creating duplicates. Preserve the
existing initial onboarding guard and ensure the successful path synchronizes
the User onboarding state with the Student relationship.
---
Nitpick comments:
In `@src/main/java/com/mr/domain/user/service/UserProfileService.java`:
- Around line 46-49: Replace the IllegalStateException fallbacks in
UserProfileService.getMyProfile() and the onboarding path at UserProfileService
lines 46-49, 51-53, and 79-80 with GeneralException using the appropriate
UserErrorStatus or StudentErrorStatus BaseCode. Add dedicated error codes where
needed, or reuse STUDENT_NOT_FOUND for missing representative instrument,
subscription, and PIANO seed cases, while preserving each existing orElseThrow
condition.
🪄 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.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 05a8619f-ae4d-440c-ae53-a2425110257c
📒 Files selected for processing (14)
src/main/java/com/mr/domain/statistics/repository/UserStatisticsRepository.javasrc/main/java/com/mr/domain/subscriptions/entity/enums/SubscriptionTier.javasrc/main/java/com/mr/domain/subscriptions/repository/SubscriptionRepository.javasrc/main/java/com/mr/domain/user/config/InstrumentSeeder.javasrc/main/java/com/mr/domain/user/controller/UserProfileController.javasrc/main/java/com/mr/domain/user/dto/UserProfileRequestDTO.javasrc/main/java/com/mr/domain/user/dto/UserProfileResponseDTO.javasrc/main/java/com/mr/domain/user/exception/StudentErrorStatus.javasrc/main/java/com/mr/domain/user/exception/UserErrorStatus.javasrc/main/java/com/mr/domain/user/repository/InstrumentRepository.javasrc/main/java/com/mr/domain/user/repository/StudentInstrumentRepository.javasrc/main/java/com/mr/domain/user/repository/StudentRepository.javasrc/main/java/com/mr/domain/user/repository/UserRepository.javasrc/main/java/com/mr/domain/user/service/UserProfileService.java
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/mr/domain/user/config/InstrumentSeeder.java`:
- Around line 26-36: InstrumentSeeder의 중복 시드 처리에서
DataIntegrityViolationException을 save 호출 내부에만 의존하지 말고, 실제 DB flush/commit 경계에서
예외가 발생하도록 트랜잭션 경계를 분리하세요. 시드 저장 작업을 별도 트랜잭션 메서드로 이동하거나 호출해 saveAndFlush()로 즉시
반영하고, 바깥 흐름에서 해당 예외를 잡아 기존처럼 경쟁 인스턴스의 중복 삽입을 무시하도록 수정하세요.
🪄 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.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 57c7a686-182b-4504-9482-aa822af6daf2
📒 Files selected for processing (4)
src/main/java/com/mr/domain/subscriptions/repository/SubscriptionRepository.javasrc/main/java/com/mr/domain/user/config/InstrumentSeeder.javasrc/main/java/com/mr/domain/user/service/UserProfileService.javasrc/test/java/com/mr/domain/user/controller/UserProfileControllerTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/com/mr/domain/user/service/UserProfileService.java
📍 개요
⛓️💥 관련 이슈
🛠️ 작업 내용
GET /api/users/me/profile프로필 조회 API 구현 (닉네임/프로필이미지/악기/숙련도/구독등급/누적 통계)POST /api/users/me/profile프로필 최초 등록(온보딩) API 구현— User/Student/StudentInstrument/Subscription 생성을 하나의 트랜잭션으로 처리
PATCH /api/users/me/profile프로필 수정 API 구현 (닉네임/화성학 숙련도)UserErrorStatus/StudentErrorStatus에 신규 에러 코드 4개 추가(
USER_404_01,USER_409_01,USER_409_02,STUDENT_404_01)InstrumentSeeder추가🔥 리뷰 요청 사항
completedLearningCount는 동균 강님의feat/#32-learning-status-api병합 전까지0으로 고정해뒀습니다(TODO 주석 남김). 병합 후 실제 집계 쿼리로 교체 예정인데, 이 방식으로 우선 진행해도 괜찮을지 확인 부탁드려요.SecurityUtil.getCurrentUserId()를 그대로 재사용했습니다.✅ 체크리스트
📎 참고 사항
소셜 로그인/회원가입 시 등록되는 값이기에 아직 미구현으로
유저에게 기본 이미지가 실제로 적용되는지는 이번 PR 범위에서 검증하지 못했습니다.
해당 필터 아직 구현 전이라 지금은 별도 조치가 없습니다. 필터 구현 시 조율 필요합니다.
> 정리 했어용UserRepository/UserErrorStatus의USER_NOT_FOUND는동균님의 미병합 브랜치(
feat/#32-learning-status-api, PR [FEAT] 학습 도메인 api 기본 구현 #46)에도 동일하게 추가되어 있어서 그쪽이 먼저 머지되면 병합 시 사소한 정리가 필요할 수 있습니다.테스트는 일단 PR 올리고 추후 진행할 예정입니다> 했어용Summary by CodeRabbit