From 8ef0885489d91a17063066f07fcb41711d98378d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EA=B2=BD=EC=88=98?= Date: Mon, 9 Feb 2026 16:34:41 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix(#341):=20qa=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RealMatch/user/application/service/UserService.java | 8 +++++++- .../domain/repository/UserMatchingDetailRepository.java | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/RealMatch/user/application/service/UserService.java b/src/main/java/com/example/RealMatch/user/application/service/UserService.java index 1ebf94fa..13e31c1e 100644 --- a/src/main/java/com/example/RealMatch/user/application/service/UserService.java +++ b/src/main/java/com/example/RealMatch/user/application/service/UserService.java @@ -62,6 +62,11 @@ public MyProfileCardResponseDto getMyProfileCard(Long userId) { throw new CustomException(UserErrorCode.PROFILE_CARD_NOT_FOUND); } + // 프로필 카드 정보가 없는 경우 예외 처리 + if (!userMatchingDetailRepository.existsByUserIdAndIsDeprecatedFalse(userId)) { + throw new CustomException(UserErrorCode.PROFILE_CARD_NOT_FOUND); + } + UserMatchingDetail detail = userMatchingDetailRepository .findByUserIdAndIsDeprecatedFalse(userId) .orElseThrow(() -> new CustomException(UserErrorCode.USER_MATCHING_DETAIL_NOT_FOUND)); @@ -79,7 +84,8 @@ public MyScrapResponseDto getMyScrap(Long userId, String type, String sort) { // .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); // 내 찜 조회를 볼 자격이 있는지 확인 - if (user.getRole() == Role.GUEST || !matchCampaignHistoryRepository.existsByUserId(userId)) { + if (user.getRole() == Role.GUEST || + !userMatchingDetailRepository.existsByUserIdAndIsDeprecatedFalse(userId)) { throw new CustomException(UserErrorCode.SCRAP_NOT_FOUND); } diff --git a/src/main/java/com/example/RealMatch/user/domain/repository/UserMatchingDetailRepository.java b/src/main/java/com/example/RealMatch/user/domain/repository/UserMatchingDetailRepository.java index 4902760f..fec52787 100644 --- a/src/main/java/com/example/RealMatch/user/domain/repository/UserMatchingDetailRepository.java +++ b/src/main/java/com/example/RealMatch/user/domain/repository/UserMatchingDetailRepository.java @@ -8,4 +8,6 @@ public interface UserMatchingDetailRepository extends JpaRepository { Optional findByUserIdAndIsDeprecatedFalse(Long userId); + + boolean existsByUserIdAndIsDeprecatedFalse(Long userId); } From de3c1f7ea259cd35e0deb3e53ca66ac6403c21e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EA=B2=BD=EC=88=98?= Date: Tue, 10 Feb 2026 01:12:05 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix(#341):=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Conflicts: # src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java --- .../user/application/service/UserService.java | 42 +++----- .../user/presentation/code/UserErrorCode.java | 99 ++----------------- 2 files changed, 20 insertions(+), 121 deletions(-) diff --git a/src/main/java/com/example/RealMatch/user/application/service/UserService.java b/src/main/java/com/example/RealMatch/user/application/service/UserService.java index 13e31c1e..cf992638 100644 --- a/src/main/java/com/example/RealMatch/user/application/service/UserService.java +++ b/src/main/java/com/example/RealMatch/user/application/service/UserService.java @@ -13,7 +13,6 @@ import com.example.RealMatch.user.domain.entity.UserContentCategory; import com.example.RealMatch.user.domain.entity.UserMatchingDetail; import com.example.RealMatch.user.domain.entity.enums.AuthProvider; -import com.example.RealMatch.user.domain.entity.enums.Role; import com.example.RealMatch.user.domain.repository.AuthenticationMethodRepository; import com.example.RealMatch.user.domain.repository.UserContentCategoryRepository; import com.example.RealMatch.user.domain.repository.UserMatchingDetailRepository; @@ -55,18 +54,11 @@ public MyPageResponseDto getMyPage(Long userId) { } public MyProfileCardResponseDto getMyProfileCard(Long userId) { + // 유저 조회 User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); - if (user.getRole() == Role.GUEST) { - throw new CustomException(UserErrorCode.PROFILE_CARD_NOT_FOUND); - } - - // 프로필 카드 정보가 없는 경우 예외 처리 - if (!userMatchingDetailRepository.existsByUserIdAndIsDeprecatedFalse(userId)) { - throw new CustomException(UserErrorCode.PROFILE_CARD_NOT_FOUND); - } - + // 매칭 검사 진행 여부 예외 처리 UserMatchingDetail detail = userMatchingDetailRepository .findByUserIdAndIsDeprecatedFalse(userId) .orElseThrow(() -> new CustomException(UserErrorCode.USER_MATCHING_DETAIL_NOT_FOUND)); @@ -77,34 +69,26 @@ public MyProfileCardResponseDto getMyProfileCard(Long userId) { return MyProfileCardResponseDto.from(user, detail, categories); } + public MyScrapResponseDto getMyScrap(Long userId, String type, String sort) { - public MyScrapResponseDto getMyScrap(Long userId, String type, String sort) { // QueryDsl 적용 예정 - // 유저 조회 - User user = userRepository.findById(userId) - .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); - - // 내 찜 조회를 볼 자격이 있는지 확인 - if (user.getRole() == Role.GUEST || - !userMatchingDetailRepository.existsByUserIdAndIsDeprecatedFalse(userId)) { + // 매칭 검사 진행 여부 예외 처리 + if (!userMatchingDetailRepository.existsByUserIdAndIsDeprecatedFalse(userId)) { throw new CustomException(UserErrorCode.SCRAP_NOT_FOUND); } - // type이 null일 경우 + // 찜 타입이 null일 때 예외 처리 if (type == null) { throw new CustomException(UserErrorCode.SCRAP_NOT_FOUND); } - // 하드코딩된 Mock 데이터 제공자를 통해 찜 목록 조회 + // 찜 타입에 따른 분기 처리 return switch (type.toLowerCase()) { - case "brand" -> { - List brandList = scrapMockDataProvider.getBrandScraps(sort, null); - yield MyScrapResponseDto.ofBrandType(brandList); - } - case "campaign" -> { - List campaignList = scrapMockDataProvider.getCampaignScraps(sort, null); - yield MyScrapResponseDto.ofCampaignType(campaignList); - } - // 정의되지 않은 type이 들어올 경우 + case "brand" -> MyScrapResponseDto.ofBrandType( + scrapMockDataProvider.getBrandScraps(sort, null) + ); + case "campaign" -> MyScrapResponseDto.ofCampaignType( + scrapMockDataProvider.getCampaignScraps(sort, null) + ); default -> throw new CustomException(UserErrorCode.SCRAP_NOT_FOUND); }; } diff --git a/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java b/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java index 1734fbfd..db47ceb9 100644 --- a/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java +++ b/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java @@ -18,132 +18,47 @@ public enum UserErrorCode implements BaseErrorCode { "존재하지 않는 사용자입니다." ), - PROFILE_CARD_NOT_FOUND( - HttpStatus.NOT_FOUND, - "USER404_2", - "내 프로필 카드 정보를 불러오는데 실패하였습니다." - ), - SCRAP_NOT_FOUND( HttpStatus.NOT_FOUND, - "USER404_3", + "USER404_2", "내 찜 정보를 불러오는데 실패하였습니다." ), SOCIAL_INFO_NOT_FOUND( HttpStatus.NOT_FOUND, - "USER404_4", + "USER404_3", "소셜 연동 정보를 불러오는데 실패하였습니다." ), - SOCIAL_CONNECT_FAILED( - HttpStatus.NOT_FOUND, - "USER404_5", - "소셜 계정 연동 추가에 실패하였습니다." - ), - - SOCIAL_NOT_CONNECTED( - HttpStatus.NOT_FOUND, - "USER404_6", - "연동되지 않은 소셜 계정입니다." - ), - - SOCIAL_DISCONNECT_FAILED( - HttpStatus.NOT_FOUND, - "USER404_7", - "소셜 계정 연동 해제에 실패하였습니다." - ), - - BEAUTY_PROFILE_NOT_FOUND( - HttpStatus.NOT_FOUND, - "USER404_8", - "뷰티 프로필 정보를 불러오는데 실패하였습니다." - ), - - FASHION_PROFILE_NOT_FOUND( - HttpStatus.NOT_FOUND, - "USER404_9", - "패션 프로필 정보를 불러오는데 실패하였습니다." - ), - - CONTENT_PROFILE_NOT_FOUND( - HttpStatus.NOT_FOUND, - "USER404_10", - "콘텐츠 프로필 정보를 불러오는데 실패하였습니다." - ), - USER_MATCHING_DETAIL_NOT_FOUND( HttpStatus.NOT_FOUND, - "USER404_11", + "USER404_4", "매칭 상세 정보를 불러오는데 실패하였습니다." ), - USER_NOTIFICATION_SETTING_NOT_FOUND( - HttpStatus.NOT_FOUND, - "USER404_12", - "알림 설정이 존재하지 않습니다." - ), - - - // 400 - 요청 오류 - USER_UPDATE_BAD_REQUEST( - HttpStatus.BAD_REQUEST, - "USER400_1", - "회원정보 변경에 실패하였습니다. 입력 형식을 확인해주세요." - ), DUPLICATE_NICKNAME( HttpStatus.BAD_REQUEST, - "USER400_2", + "USER400_1", "이미 사용 중인 닉네임입니다." ), - LOGIN_METHOD_REQUIRED( - HttpStatus.BAD_REQUEST, - "USER400_3", - "최소 1개의 로그인 수단은 유지되어야 합니다." - ), - TRAIT_UPDATE_FAILED( HttpStatus.BAD_REQUEST, - "USER400_4", + "USER400_2", "특성 정보 수정 중 오류가 발생했습니다. 입력 값을 확인해주세요." ), - WITHDRAW_FAILED( - HttpStatus.BAD_REQUEST, - "USER400_5", - "탈퇴 처리에 실패했습니다. 다시 시도해주세요." - ), - INVALID_NICKNAME_FORMAT( HttpStatus.BAD_REQUEST, - "USER400_6", + "USER400_3", "닉네임은 한글, 영문, 숫자만 사용 가능합니다." ), INVALID_NICKNAME_LENGTH( HttpStatus.BAD_REQUEST, - "USER400_7", + "USER400_4", "닉네임은 2~10자 사이여야 합니다." - ), - - INVALID_PAGE_INDEX( - HttpStatus.BAD_REQUEST, - "USER400_8", - "페이지 번호는 0보다 작을 수 없습니다." - ), - - INVALID_PAGE_SIZE( - HttpStatus.BAD_REQUEST, - "USER400_9", - "페이지 크기는 1보다 커야 합니다." - ), - - INVALID_TERM( - HttpStatus.BAD_REQUEST, - "USER400_10", - "Term이 존재하지 않습니다." ); private final HttpStatus status; From d64e75ce107f50592077c7e0e899f20af8d9bcb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EA=B2=BD=EC=88=98?= Date: Tue, 10 Feb 2026 01:33:53 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix(#341):=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/application/service/UserService.java | 6 +- .../user/presentation/code/UserErrorCode.java | 99 +++++++++++++++++-- 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/RealMatch/user/application/service/UserService.java b/src/main/java/com/example/RealMatch/user/application/service/UserService.java index cf992638..495d8d17 100644 --- a/src/main/java/com/example/RealMatch/user/application/service/UserService.java +++ b/src/main/java/com/example/RealMatch/user/application/service/UserService.java @@ -58,10 +58,10 @@ public MyProfileCardResponseDto getMyProfileCard(Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); - // 매칭 검사 진행 여부 예외 처리 + // 매칭 검사 진행 여부 예외 처리 - 매칭 검사를 안하면 프로필 카드가 없음 UserMatchingDetail detail = userMatchingDetailRepository .findByUserIdAndIsDeprecatedFalse(userId) - .orElseThrow(() -> new CustomException(UserErrorCode.USER_MATCHING_DETAIL_NOT_FOUND)); + .orElseThrow(() -> new CustomException(UserErrorCode.PROFILE_CARD_NOT_FOUND)); List categories = userContentCategoryRepository.findByUserId(userId); @@ -71,7 +71,7 @@ public MyProfileCardResponseDto getMyProfileCard(Long userId) { public MyScrapResponseDto getMyScrap(Long userId, String type, String sort) { - // 매칭 검사 진행 여부 예외 처리 + // 매칭 검사 진행 여부 예외 처리 - 매칭 검사를 안하면 찜한 내역이 없음 if (!userMatchingDetailRepository.existsByUserIdAndIsDeprecatedFalse(userId)) { throw new CustomException(UserErrorCode.SCRAP_NOT_FOUND); } diff --git a/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java b/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java index db47ceb9..1734fbfd 100644 --- a/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java +++ b/src/main/java/com/example/RealMatch/user/presentation/code/UserErrorCode.java @@ -18,47 +18,132 @@ public enum UserErrorCode implements BaseErrorCode { "존재하지 않는 사용자입니다." ), - SCRAP_NOT_FOUND( + PROFILE_CARD_NOT_FOUND( HttpStatus.NOT_FOUND, "USER404_2", + "내 프로필 카드 정보를 불러오는데 실패하였습니다." + ), + + SCRAP_NOT_FOUND( + HttpStatus.NOT_FOUND, + "USER404_3", "내 찜 정보를 불러오는데 실패하였습니다." ), SOCIAL_INFO_NOT_FOUND( HttpStatus.NOT_FOUND, - "USER404_3", + "USER404_4", "소셜 연동 정보를 불러오는데 실패하였습니다." ), + SOCIAL_CONNECT_FAILED( + HttpStatus.NOT_FOUND, + "USER404_5", + "소셜 계정 연동 추가에 실패하였습니다." + ), + + SOCIAL_NOT_CONNECTED( + HttpStatus.NOT_FOUND, + "USER404_6", + "연동되지 않은 소셜 계정입니다." + ), + + SOCIAL_DISCONNECT_FAILED( + HttpStatus.NOT_FOUND, + "USER404_7", + "소셜 계정 연동 해제에 실패하였습니다." + ), + + BEAUTY_PROFILE_NOT_FOUND( + HttpStatus.NOT_FOUND, + "USER404_8", + "뷰티 프로필 정보를 불러오는데 실패하였습니다." + ), + + FASHION_PROFILE_NOT_FOUND( + HttpStatus.NOT_FOUND, + "USER404_9", + "패션 프로필 정보를 불러오는데 실패하였습니다." + ), + + CONTENT_PROFILE_NOT_FOUND( + HttpStatus.NOT_FOUND, + "USER404_10", + "콘텐츠 프로필 정보를 불러오는데 실패하였습니다." + ), + USER_MATCHING_DETAIL_NOT_FOUND( HttpStatus.NOT_FOUND, - "USER404_4", + "USER404_11", "매칭 상세 정보를 불러오는데 실패하였습니다." ), + USER_NOTIFICATION_SETTING_NOT_FOUND( + HttpStatus.NOT_FOUND, + "USER404_12", + "알림 설정이 존재하지 않습니다." + ), + - DUPLICATE_NICKNAME( + // 400 - 요청 오류 + USER_UPDATE_BAD_REQUEST( HttpStatus.BAD_REQUEST, "USER400_1", + "회원정보 변경에 실패하였습니다. 입력 형식을 확인해주세요." + ), + + DUPLICATE_NICKNAME( + HttpStatus.BAD_REQUEST, + "USER400_2", "이미 사용 중인 닉네임입니다." ), + LOGIN_METHOD_REQUIRED( + HttpStatus.BAD_REQUEST, + "USER400_3", + "최소 1개의 로그인 수단은 유지되어야 합니다." + ), + TRAIT_UPDATE_FAILED( HttpStatus.BAD_REQUEST, - "USER400_2", + "USER400_4", "특성 정보 수정 중 오류가 발생했습니다. 입력 값을 확인해주세요." ), + WITHDRAW_FAILED( + HttpStatus.BAD_REQUEST, + "USER400_5", + "탈퇴 처리에 실패했습니다. 다시 시도해주세요." + ), + INVALID_NICKNAME_FORMAT( HttpStatus.BAD_REQUEST, - "USER400_3", + "USER400_6", "닉네임은 한글, 영문, 숫자만 사용 가능합니다." ), INVALID_NICKNAME_LENGTH( HttpStatus.BAD_REQUEST, - "USER400_4", + "USER400_7", "닉네임은 2~10자 사이여야 합니다." + ), + + INVALID_PAGE_INDEX( + HttpStatus.BAD_REQUEST, + "USER400_8", + "페이지 번호는 0보다 작을 수 없습니다." + ), + + INVALID_PAGE_SIZE( + HttpStatus.BAD_REQUEST, + "USER400_9", + "페이지 크기는 1보다 커야 합니다." + ), + + INVALID_TERM( + HttpStatus.BAD_REQUEST, + "USER400_10", + "Term이 존재하지 않습니다." ); private final HttpStatus status; From f3dd872bdc417556139c2f5c3aa913f126d7daae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EA=B2=BD=EC=88=98?= Date: Tue, 10 Feb 2026 02:24:18 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix(#341):=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 2dfae9a6..5d4d6ecf 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,7 @@ repositories { } dependencies { + implementation 'org.springframework.boot:spring-boot-starter-mail' implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'