-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor: MSA 전환에 유리하게 구조를 수정 #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
""" Walkthrough이번 변경은 인증 및 사용자 관리 도메인의 대대적인 리팩토링과 확장입니다. 인증 주체가 기존 User에서 UserAuth로 분리되었으며, AuthPrinciple DTO가 도입되었습니다. 각종 서비스, 컨트롤러, 레포지토리, DTO, 엔티티가 이에 맞춰 대거 수정, 추가, 삭제되었습니다. 테스트 코드도 전면적으로 제거되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant AuthController
participant AuthService
participant UserService
participant UserAuthRepository
participant UserProfileRepository
Client->>AuthController: POST /register (UserRegisterRequest)
AuthController->>AuthService: register(req)
AuthService->>UserService: createUser(command)
UserService->>UserProfileRepository: save(UserProfile)
UserService-->>AuthService: userId
AuthService->>UserAuthRepository: save(UserAuth)
AuthService-->>AuthController: UserRegisterResponse
AuthController-->>Client: 201 Created (UserRegisterResponse)
sequenceDiagram
participant Client
participant AuthController
participant AuthService
participant UserAuthRepository
Client->>AuthController: PATCH /password (ChangePasswordRequest)
AuthController->>AuthService: changePassword(authId, req)
AuthService->>UserAuthRepository: findByIdAndStatus(authId, ACTIVE)
AuthService->>UserAuthRepository: updatePassword(email, encodedPassword)
AuthService->>UserAuthRepository: incrementTokenVersion(authId)
AuthService-->>AuthController: void
AuthController-->>Client: 204 No Content
Estimated code review effort🎯 5 (Critical) | ⏱️ ~90+ minutes
Possibly related PRs
Suggested reviewers
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 12
🔭 Outside diff range comments (1)
src/main/java/project/flipnote/auth/entity/OAuthLink.java (1)
1-26: import 문에 불필요한 의존성이 포함되어 있습니다.24-25번 라인의 import들이 실제로 사용되지 않고 있습니다.
-import project.flipnote.auth.repository.AuthAccountRepository; -import project.flipnote.user.entity.UserProfile;
🧹 Nitpick comments (16)
src/main/java/project/flipnote/common/util/PkceUtil.java (2)
14-15:SecureRandom인스턴스를static final로 선언하세요
SecureRandom은 thread-safe 합니다. 변경될 필요가 없으므로static final로 선언해 불변임을 명확히 하고, 혹시 모를 재할당을 방지하는 편이 좋습니다.- private static SecureRandom random = new SecureRandom(); + private static final SecureRandom RANDOM = new SecureRandom();
11-15: 유틸리티 성격에 맞추어@Component제거 또는 정적 메서드화 고려이 클래스는 상태가 없고 외부 의존성도 없으므로 Spring 빈으로 등록할 필요가 없어 보입니다.
옵션:
@Component제거 후 모든 메서드를static으로 변경하여 순수 유틸리티 클래스로 사용- 혹은 현재 형태를 유지하되, 테스트 용이성을 위해 인터페이스로 추출
첫 번째 방법이 가장 간단합니다.
-@Component -public class PkceUtil { +public final class PkceUtil { - public String generateCodeVerifier() { + public static String generateCodeVerifier() { ... - public String generateCodeChallenge(String codeVerifier) { + public static String generateCodeChallenge(String codeVerifier) {src/main/java/project/flipnote/common/event/UserWithdrawnEvent.java (1)
3-6: 이벤트 기반 아키텍처 도입이 MSA 전환에 적합합니다.UserWithdrawnEvent 레코드를 통해 사용자 탈퇴 시 도메인 간 결합도를 낮춘 설계가 좋습니다. 사용자 프로필과 인증 계정 상태 업데이트를 비동기적으로 분리할 수 있어 MSA 전환에 유리합니다.
더 견고한 구현을 위해 userId에 대한 검증을 고려해보세요:
public record UserWithdrawnEvent( - Long userId + @NonNull Long userId ) { + public UserWithdrawnEvent { + if (userId == null || userId <= 0) { + throw new IllegalArgumentException("유효하지 않은 사용자 ID입니다."); + } + } }src/main/java/project/flipnote/common/dto/UserCreateCommand.java (1)
3-11: 검증 어노테이션 추가를 고려해보세요.관련된 UserRegisterRequest, UserUpdateRequest 클래스들에는
@NotBlank,@ValidPhone등의 검증 어노테이션이 있는데, 이 Command 클래스에는 없습니다. 데이터 무결성을 위해 최소한의 검증 어노테이션 추가를 고려해보세요.다음과 같이 검증 어노테이션을 추가할 수 있습니다:
+import jakarta.validation.constraints.*; +import project.flipnote.user.validator.ValidPhone; + public record UserCreateCommand( Long userId, + @Email @NotBlank String email, + @NotBlank String name, + @NotBlank String nickname, + @NotNull Boolean smsAgree, + @ValidPhone String phone, String profileImageUrl ) {src/main/java/project/flipnote/auth/repository/OAuthLinkRepository.java (2)
20-30: JPQL 쿼리에서 별칭 일관성을 개선하세요.JOIN FETCH를 사용한 쿼리는 좋지만, 별칭이
uol로 되어 있어 이전UserOAuthLink시절의 네이밍이 남아있습니다.@Query(""" - SELECT uol - FROM OAuthLink uol - JOIN FETCH uol.account - WHERE uol.provider = :provider - AND uol.providerId = :providerId + SELECT ol + FROM OAuthLink ol + JOIN FETCH ol.account + WHERE ol.provider = :provider + AND ol.providerId = :providerId """)
14-14: 데이터베이스 인덱스 최적화를 검토하세요.
existsByAccount_IdAndProviderId메서드는 복합 조건으로 자주 사용될 것으로 예상됩니다. 성능 최적화를 위해(account_id, provider_id)복합 인덱스 생성을 고려해보세요.src/main/java/project/flipnote/user/repository/UserRepository.java (1)
9-11: 사용자 프로필 조회 메서드 추가를 고려하세요.현재는 존재성 확인만 가능한데, 실제 서비스에서는 사용자 프로필 조회가 필요할 것입니다.
boolean existsByEmail(String email); boolean existsByPhone(String phone); + Optional<UserProfile> findByEmail(String email); + + Optional<UserProfile> findByPhone(String phone);src/main/java/project/flipnote/common/security/dto/AccountAuth.java (2)
29-38: JWT 클레임 파싱에서 변수명 불일치를 수정하세요.
AccountAuth레코드의 첫 번째 필드가accountId인데, JWT 파싱에서는 여전히userId변수명을 사용하고 있습니다.public static AccountAuth from(Claims claims) { - long userId = Long.parseLong(claims.getId()); + long accountId = Long.parseLong(claims.getId()); AccountRole userRole = AccountRole.from( claims.get(JwtConstants.ROLE, String.class) ); String email = claims.getSubject(); long tokenVersion = claims.get(JwtConstants.TOKEN_VERSION, Long.class); - return new AccountAuth(userId, email, userRole, tokenVersion); + return new AccountAuth(accountId, email, userRole, tokenVersion); }
17-17: 필드명과 실제 역할의 불일치를 수정하세요.레코드 필드명이
userRole인데 타입이AccountRole로 변경되었습니다. 일관성을 위해 필드명도accountRole로 변경하는 것이 좋겠습니다.public record AccountAuth( Long accountId, String email, - AccountRole userRole, + AccountRole accountRole, long tokenVersion ) { public Collection<? extends GrantedAuthority> getAuthorities() { - return List.of(new SimpleGrantedAuthority("ROLE_" + userRole.name())); + return List.of(new SimpleGrantedAuthority("ROLE_" + accountRole.name())); } public static AccountAuth from(AuthAccount account) { return new AccountAuth(account.getId(), account.getEmail(), account.getRole(), account.getTokenVersion()); } public static AccountAuth from(Claims claims) { long accountId = Long.parseLong(claims.getId()); - AccountRole userRole = AccountRole.from( + AccountRole accountRole = AccountRole.from( claims.get(JwtConstants.ROLE, String.class) ); String email = claims.getSubject(); long tokenVersion = claims.get(JwtConstants.TOKEN_VERSION, Long.class); - return new AccountAuth(accountId, email, userRole, tokenVersion); + return new AccountAuth(accountId, email, accountRole, tokenVersion); } }src/main/java/project/flipnote/auth/entity/AuthAccount.java (1)
1-72: 인증 도메인 분리가 MSA 전환에 적합합니다.
AuthAccount로 인증 관련 데이터만 분리한 설계가 마이크로서비스 아키텍처 전환에 유리합니다. 프로필 정보는UserProfile로 분리되어 관심사가 명확히 구분되었습니다.데이터 마이그레이션 시 기존
users테이블에서auth_account테이블로의 데이터 이관 전략과 외래 키 제약 조건 처리 방안을 고려해야 합니다.src/main/java/project/flipnote/auth/controller/AuthController.java (1)
140-157: 소셜 연동 관리 엔드포인트가 잘 설계되었습니다.RESTful 규약에 따라 GET과 DELETE 메서드를 적절히 사용했으며, 인증 확인도 적절합니다.
삭제 작업 시 해당 소셜 링크가 현재 사용자의 것인지 서비스 레이어에서 추가 검증이 필요할 수 있습니다.
src/main/java/project/flipnote/common/security/jwt/JwtComponent.java (1)
75-81: 메서드명이 일관성 있게 변경되지 않았습니다.메서드명이 여전히
extractUserAuthFromToken으로 되어 있지만, 반환 타입은AccountAuth입니다. 일관성을 위해 메서드명을extractAccountAuthFromToken으로 변경하는 것을 고려해보세요.-public AccountAuth extractUserAuthFromToken(String token) { +public AccountAuth extractAccountAuthFromToken(String token) {src/main/java/project/flipnote/user/controller/UserController.java (1)
52-58: 경로 변수명과 일관성 문제가 있습니다.경로 변수가 여전히
userId로 되어 있는데, 전체적인 리팩토링 방향을 고려하면accountId로 변경하는 것이 일관성 있을 것 같습니다. 다만, 이는 API 호환성에 영향을 줄 수 있으므로 신중한 결정이 필요합니다.-@GetMapping("/{userId}") +@GetMapping("/{accountId}") public ResponseEntity<UserInfoResponse> getUserInfo( - @PathVariable("userId") Long userId + @PathVariable("accountId") Long accountId ) { - UserInfoResponse res = userService.getUserInfo(userId); + UserInfoResponse res = userService.getUserInfo(accountId); return ResponseEntity.ok(res); }src/main/java/project/flipnote/user/service/UserService.java (1)
88-96: 전화번호 중복 검증 메서드의 접근 제한자 변경
validatePhoneDuplicate메서드가 public으로 변경되었는데, 이는AuthService에서 사용하기 위한 것으로 보입니다. 도메인 간 직접 호출보다는 별도의 검증 서비스나 이벤트 기반 검증을 고려해보세요.MSA 전환을 고려한다면, 도메인 간 직접적인 의존성보다는 API 호출이나 이벤트 기반 검증이 더 적합할 수 있습니다.
src/main/java/project/flipnote/auth/service/AuthService.java (2)
3-42: 도메인 간 의존성이 증가했습니다.Auth 도메인이 User 도메인의 서비스와 모델을 직접 참조하고 있습니다. MSA 전환을 고려한다면 이러한 직접적인 의존성을 줄이는 것이 좋습니다.
190-194: validatePasswordMatch 메서드의 접근 제한자이 메서드가 public으로 선언되어 있는데, 클래스 내부에서만 사용된다면 private으로 변경하는 것이 좋습니다.
-public void validatePasswordMatch(String rawPassword, String encodedPassword) { +private void validatePasswordMatch(String rawPassword, String encodedPassword) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (53)
src/main/java/project/flipnote/auth/constants/AuthRedisKey.java(1 hunks)src/main/java/project/flipnote/auth/controller/AuthController.java(3 hunks)src/main/java/project/flipnote/auth/controller/OAuthController.java(2 hunks)src/main/java/project/flipnote/auth/entity/AccountRole.java(1 hunks)src/main/java/project/flipnote/auth/entity/AccountStatus.java(1 hunks)src/main/java/project/flipnote/auth/entity/AuthAccount.java(3 hunks)src/main/java/project/flipnote/auth/entity/OAuthLink.java(3 hunks)src/main/java/project/flipnote/auth/exception/AuthErrorCode.java(1 hunks)src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java(1 hunks)src/main/java/project/flipnote/auth/model/ChangePasswordRequest.java(1 hunks)src/main/java/project/flipnote/auth/model/UserRegisterRequest.java(2 hunks)src/main/java/project/flipnote/auth/model/UserRegisterResponse.java(1 hunks)src/main/java/project/flipnote/auth/repository/AuthAccountRepository.java(1 hunks)src/main/java/project/flipnote/auth/repository/OAuthLinkRepository.java(1 hunks)src/main/java/project/flipnote/auth/repository/SocialLinkTokenRedisRepository.java(1 hunks)src/main/java/project/flipnote/auth/repository/TokenVersionRedisRepository.java(1 hunks)src/main/java/project/flipnote/auth/service/AuthService.java(6 hunks)src/main/java/project/flipnote/auth/service/EmailVerificationService.java(0 hunks)src/main/java/project/flipnote/auth/service/OAuthService.java(4 hunks)src/main/java/project/flipnote/auth/service/TokenVersionService.java(1 hunks)src/main/java/project/flipnote/common/config/OAuthProperties.java(1 hunks)src/main/java/project/flipnote/common/config/WebConfig.java(1 hunks)src/main/java/project/flipnote/common/dto/UserCreateCommand.java(1 hunks)src/main/java/project/flipnote/common/event/UserWithdrawnEvent.java(1 hunks)src/main/java/project/flipnote/common/security/config/SecurityConfig.java(1 hunks)src/main/java/project/flipnote/common/security/dto/AccountAuth.java(1 hunks)src/main/java/project/flipnote/common/security/filter/JwtAuthenticationFilter.java(3 hunks)src/main/java/project/flipnote/common/security/jwt/JwtComponent.java(3 hunks)src/main/java/project/flipnote/common/util/PkceUtil.java(1 hunks)src/main/java/project/flipnote/group/controller/GroupController.java(2 hunks)src/main/java/project/flipnote/group/entity/Group.java(2 hunks)src/main/java/project/flipnote/group/entity/GroupMember.java(2 hunks)src/main/java/project/flipnote/group/service/GroupService.java(4 hunks)src/main/java/project/flipnote/infra/email/EmailService.java(1 hunks)src/main/java/project/flipnote/infra/oauth/OAuthApiClient.java(3 hunks)src/main/java/project/flipnote/infra/oauth/model/OAuth2UserInfo.java(1 hunks)src/main/java/project/flipnote/user/controller/UserController.java(2 hunks)src/main/java/project/flipnote/user/entity/UserProfile.java(1 hunks)src/main/java/project/flipnote/user/entity/UserRole.java(0 hunks)src/main/java/project/flipnote/user/entity/UserStatus.java(0 hunks)src/main/java/project/flipnote/user/exception/UserErrorCode.java(1 hunks)src/main/java/project/flipnote/user/model/MyInfoResponse.java(2 hunks)src/main/java/project/flipnote/user/model/SocialLinkResponse.java(2 hunks)src/main/java/project/flipnote/user/model/SocialLinksResponse.java(1 hunks)src/main/java/project/flipnote/user/model/UserInfoResponse.java(1 hunks)src/main/java/project/flipnote/user/model/UserUpdateResponse.java(2 hunks)src/main/java/project/flipnote/user/repository/UserOAuthLinkRepository.java(0 hunks)src/main/java/project/flipnote/user/repository/UserRepository.java(1 hunks)src/main/java/project/flipnote/user/service/UserService.java(4 hunks)src/test/java/project/flipnote/auth/service/AuthServiceTest.java(0 hunks)src/test/java/project/flipnote/fixture/UserFixture.java(1 hunks)src/test/java/project/flipnote/group/service/GroupServiceTest.java(0 hunks)src/test/java/project/flipnote/user/service/UserServiceTest.java(8 hunks)
💤 Files with no reviewable changes (6)
- src/main/java/project/flipnote/auth/service/EmailVerificationService.java
- src/main/java/project/flipnote/user/entity/UserRole.java
- src/test/java/project/flipnote/group/service/GroupServiceTest.java
- src/main/java/project/flipnote/user/entity/UserStatus.java
- src/main/java/project/flipnote/user/repository/UserOAuthLinkRepository.java
- src/test/java/project/flipnote/auth/service/AuthServiceTest.java
🧰 Additional context used
🧬 Code Graph Analysis (19)
src/main/java/project/flipnote/infra/oauth/model/OAuth2UserInfo.java (1)
src/main/java/project/flipnote/infra/oauth/model/GoogleUserInfo.java (1)
GoogleUserInfo(7-30)
src/main/java/project/flipnote/auth/model/UserRegisterResponse.java (1)
src/main/java/project/flipnote/user/model/UserRegisterResponse.java (1)
UserRegisterResponse(3-10)
src/main/java/project/flipnote/auth/model/ChangePasswordRequest.java (1)
src/main/java/project/flipnote/user/model/ChangePasswordRequest.java (1)
ChangePasswordRequest(5-13)
src/main/java/project/flipnote/common/event/UserWithdrawnEvent.java (2)
src/main/java/project/flipnote/user/model/UserRegisterResponse.java (1)
UserRegisterResponse(3-10)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/auth/entity/AccountStatus.java (3)
src/main/java/project/flipnote/auth/entity/AuthAccount.java (1)
Getter(18-72)src/main/java/project/flipnote/user/entity/UserStatus.java (1)
UserStatus(5-8)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/common/dto/UserCreateCommand.java (3)
src/main/java/project/flipnote/user/model/UserUpdateRequest.java (1)
UserUpdateRequest(8-25)src/main/java/project/flipnote/user/model/UserRegisterRequest.java (1)
UserRegisterRequest(10-35)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/user/model/UserUpdateResponse.java (2)
src/main/java/project/flipnote/user/model/UserUpdateRequest.java (1)
UserUpdateRequest(8-25)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/auth/controller/OAuthController.java (2)
src/main/java/project/flipnote/common/security/dto/UserAuth.java (1)
UserAuth(14-39)src/main/java/project/flipnote/user/entity/UserOAuthLink.java (1)
UserOAuthLink(20-52)
src/main/java/project/flipnote/user/model/MyInfoResponse.java (1)
src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/test/java/project/flipnote/fixture/UserFixture.java (2)
src/test/java/project/flipnote/group/service/GroupServiceTest.java (1)
before(65-72)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/group/controller/GroupController.java (2)
src/test/java/project/flipnote/group/service/GroupServiceTest.java (2)
before(65-72)GroupServiceTest(37-120)src/main/java/project/flipnote/common/security/dto/UserAuth.java (1)
UserAuth(14-39)
src/main/java/project/flipnote/auth/repository/AuthAccountRepository.java (1)
src/main/java/project/flipnote/auth/repository/PasswordResetRedisRepository.java (1)
PasswordResetRedisRepository(16-71)
src/main/java/project/flipnote/group/service/GroupService.java (2)
src/test/java/project/flipnote/group/service/GroupServiceTest.java (1)
before(65-72)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/auth/entity/AuthAccount.java (3)
src/main/java/project/flipnote/user/entity/User.java (4)
User(20-105)update(95-100)unregister(83-89)changePassword(102-104)src/main/java/project/flipnote/common/security/dto/UserAuth.java (1)
UserAuth(14-39)src/main/java/project/flipnote/user/entity/UserOAuthLink.java (1)
UserOAuthLink(20-52)
src/test/java/project/flipnote/user/service/UserServiceTest.java (1)
src/test/java/project/flipnote/fixture/UserFixture.java (1)
UserFixture(7-26)
src/main/java/project/flipnote/common/security/jwt/JwtComponent.java (2)
src/main/java/project/flipnote/common/security/dto/UserAuth.java (1)
UserAuth(14-39)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/user/controller/UserController.java (1)
src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
src/main/java/project/flipnote/auth/service/AuthService.java (1)
src/test/java/project/flipnote/auth/service/AuthServiceTest.java (2)
AuthServiceTest(44-410)success(379-394)
src/main/java/project/flipnote/user/model/SocialLinkResponse.java (3)
src/main/java/project/flipnote/user/entity/UserOAuthLink.java (2)
UserOAuthLink(20-52)UserOAuthLink(46-51)src/main/java/project/flipnote/user/repository/UserOAuthLinkRepository.java (1)
UserOAuthLinkRepository(7-10)src/main/java/project/flipnote/user/entity/User.java (1)
User(20-105)
🔇 Additional comments (72)
src/main/java/project/flipnote/common/config/OAuthProperties.java (1)
49-49: 파일 끝에 개행 추가 👍POSIX 규격에 맞춰 EOF 개행을 추가한 점 확인했습니다.
코드 스타일 일관성 유지에 도움이 됩니다.src/main/java/project/flipnote/common/config/WebConfig.java (1)
21-22: 파일 끝 개행 추가로 POSIX 규약 충족텍스트 파일을 개행으로 종료하도록 수정되어 리눅스 계열 도구에서 경고가 발생하지 않습니다. 기능적 변경은 없으며, 스타일 가이드 측면에서 긍정적인 개선입니다.
src/main/java/project/flipnote/common/util/PkceUtil.java (1)
31-31: 마지막 줄 개행 추가 확인파일 끝에 개행을 추가한 변경만 이루어졌습니다. 스타일 가이드에 부합하므로 문제 없습니다.
src/main/java/project/flipnote/auth/model/UserRegisterResponse.java (1)
1-1: MSA 전환을 위한 패키지 구조 개선이 적절합니다.사용자 등록 응답 모델을
user.model에서auth.model패키지로 이동한 것은 인증 관련 기능을 분리하여 MSA 전환에 유리한 구조로 개선하는 올바른 접근입니다.src/main/java/project/flipnote/auth/entity/AccountStatus.java (1)
5-8: 중복된 UserStatus enum 사용 없음 확인
rg -A5 "UserStatus" --type java실행 결과, UserStatus enum에 대한 참조가 전혀 발견되지 않았습니다. 모든 이전 UserStatus 참조가 새로운AccountStatus로 성공적으로 마이그레이션된 것으로 확인되며, 중복 이슈는 없습니다.src/main/java/project/flipnote/auth/model/UserRegisterRequest.java (2)
1-1: 인증 모듈로의 패키지 이동이 적절합니다.사용자 등록 요청 모델을
auth.model패키지로 이동한 것은 MSA 전환을 위한 도메인 분리에 부합합니다.
37-39: 확인 완료: UserCreateCommand 정의 및 사용처 적합
- project/flipnote/common/dto/UserCreateCommand.java에 record로 정의되어 있습니다.
- UserRegisterRequest.toCommand(Long accountId)에서 전달하는 인자(accountId, email, name, nickname, smsAgree, getNormalizedPhone(), profileImageUrl)와 record 필드 순서가 일치합니다.
- AuthService 및 UserService에서 의도한 대로 사용되고 있으므로 추가 수정은 필요 없습니다.
src/main/java/project/flipnote/group/entity/GroupMember.java (1)
18-18: 관련 서비스 및 컨트롤러 검증 완료: 추가 수정 불필요서비스와 레포지토리에서
UserProfile연관관계가 올바르게 반영되었으며, 컨트롤러 레이어에는GroupMember를 직접 참조하는 코드가 없어 추가 변경이 필요하지 않습니다.
- GroupService
findUser(accountAuth)및saveGroupOwner(Group, UserProfile)로직에서UserProfile연관관계 정상 작동 확인- GroupMemberRepository
JpaRepository<GroupMember, Long>확장부 정상- 컨트롤러
GroupMember직접 참조 위치 없음 (검색 결과)src/main/java/project/flipnote/user/entity/UserProfile.java (3)
1-22: 도메인 분리를 위한 새로운 엔티티 설계가 우수합니다.인증 관련 데이터(
AuthAccount)와 사용자 프로필 데이터(UserProfile)를 분리한 것은 MSA 전환에 매우 적합한 설계입니다. 각 엔티티가 명확한 책임을 가지게 되었습니다.
44-49: 프로필 업데이트 메서드가 적절합니다.변경 가능한 필드들(
nickname,phone,smsAgree,profileImageUrl)만을 업데이트하는 메서드 설계가 적절하며, 불변 필드들(name)은 보호되고 있습니다.
24-25: UserProfile 생성 로직 및 ID 할당 방식 재확인 필요
UserProfile엔티티에@GeneratedValue가 없어 수동 ID 할당으로 보이지만, 실제 생성·저장 지점과AuthAccount와의 연관관계 매핑이 코드상 확인되지 않습니다. 아래 항목을 점검해주세요:
- 서비스(또는 핸들러)에서
new UserProfile(...)또는UserProfile.builder()호출 위치UserProfileRepository.save(…)등 저장 로직AuthAccount엔티티 내@OneToOne(또는@MapsId) 매핑 및 cascade 설정src/main/java/project/flipnote/infra/email/EmailService.java (1)
5-7: 형식 변경만 존재 – 추가 조치 불필요공백 한 줄 추가만 이루어졌으며 기능적 영향이 없습니다.
src/main/java/project/flipnote/infra/oauth/model/OAuth2UserInfo.java (1)
4-10: 형식 변경만 존재 – 추가 조치 불필요메서드 사이 공백 추가 외에 변경 사항이 없습니다.
src/main/java/project/flipnote/auth/constants/AuthRedisKey.java (1)
16-16: 컴파일 오류 수정 완료마지막 enum 항목 뒤의 세미콜론 추가로 컴파일 오류가 해결되었습니다. TTL(180초) 값도 요구사항에 부합한다면 그대로 유지해도 무방합니다.
src/main/java/project/flipnote/auth/model/ChangePasswordRequest.java (1)
1-1: 패키지 참조 확인 완료: ChangePasswordRequest 이전 경로 미사용
rg -n "project\.flipnote\.user\.model\.ChangePasswordRequest"로 검색해도 결과가 없었고, 패키지 전체 검색에서도 해당 클래스에 대한 구(舊)경로 참조는 발견되지 않았습니다.
- 별도의 수정 없이 안전합니다.
src/main/java/project/flipnote/group/entity/Group.java (1)
11-13: 형식 변경만 존재 – 추가 조치 불필요import 정리 및 트레일링 콤마 제거만 이루어졌습니다.
src/main/java/project/flipnote/user/exception/UserErrorCode.java (1)
15-15: MSA 전환을 위한 도메인 분리가 적절히 반영되었습니다.SOCIAL_LINK_NOT_FOUND 에러 코드를 AuthErrorCode로 이동한 것은 소셜 연동 기능을 인증 도메인으로 분리하는 리팩토링 목표와 일치합니다. 사용자 프로필 관련 에러 코드만 남겨둔 것이 적절합니다.
src/main/java/project/flipnote/common/security/config/SecurityConfig.java (1)
61-61: 회원가입 엔드포인트에 대한 보안 설정이 적절합니다.새로 추가된 "/*/auth/register" 엔드포인트를 permitAll()에 포함한 것이 올바릅니다. 기존 인증 관련 엔드포인트들과 함께 그룹화되어 있고, 와일드카드 패턴을 통한 버전 지원도 일관성 있게 적용되었습니다.
src/main/java/project/flipnote/user/model/MyInfoResponse.java (2)
7-7: 도메인 분리를 위한 임포트 변경이 적절합니다.User에서 UserProfile로 임포트를 변경한 것이 사용자 프로필과 인증 도메인을 분리하는 리팩토링 목표와 일치합니다.
25-37: 팩토리 메서드 업데이트가 올바르게 구현되었습니다.from() 메서드의 매개변수 타입을 UserProfile로 변경하고 해당 게터 메서드들을 사용하도록 구현한 것이 적절합니다. API 응답 구조는 유지하면서 내부 도메인 모델만 변경되어 기존 클라이언트와의 호환성도 보장됩니다.
src/main/java/project/flipnote/auth/exception/AuthErrorCode.java (1)
25-26: 소셜 연동 관리의 Auth 도메인 이관이 적절합니다.소셜 연동 계정 관리 책임이 User 도메인에서 Auth 도메인으로 이관되면서
SOCIAL_LINK_NOT_FOUND에러 코드가 추가된 것이 MSA 전환을 위한 도메인 분리 목적에 부합합니다. 에러 메시지와 HTTP 상태 코드도 적절하게 설정되어 있습니다.src/main/java/project/flipnote/user/model/UserUpdateResponse.java (2)
3-3: UserProfile 엔티티로의 전환이 도메인 분리 목적에 적합합니다.User 엔티티에서 UserProfile 엔티티로 변경된 것이 인증 관심사와 사용자 프로필 관심사를 분리하는 MSA 구조 개선에 부합합니다.
13-17: UserProfile 엔티티에 클래스 레벨 @Getter 어노테이션이 적용되어 있어 getId(), getNickname(), getPhone(), isSmsAgree(), getProfileImageUrl() 메서드가 자동 생성됩니다.
해당 factory 메서드는 별도 수정 없이 정상 동작합니다.src/main/java/project/flipnote/user/model/UserInfoResponse.java (2)
3-3: 도메인 분리에 따른 일관된 엔티티 변경입니다.UserUpdateResponse와 동일하게 User에서 UserProfile로 변경된 것이 일관된 리팩토링 패턴을 보여줍니다.
11-13: UserProfile 엔티티의 메서드 구현 확인이 필요합니다.factory 메서드에서 호출하는
getId(),getNickname(),getProfileImageUrl()메서드들이 UserProfile 엔티티에 적절히 구현되어 있는지 확인해주세요.src/main/java/project/flipnote/common/dto/UserCreateCommand.java (1)
1-13: 도메인 분리를 위한 Command DTO 구조가 적절합니다.AuthService에서 UserService로 사용자 생성을 위임하기 위한 Command 패턴 적용이 MSA 구조 개선에 적합합니다. 불변 객체로 설계된 점도 좋습니다.
src/test/java/project/flipnote/fixture/UserFixture.java (2)
5-5: UserProfile 엔티티로의 테스트 픽스처 업데이트가 적절합니다.User에서 UserProfile로 변경하면서 인증 관련 필드(password)가 제거된 것이 도메인 분리 목적에 부합합니다.
12-25: UserFixture 변경으로 인한 테스트 영향 없음 확인
UserFixture.createActiveUser()를 사용하는 모든 테스트(UserServiceTest등)에서getRole(),getTokenVersion(),getStatus()호출을 검색한 결과, 해당 메서드가 사용된 부분이 없으므로 추가 수정은 필요하지 않습니다.src/main/java/project/flipnote/user/model/SocialLinkResponse.java (1)
7-7: 도메인 모델 리팩토링이 올바르게 적용되었습니다.
UserOAuthLink에서OAuthLink로의 변경이 일관성 있게 적용되어 있으며, 인증 관련 엔티티가 auth 패키지로 적절히 이동되었습니다.Also applies to: 19-19
src/main/java/project/flipnote/user/model/SocialLinksResponse.java (1)
5-5: 일관된 타입 변경이 적용되었습니다.
OAuthLink엔티티 사용으로의 변경이 올바르게 적용되어 있으며, 리스트 처리 로직도 적절히 업데이트되었습니다.Also applies to: 11-11
src/main/java/project/flipnote/auth/controller/OAuthController.java (1)
28-28: AccountAuth가 일관되게 적용되었으며, UserAuth는 더 이상 존재하지 않습니다.
OAuthController와 관련 호출부가 모두AccountAuth로 정상 업데이트되어 있어 추가 검증이 필요 없습니다.src/main/java/project/flipnote/group/controller/GroupController.java (1)
13-13: 컨트롤러 인증 타입 변경 검토 완료
GroupController의 인증 타입이UserAuth에서AccountAuth로 일관되게 변경되었습니다.
전체 테스트 코드에서도UserAuth사용이 발견되지 않아 추가 수정이 필요하지 않습니다.src/main/java/project/flipnote/infra/oauth/OAuthApiClient.java (1)
30-35: 코드 스타일 개선이 적절히 적용되었습니다.메서드 파라미터 포맷팅과
TypeReference사용법이 일관되게 개선되어 가독성이 향상되었습니다.Also applies to: 52-54, 68-69
src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java (2)
1-16: 패키지 구조와 import문이 적절합니다.MSA 전환을 위한 리팩토링에 맞게 auth 도메인으로 적절히 분리되었고, 필요한 Spring 어노테이션들과 의존성들이 올바르게 import되었습니다.
17-22: 컴포넌트 선언이 적절합니다.Lombok을 활용한 의존성 주입과 로깅 설정이 올바르게 구성되었습니다. AuthAccountRepository 의존성도 새로운 account 기반 구조에 맞게 적절히 설정되었습니다.
src/main/java/project/flipnote/auth/entity/OAuthLink.java (3)
32-38: 테이블명 변경이 MSA 전환 목적에 부합합니다.
user_oauth_link에서oauth_link로 변경된 것은 도메인 분리에 적합하며, 인덱스 설정도 적절히 유지되었습니다.
51-52: 연관관계 설정이 올바르게 변경되었습니다.User에서 AuthAccount로의 연관관계 변경과 조인 컬럼명 변경(
user_id→account_id)이 새로운 account 기반 구조에 맞게 적절히 수정되었습니다.
59-63: 생성자 파라미터가 일관성 있게 변경되었습니다.Builder 메서드의 파라미터가 User에서 AuthAccount로 적절히 변경되어 새로운 도메인 모델과 일치합니다.
src/main/java/project/flipnote/auth/service/TokenVersionService.java (3)
8-16: 의존성 변경이 적절합니다.UserRepository에서 AuthAccountRepository로의 변경이 새로운 account 기반 인증 구조에 맞게 올바르게 수정되었습니다.
18-27: 메서드 시그니처와 로직이 일관성 있게 변경되었습니다.
userId에서accountId로의 파라미터명 변경과 관련 로직들이 새로운 명명 규칙에 맞게 적절히 수정되었습니다. Redis 캐싱 로직도 올바르게 유지되었습니다.
29-32: 토큰 버전 증가 로직이 올바르게 업데이트되었습니다.
accountId기반으로 토큰 버전을 증가시키고 Redis 캐시를 삭제하는 로직이 새로운 도메인 모델에 맞게 적절히 변경되었습니다.src/main/java/project/flipnote/auth/repository/SocialLinkTokenRedisRepository.java (2)
18-23: 메서드 파라미터명이 일관성 있게 변경되었습니다.
userId에서accountId로의 파라미터명 변경이 새로운 account 기반 명명 규칙에 맞게 적절히 수정되었고, Redis 저장 로직도 올바르게 유지되었습니다.
25-32: 메서드명과 내부 로직이 올바르게 업데이트되었습니다.
findUserIdByToken에서findAccountIdByToken으로의 메서드명 변경과 내부 변수명들이 새로운 도메인 모델에 맞게 일관성 있게 수정되었습니다. Redis 조회 로직은 적절히 유지되었습니다.src/main/java/project/flipnote/common/security/filter/JwtAuthenticationFilter.java (3)
18-18: import문이 새로운 DTO에 맞게 적절히 변경되었습니다.UserAuth에서 AccountAuth로의 import 변경이 새로운 account 기반 인증 구조에 맞게 올바르게 수정되었습니다.
38-41: 변수명과 메서드 호출이 일관성 있게 변경되었습니다.
userAuth에서accountAuth로의 변수명 변경이 새로운 명명 규칙에 맞게 적절히 수정되었고, JWT 컴포넌트 호출도 올바르게 유지되었습니다.
55-57: 인증 설정 메서드가 올바르게 업데이트되었습니다.
setAuthentication메서드의 파라미터 타입이 AccountAuth로 변경되었고, Spring Security의UsernamePasswordAuthenticationToken생성 시 새로운 DTO를 올바르게 사용하고 있습니다.src/main/java/project/flipnote/auth/repository/OAuthLinkRepository.java (1)
12-18: 리포지토리 메서드 구성이 적절합니다.OAuth 링크 관리에 필요한 핵심 기능들이 잘 정의되어 있습니다. 계정별 OAuth 링크 조회, 존재성 확인 등 필수 메서드들이 포함되어 있어 좋습니다.
src/main/java/project/flipnote/user/repository/UserRepository.java (1)
5-7: 도메인 분리가 잘 이루어졌습니다.
User에서UserProfile로 변경하여 인증과 사용자 프로필 관리를 명확히 분리한 것이 MSA 전환에 적합합니다. 인증 관련 책임은AuthAccountRepository로 이관되어 단일 책임 원칙을 잘 준수하고 있습니다.src/main/java/project/flipnote/auth/repository/AuthAccountRepository.java (2)
13-19: 인증 관련 메서드들이 잘 구성되어 있습니다.계정 존재성 확인, 상태별 조회 등 인증에 필요한 핵심 기능들이 적절히 정의되어 있습니다.
AccountStatus를 활용한 상태 기반 조회도 좋은 설계입니다.
21-23: 비밀번호 해싱 처리 확인 완료AuthService(src/main/java/project/flipnote/auth/service/AuthService.java:152–153)에서
String encodedPassword = passwordEncoder.encode(req.password()); authAccountRepository.updatePassword(email, encodedPassword);를 통해 해싱된 값이 전달되고 있으므로, 비밀번호가 안전하게 업데이트되고 있습니다. 추가 수정은 필요 없습니다.
src/main/java/project/flipnote/auth/repository/TokenVersionRedisRepository.java (1)
18-36: 일관성 있는 네이밍 변경이 잘 이루어졌습니다.
userId에서accountId로의 파라미터명 변경이 모든 메서드에 일관성 있게 적용되었습니다. 도메인 모델 변경에 따른 적절한 리팩토링입니다.src/main/java/project/flipnote/common/security/dto/AccountAuth.java (2)
14-19: 도메인 모델 변경이 일관성 있게 적용되었습니다.
UserAuth에서AccountAuth로의 변경과 함께 필드명과 타입이 새로운 도메인 모델에 맞게 적절히 업데이트되었습니다.
25-27: 팩토리 메서드가 적절히 업데이트되었습니다.
AuthAccount엔티티로부터AccountAuth생성하는 로직이 올바르게 구현되어 있습니다.src/main/java/project/flipnote/auth/service/OAuthService.java (3)
46-65: OAuth 인증 URI 생성 로직이 적절합니다.
AccountAuth기반으로 상태 토큰을 생성하고 PKCE 플로우를 올바르게 구현했습니다.
67-91: 소셜 계정 연동 로직이 견고합니다.Redis를 통한 상태 토큰 검증, 중복 연동 체크, 그리고
getReferenceById를 사용한 효율적인 엔티티 참조가 잘 구현되었습니다.
119-126: 상태 토큰 생성 로직이 안전합니다.인증되지 않은 요청에 대한 null 처리와 UUID를 사용한 안전한 토큰 생성이 적절합니다.
src/main/java/project/flipnote/group/service/GroupService.java (1)
114-122: 그룹 소유자 저장 로직이 적절합니다.
UserProfile엔티티 사용으로의 변경이 일관성 있게 적용되었습니다.src/main/java/project/flipnote/auth/controller/AuthController.java (2)
46-50: 회원가입 엔드포인트가 적절히 구현되었습니다.POST 메서드와 201 CREATED 상태 코드 사용이 RESTful 규약에 부합합니다.
131-138: 비밀번호 변경 엔드포인트가 안전하게 구현되었습니다.인증된 사용자만 접근 가능하고 PATCH 메서드를 적절히 사용했습니다.
src/test/java/project/flipnote/user/service/UserServiceTest.java (3)
45-46: 테스트가 새로운 도메인 모델에 맞게 업데이트되었습니다.
User에서UserProfile로의 변경이 일관성 있게 적용되었습니다.Also applies to: 69-70, 105-106, 127-128, 162-163
51-51: 테스트가 서비스 구현과 일치하지만 상태 검증 누락 문제를 포함합니다.
findById사용은 현재 서비스 구현과 일치하나, 앞서 지적한 사용자 상태 검증 누락 문제가 테스트에도 반영되어 있습니다. 서비스 수정 후 테스트도 함께 업데이트가 필요합니다.Also applies to: 75-75, 95-95, 111-111, 129-129, 147-147, 163-163, 177-177
1-184: 인증 관련 테스트 이동 여부 확인 필요UserServiceTest에서 제거된 인증, 비밀번호 변경, 소셜 연동 관련 테스트가 auth 모듈 내 AuthServiceTest.java 또는 다른 테스트 파일로 정상적으로 이관되었는지 확인해주세요. 누락된 테스트로 인한 회귀가 없도록 아래 사항을 검증해 주세요.
- auth 모듈의 테스트 디렉토리(예: src/test/java/project/flipnote/auth) 내 AuthServiceTest.java 파일 존재 여부
- 해당 파일 또는 관련 테스트 클래스에 회원가입(register), 비밀번호 변경(changePassword), 소셜 연동(socialLink) 관련 테스트 메서드 포함 여부
src/main/java/project/flipnote/common/security/jwt/JwtComponent.java (4)
15-20: 임포트 변경이 올바르게 적용되었습니다.User 기반에서 Account 기반으로의 전환이 적절히 반영되었습니다.
35-45: 토큰 생성 메서드가 새로운 도메인 모델에 맞게 잘 리팩토링되었습니다.
AuthAccount와AccountAuth를 사용하는 두 가지 오버로드 메서드가 적절히 구현되었습니다.
61-73: 토큰 클레임 설정이 올바르게 업데이트되었습니다.
accountId,userRole,tokenVersion필드가 새로운AccountAuth구조에 맞게 적절히 설정됩니다.
108-115: 토큰 검증 로직이 새로운 Account 모델에 맞게 적절히 수정되었습니다.
accountId를 사용한 토큰 버전 검증이 올바르게 구현되었습니다.src/main/java/project/flipnote/user/controller/UserController.java (2)
15-15: AccountAuth 임포트가 올바르게 변경되었습니다.새로운 인증 모델에 맞게 적절히 업데이트되었습니다.
30-33: 회원 탈퇴 메서드가 새로운 인증 모델에 맞게 잘 수정되었습니다.
AccountAuth와accountId를 사용하여 일관성 있게 구현되었습니다.src/main/java/project/flipnote/user/service/UserService.java (2)
5-12: 이벤트 기반 아키텍처를 위한 임포트가 적절히 추가되었습니다.MSA 전환을 위한 이벤트 기반 통신 구조가 잘 반영되었습니다.
46-49: 이벤트 기반 회원 탈퇴 처리가 잘 구현되었습니다.직접적인 상태 변경 대신 이벤트 발행을 통한 느슨한 결합이 MSA 아키텍처에 적합합니다.
src/main/java/project/flipnote/auth/service/AuthService.java (2)
158-167: 비밀번호 변경 시 토큰 버전 증가가 적절히 구현되었습니다.비밀번호 변경 후 기존 토큰을 무효화하는 보안 조치가 잘 적용되었습니다.
175-182: 소셜 링크 삭제 시 권한 검증이 적절히 구현되었습니다.계정 ID와 소셜 링크 ID를 모두 확인하여 소유권을 검증하는 것이 보안상 올바른 접근입니다.
src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java
Show resolved
Hide resolved
src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java
Show resolved
Hide resolved
src/main/java/project/flipnote/auth/repository/AuthAccountRepository.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (4)
src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java (2)
24-33: 이벤트 처리 로직의 동시성 및 트랜잭션 관리가 필요합니다.현재 구현에서
findByIdAndStatus와withdraw호출 사이에 race condition이 발생할 수 있으며, 트랜잭션 경계가 명확하지 않습니다.
35-38: 복구 메서드의 로깅을 국제화하고 개선해야 합니다.로그 메시지가 한국어로 되어 있어 국제화 관점에서 개선이 필요하고, 더 구체적인 컨텍스트 정보가 필요합니다.
src/main/java/project/flipnote/auth/service/AuthService.java (2)
58-61: MSA 전환에 부적합한 서비스 간 직접 의존성
UserService를 직접 의존성으로 주입받는 것은 MSA 원칙에 위배됩니다. 인증 서비스와 사용자 서비스 간의 강한 결합을 만들어 독립적인 배포와 확장성을 저해합니다.MSA 환경에서는 다음 방법을 고려해보세요:
- REST API 호출을 통한 서비스 간 통신
- 이벤트 기반 비동기 처리 (Event Sourcing)
- API Gateway를 통한 오케스트레이션
63-81: 트랜잭션 일관성 문제 지속회원가입 메서드에서
userService.createUser()와UserAuth저장이 분리된 트랜잭션에서 실행될 가능성이 있습니다. 한쪽이 실패할 경우 데이터 불일치 상태가 발생할 수 있습니다.
🧹 Nitpick comments (3)
src/main/java/project/flipnote/user/entity/UserProfile.java (1)
17-18: 사용되지 않는 import 제거 필요
AccountRole과AccountStatus가 import되었지만 클래스 내에서 실제로 사용되지 않습니다. 리팩토링 과정에서 남은 불필요한 import로 보입니다.-import project.flipnote.auth.entity.AccountRole; -import project.flipnote.auth.entity.AccountStatus;src/main/java/project/flipnote/auth/repository/UserAuthRepository.java (1)
30-32: 토큰 버전 증가 연산의 원자성을 보장해야 합니다.
incrementTokenVersion메서드가 동시성 환경에서 안전한지 확인이 필요합니다. JPA의@Modifying쿼리가 원자적으로 실행되지만, 여러 스레드에서 동시에 호출될 경우를 고려해야 합니다.더 안전한 구현을 위해 낙관적 잠금이나
@Version컬럼 사용을 고려할 수 있습니다:@Modifying @Query("UPDATE UserAuth aa SET aa.tokenVersion = aa.tokenVersion + 1 WHERE aa.userId = :userId AND aa.tokenVersion = :currentVersion") int incrementTokenVersionWithOptimisticLock(@Param("userId") Long userId, @Param("currentVersion") Long currentVersion);src/main/java/project/flipnote/auth/entity/UserAuth.java (1)
69-71: 동시성 환경에서의 토큰 버전 증가 처리를 고려해야 합니다.엔티티 레벨에서의
increaseTokenVersion()메서드는 동시성 문제가 발생할 수 있습니다. Repository의@Modifying쿼리를 사용하는 것이 더 안전합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
src/main/java/project/flipnote/auth/controller/AuthController.java(3 hunks)src/main/java/project/flipnote/auth/controller/OAuthController.java(2 hunks)src/main/java/project/flipnote/auth/entity/AccountStatus.java(1 hunks)src/main/java/project/flipnote/auth/entity/OAuthLink.java(3 hunks)src/main/java/project/flipnote/auth/entity/UserAuth.java(1 hunks)src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java(1 hunks)src/main/java/project/flipnote/auth/model/UserRegisterRequest.java(2 hunks)src/main/java/project/flipnote/auth/repository/OAuthLinkRepository.java(1 hunks)src/main/java/project/flipnote/auth/repository/SocialLinkTokenRedisRepository.java(1 hunks)src/main/java/project/flipnote/auth/repository/TokenVersionRedisRepository.java(1 hunks)src/main/java/project/flipnote/auth/repository/UserAuthRepository.java(1 hunks)src/main/java/project/flipnote/auth/service/AuthService.java(6 hunks)src/main/java/project/flipnote/auth/service/OAuthService.java(4 hunks)src/main/java/project/flipnote/auth/service/TokenVersionService.java(1 hunks)src/main/java/project/flipnote/common/dto/UserCreateCommand.java(1 hunks)src/main/java/project/flipnote/common/security/dto/AuthPrinciple.java(1 hunks)src/main/java/project/flipnote/common/security/filter/JwtAuthenticationFilter.java(3 hunks)src/main/java/project/flipnote/common/security/jwt/JwtComponent.java(3 hunks)src/main/java/project/flipnote/common/security/jwt/JwtConstants.java(1 hunks)src/main/java/project/flipnote/group/controller/GroupController.java(2 hunks)src/main/java/project/flipnote/group/service/GroupService.java(4 hunks)src/main/java/project/flipnote/user/controller/UserController.java(3 hunks)src/main/java/project/flipnote/user/entity/UserProfile.java(3 hunks)src/main/java/project/flipnote/user/entity/UserStatus.java(1 hunks)src/main/java/project/flipnote/user/repository/UserProfileRepository.java(1 hunks)src/main/java/project/flipnote/user/service/UserService.java(2 hunks)src/test/java/project/flipnote/fixture/UserFixture.java(0 hunks)src/test/java/project/flipnote/user/service/UserServiceTest.java(0 hunks)
💤 Files with no reviewable changes (2)
- src/test/java/project/flipnote/fixture/UserFixture.java
- src/test/java/project/flipnote/user/service/UserServiceTest.java
✅ Files skipped from review due to trivial changes (2)
- src/main/java/project/flipnote/common/security/jwt/JwtConstants.java
- src/main/java/project/flipnote/user/repository/UserProfileRepository.java
🚧 Files skipped from review as they are similar to previous changes (17)
- src/main/java/project/flipnote/user/entity/UserStatus.java
- src/main/java/project/flipnote/common/dto/UserCreateCommand.java
- src/main/java/project/flipnote/group/controller/GroupController.java
- src/main/java/project/flipnote/auth/model/UserRegisterRequest.java
- src/main/java/project/flipnote/auth/entity/OAuthLink.java
- src/main/java/project/flipnote/common/security/filter/JwtAuthenticationFilter.java
- src/main/java/project/flipnote/auth/service/TokenVersionService.java
- src/main/java/project/flipnote/auth/repository/OAuthLinkRepository.java
- src/main/java/project/flipnote/auth/repository/SocialLinkTokenRedisRepository.java
- src/main/java/project/flipnote/auth/service/OAuthService.java
- src/main/java/project/flipnote/auth/controller/OAuthController.java
- src/main/java/project/flipnote/group/service/GroupService.java
- src/main/java/project/flipnote/auth/repository/TokenVersionRedisRepository.java
- src/main/java/project/flipnote/common/security/jwt/JwtComponent.java
- src/main/java/project/flipnote/auth/controller/AuthController.java
- src/main/java/project/flipnote/user/controller/UserController.java
- src/main/java/project/flipnote/user/service/UserService.java
🔇 Additional comments (17)
src/main/java/project/flipnote/user/entity/UserProfile.java (5)
24-26: 도메인 분리가 잘 반영된 명명테이블명과 클래스명이 사용자 프로필 데이터에 집중하도록 명확하게 변경되었습니다. MSA 전환을 위한 도메인 분리 원칙에 잘 부합합니다.
54-69: 생성자가 프로필 도메인에 잘 집중됨인증 관련 파라미터들이 제거되고 사용자 프로필 정보에만 집중하도록 잘 리팩토링되었습니다. 기본 상태를 ACTIVE로 설정하는 것도 적절합니다.
71-76: 업데이트 메서드가 프로필 도메인에 적절히 제한됨프로필 관련 필드들만 업데이트하도록 잘 구성되어 있어 도메인 분리 원칙에 부합합니다.
49-51: UserStatus enum import 불필요 확인됨
UserStatusenum이 동일 패키지(project.flipnote.user.entity)에 정의되어 있어 import 없이도 참조 가능하며,
@Enumerated(EnumType.STRING)애노테이션 적용도 적절합니다.
78-82: WITHDRAWN 상수 정의 확인 완료 및 탈퇴 메서드 승인소프트 삭제 로직과
withdraw명명 모두 적절하며, UserStatus enum에WITHDRAWN상수가 정의되어 있어 올바르게 사용되고 있습니다.src/main/java/project/flipnote/auth/entity/AccountStatus.java (1)
1-8: 깔끔한 enum 구현입니다.계정 상태를 나타내는 간단하고 명확한 enum으로, MSA 전환에 적합한 도메인 모델링이 잘 되어 있습니다.
src/main/java/project/flipnote/auth/repository/UserAuthRepository.java (1)
21-23: 비밀번호 암호화 처리 확인됨:updatePassword호출 시 인코딩된 비밀번호 전달
AuthService.java(라인 151) 에서
String encodedPassword = passwordEncoder.encode(req.password());
이후userAuthRepository.updatePassword(email, encodedPassword);호출- 그 외에도 Service 레이어 전반에서
passwordEncoder.encode(...)를 사용하여 암호화된 비밀번호만 전달따라서 Repository 레벨에서 별도의 암호화 검증 로직은 필요하지 않습니다.
src/main/java/project/flipnote/auth/entity/UserAuth.java (2)
47-59: Builder 패턴 구현이 우수합니다.기본값 설정과 필수 필드만 받는 생성자 설계가 깔끔하며, MSA 환경에서 일관된 초기 상태를 보장합니다.
61-67: withdraw 메서드의 원자성을 개선해야 합니다.현재 구현에서
softDelete()와 상태 변경,increaseTokenVersion()호출이 분리되어 있어 일부만 성공할 위험이 있습니다.메서드를 더 원자적으로 만들기 위해 다음과 같이 개선할 수 있습니다:
public void withdraw() { + // 모든 상태 변경을 한 번에 수행 + this.status = AccountStatus.WITHDRAWN; + this.tokenVersion++; super.softDelete(); - - this.status = AccountStatus.WITHDRAWN; - - increaseTokenVersion(); }Likely an incorrect or invalid review comment.
src/main/java/project/flipnote/common/security/dto/AuthPrinciple.java (2)
13-23: Record 구조와 Spring Security 통합이 우수합니다.인증 주체 정보를 담은 불변 레코드로서 깔끔하게 설계되었고, Spring Security와의 통합도 적절합니다.
25-29: UserAuth 엔티티로부터의 변환이 안전합니다.null 체크는 JPA 엔티티의 제약 조건에 의해 보장되므로 현재 구현이 적절합니다.
src/main/java/project/flipnote/auth/service/AuthService.java (6)
84-88: 인증 엔티티 분리에 따른 적절한 수정
UserAuth엔티티를 사용하도록 로그인 로직이 올바르게 수정되었습니다. 인증 데이터와 사용자 프로필 데이터의 분리가 명확해졌습니다.
123-125: 보안 DTO 도입으로 인한 적절한 수정토큰에서
AuthPrincipleDTO를 추출하도록 변경된 것은 보안 계층의 추상화를 개선합니다. 토큰 처리 로직이 더 명확해졌습니다.
157-166: 보안을 고려한 우수한 비밀번호 변경 구현현재 비밀번호 검증, 새 비밀번호 암호화, 토큰 버전 증가까지 포함된 완전한 비밀번호 변경 로직입니다. 기존 토큰 무효화를 통한 보안 강화가 잘 구현되었습니다.
168-181: 소셜 링크 관리 기능의 올바른 구현소셜 링크 조회 및 삭제 기능이 적절한 권한 검증과 함께 구현되었습니다. 특히
deleteSocialLink에서 소유권 검증을 통해 보안이 강화되었습니다.
195-209: 헬퍼 메서드들의 일관된 리팩토링
UserAuth엔티티와AccountStatus를 사용하도록 헬퍼 메서드들이 일관되게 수정되었습니다. 활성 계정 상태 확인 로직이 명확해졌습니다.
152-152: 비밀번호 재설정 로직의 적절한 수정
UserAuthRepository를 사용하도록 비밀번호 업데이트 로직이 올바르게 수정되었습니다.
| public static AuthPrinciple from(Claims claims) { | ||
| long authId = Long.parseLong(claims.getId()); | ||
| long userId = claims.get(JwtConstants.USER_ID, Long.class); | ||
| AccountRole userRole = AccountRole.from( | ||
| claims.get(JwtConstants.ROLE, String.class) | ||
| ); | ||
| String email = claims.getSubject(); | ||
| long tokenVersion = claims.get(JwtConstants.TOKEN_VERSION, Long.class); | ||
|
|
||
| return new AuthPrinciple(authId, userId, email, userRole, tokenVersion); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT Claims 파싱 시 예외 처리를 강화해야 합니다.
Long.parseLong()와 claims.get() 호출에서 예외가 발생할 수 있지만 처리되지 않고 있습니다.
다음과 같이 안전한 파싱을 구현하는 것을 권장합니다:
public static AuthPrinciple from(Claims claims) {
- long authId = Long.parseLong(claims.getId());
- long userId = claims.get(JwtConstants.USER_ID, Long.class);
- AccountRole userRole = AccountRole.from(
- claims.get(JwtConstants.ROLE, String.class)
- );
- String email = claims.getSubject();
- long tokenVersion = claims.get(JwtConstants.TOKEN_VERSION, Long.class);
+ try {
+ long authId = Long.parseLong(claims.getId());
+ long userId = Optional.ofNullable(claims.get(JwtConstants.USER_ID, Long.class))
+ .orElseThrow(() -> new IllegalArgumentException("Missing USER_ID in claims"));
+ AccountRole userRole = AccountRole.from(
+ Optional.ofNullable(claims.get(JwtConstants.ROLE, String.class))
+ .orElseThrow(() -> new IllegalArgumentException("Missing ROLE in claims"))
+ );
+ String email = Optional.ofNullable(claims.getSubject())
+ .orElseThrow(() -> new IllegalArgumentException("Missing email in claims"));
+ long tokenVersion = Optional.ofNullable(claims.get(JwtConstants.TOKEN_VERSION, Long.class))
+ .orElseThrow(() -> new IllegalArgumentException("Missing TOKEN_VERSION in claims"));
- return new AuthPrinciple(authId, userId, email, userRole, tokenVersion);
+ return new AuthPrinciple(authId, userId, email, userRole, tokenVersion);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid authId format in JWT claims", e);
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static AuthPrinciple from(Claims claims) { | |
| long authId = Long.parseLong(claims.getId()); | |
| long userId = claims.get(JwtConstants.USER_ID, Long.class); | |
| AccountRole userRole = AccountRole.from( | |
| claims.get(JwtConstants.ROLE, String.class) | |
| ); | |
| String email = claims.getSubject(); | |
| long tokenVersion = claims.get(JwtConstants.TOKEN_VERSION, Long.class); | |
| return new AuthPrinciple(authId, userId, email, userRole, tokenVersion); | |
| } | |
| public static AuthPrinciple from(Claims claims) { | |
| try { | |
| long authId = Long.parseLong(claims.getId()); | |
| long userId = Optional.ofNullable(claims.get(JwtConstants.USER_ID, Long.class)) | |
| .orElseThrow(() -> new IllegalArgumentException("Missing USER_ID in claims")); | |
| AccountRole userRole = AccountRole.from( | |
| Optional.ofNullable(claims.get(JwtConstants.ROLE, String.class)) | |
| .orElseThrow(() -> new IllegalArgumentException("Missing ROLE in claims")) | |
| ); | |
| String email = Optional.ofNullable(claims.getSubject()) | |
| .orElseThrow(() -> new IllegalArgumentException("Missing email in claims")); | |
| long tokenVersion = Optional.ofNullable(claims.get(JwtConstants.TOKEN_VERSION, Long.class)) | |
| .orElseThrow(() -> new IllegalArgumentException("Missing TOKEN_VERSION in claims")); | |
| return new AuthPrinciple(authId, userId, email, userRole, tokenVersion); | |
| } catch (NumberFormatException e) { | |
| throw new IllegalArgumentException("Invalid authId format in JWT claims", e); | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/main/java/project/flipnote/common/security/dto/AuthPrinciple.java lines
31 to 41, the method from(Claims claims) parses JWT claims without handling
potential exceptions from Long.parseLong() and claims.get() calls. To fix this,
wrap the parsing logic in try-catch blocks to catch and handle exceptions such
as NumberFormatException or ClassCastException, and provide fallback values or
throw a custom exception with a clear message to ensure robust and safe JWT
claims parsing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/main/java/project/flipnote/auth/service/AuthService.java (1)
63-81: 회원가입 로직의 트랜잭션 일관성과 MSA 원칙 준수 필요현재 구현에서 여전히 다음 문제들이 존재합니다:
userService.createUser()와UserAuth저장이 분리된 트랜잭션에서 실행될 가능성- 서비스 간 직접 호출로 인한 강한 결합
이는 이전 리뷰에서 지적된 동일한 문제들입니다.
🧹 Nitpick comments (1)
src/main/java/project/flipnote/auth/service/AuthService.java (1)
47-227: MSA 전환을 위한 리팩토링이 전반적으로 성공적으로 수행되었습니다.인증 도메인이 User에서 UserAuth로 성공적으로 분리되었고, 트랜잭션 관리, 보안, 에러 처리 등이 일관성 있게 구현되어 있습니다. 새로운 기능들(회원가입, 비밀번호 변경, 소셜 링크 관리)도 적절히 추가되었습니다.
다만 UserService에 대한 직접 의존성은 여전히 서비스 간 결합도를 높이는 요소로 남아있어, 향후 완전한 MSA 전환 시 고려가 필요합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/main/java/project/flipnote/auth/controller/AuthController.java(2 hunks)src/main/java/project/flipnote/auth/controller/OAuthController.java(2 hunks)src/main/java/project/flipnote/auth/controller/docs/AuthControllerDocs.java(1 hunks)src/main/java/project/flipnote/auth/controller/docs/OAuthControllerDocs.java(1 hunks)src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java(1 hunks)src/main/java/project/flipnote/auth/repository/UserAuthRepository.java(1 hunks)src/main/java/project/flipnote/auth/service/AuthService.java(6 hunks)src/main/java/project/flipnote/common/config/SwaggerConfig.java(1 hunks)src/main/java/project/flipnote/user/controller/UserController.java(2 hunks)src/main/java/project/flipnote/user/controller/docs/UserControllerDocs.java(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- src/main/java/project/flipnote/user/controller/docs/UserControllerDocs.java
- src/main/java/project/flipnote/auth/controller/docs/AuthControllerDocs.java
- src/main/java/project/flipnote/auth/controller/docs/OAuthControllerDocs.java
🚧 Files skipped from review as they are similar to previous changes (5)
- src/main/java/project/flipnote/auth/listener/UserWithdrawnEventListener.java
- src/main/java/project/flipnote/auth/repository/UserAuthRepository.java
- src/main/java/project/flipnote/auth/controller/AuthController.java
- src/main/java/project/flipnote/auth/controller/OAuthController.java
- src/main/java/project/flipnote/user/controller/UserController.java
🔇 Additional comments (11)
src/main/java/project/flipnote/common/config/SwaggerConfig.java (2)
19-29: Bearer 토큰 기반 인증으로의 단순화가 MSA 전환에 적합합니다.쿠키 기반 refresh-token에서 Bearer JWT 토큰 방식으로의 전환은 MSA 아키텍처에 매우 적합한 선택입니다. Stateless한 인증 방식은 서비스 간 통신과 확장성에 유리합니다.
29-29: 29번 라인 변경 검토 결과
닫는 괄호 이동만 표시된 것으로, 실제로는refresh-token-cookie관련 코드가 모두 삭제되었습니다.주요 변경 사항:
- SecurityRequirement에서
.addList("refresh-token-cookie")제거- Components에서
addSecuritySchemes("refresh-token-cookie", …)블록 전체 삭제29번 라인의 변경 표시는 위 삭제에 따른 괄호 정렬 차이일 뿐이며, 실제 변경 내역은 위 두 부분입니다.
src/main/java/project/flipnote/auth/service/AuthService.java (9)
3-61: 임포트 및 의존성 주입이 적절하게 구성되었습니다.MSA 전환을 위한 리팩토링에 필요한 새로운 엔티티와 레포지토리들이 올바르게 임포트되었고, 의존성 주입도 Spring 패턴을 따르고 있습니다.
83-89: 로그인 로직이 올바르게 리팩토링되었습니다.UserAuth 엔티티를 사용하도록 업데이트되었고, 활성 계정 조회와 비밀번호 검증 로직이 적절하게 구현되어 있습니다.
91-102: 이메일 인증 코드 발송 로직이 적절하게 수정되었습니다.회원가입 플로우에 맞게 이메일 중복 검증으로 변경된 것이 올바른 접근입니다.
115-126: 토큰 갱신 로직이 새로운 인증 모델에 맞게 적절히 업데이트되었습니다.AuthPrinciple 사용으로 변경된 것이 일관성 있고 올바른 접근입니다.
128-155: 비밀번호 재설정 로직이 UserAuth 모델에 맞게 올바르게 업데이트되었습니다.활성 계정 확인과 비밀번호 업데이트 로직이 새로운 아키텍처에 적절히 적응되었고, 보안 조치들이 잘 유지되고 있습니다.
157-166: 비밀번호 변경 메서드가 보안 모범 사례를 잘 따르고 있습니다.현재 비밀번호 검증, 엔티티 메서드를 통한 비밀번호 업데이트, 토큰 버전 증가를 통한 기존 토큰 무효화까지 적절하게 구현되어 있습니다.
168-172: 소셜 링크 조회 메서드가 간결하고 올바르게 구현되었습니다.레포지토리 패턴을 적절히 사용하고 있으며 로직이 명확합니다.
174-181: 소셜 링크 삭제 메서드가 보안을 고려하여 올바르게 구현되었습니다.소유권 검증 후 삭제하는 로직이 적절하며, 사용자가 자신의 링크만 삭제할 수 있도록 보안이 잘 구현되어 있습니다.
183-226: 헬퍼 메서드들이 새로운 인증 모델에 맞게 적절히 업데이트되었습니다.이메일 인증 확인, 활성 계정 조회, 이메일 중복 검증 등의 로직이 UserAuth 모델과 일관성 있게 구현되었고, 에러 처리 패턴도 통일되어 있습니다.
📝 변경 내용
✅ 체크리스트
💬 기타 참고 사항
Summary by CodeRabbit
신규 기능
변경 사항
버그 수정
테스트
기타