-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 서비스 로그아웃 기능 추가 #5
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
- 게스트/카카오 로그인 플로우를 분리 - loginWithGuest, loginOrRegisterWithKakao 메서드로 역할 명확히 구분 - 인증 로직 구조 개선 및 가독성 향상 - 카카오 프로필 데이터 구조를 단순화하여 필요한 정보만 사용하도록 변경
Walkthrough이번 변경은 카카오 OAuth 연동의 구조적 리팩토링과 로그아웃 기능 추가, 사용자 도메인 서비스 분리, DTO 및 엔티티 구조 정비, 테스트 코드 및 설정 파일 확장 등 인증/사용자 관리 전반에 걸쳐 대규모 개선을 수행합니다. 카카오 관련 설정이 외부화되고, 서비스 계층이 세분화되었으며, 로그아웃 및 토큰 발급 로직이 명확해졌습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant AuthController
participant AuthService
participant KakaoClient
participant CommandUserService
participant QueryUserService
participant JwtProvider
Client->>AuthController: GET /api/v1/oauth/kakao/callback?code=XXX
AuthController->>AuthService: loginOrRegisterWithKakao(code)
AuthService->>KakaoClient: join(code)
KakaoClient-->>AuthService: KakaoTokenResponse
AuthService->>KakaoClient: getKakaoProfile(accessToken)
KakaoClient-->>AuthService: KakaoProfile
AuthService->>CommandUserService: getOrCreateUser(UserSaveRequest)
CommandUserService->>UserReader: findByKakaoId
alt not found
CommandUserService->>UserCreator: createUser
UserCreator-->>CommandUserService: User
end
CommandUserService-->>AuthService: User
AuthService->>JwtProvider: generateToken(User)
JwtProvider-->>AuthService: TokenResponse
AuthService-->>AuthController: TokenResponse
AuthController-->>Client: Set-Cookie(accessToken), redirect
%% 로그아웃 시나리오
Client->>AuthController: GET /api/v1/logout (with accessToken)
AuthController->>JwtService: getUserId(token)
JwtService-->>AuthController: userId
AuthController->>AuthService: logout(userId)
AuthService->>QueryUserService: findKakaoIdById(userId)
QueryUserService-->>AuthService: kakaoId
alt kakaoId exists
AuthService->>KakaoClient: logout(kakaoId)
KakaoClient-->>AuthService: KakaoLogoutResponse
AuthService-->>AuthController: void
else kakaoId null
AuthService-->>AuthController: void
end
AuthController-->>Client: JSON 메시지 + 쿠키 만료
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (7)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
🧰 Additional context used🧠 Learnings (1)src/main/java/com/dnd/moddo/domain/auth/service/AuthService.java (1)🧬 Code Graph Analysis (1)src/test/java/com/dnd/moddo/domain/auth/service/AuthServiceTest.java (3)
🔇 Additional comments (8)
🪧 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: 7
🧹 Nitpick comments (17)
src/main/java/com/dnd/moddo/global/config/CookieProperties.java (1)
7-15: 설정 클래스 구조는 우수하나 개선점이 있습니다.record 클래스와 ConfigurationProperties 사용이 적절하며, 필드 타입들도 올바르게 선택되었습니다.
다음과 같은 개선사항을 고려해보세요:
@ConfigurationProperties(prefix = "cookie") public record CookieProperties( + /** + * HTTP-only 쿠키 설정 여부 + */ + @DefaultValue("true") boolean httpOnly, + /** + * HTTPS 환경에서만 쿠키 전송 여부 + */ + @DefaultValue("false") boolean secure, + /** + * 쿠키 경로 + */ + @DefaultValue("/") String path, + /** + * SameSite 쿠키 정책 + */ + @DefaultValue("Lax") String sameSite, + /** + * 쿠키 만료 시간 + */ + @DefaultValue("PT24H") Duration maxAge ) { }이렇게 하면 설정 파일이 없거나 일부 값이 누락되어도 안전한 기본값으로 동작할 수 있습니다.
src/test/java/com/dnd/moddo/domain/user/entity/UserTest.java (1)
30-30: 사용되지 않는 변수를 제거해주세요.
LocalDateTime time변수가 선언되었지만 사용되지 않고 있습니다. 팩토리 메서드에서 시간을 처리하므로 이 변수는 제거할 수 있습니다.다음과 같이 수정해주세요:
- LocalDateTime time = LocalDateTime.now(); -src/test/java/com/dnd/moddo/domain/user/service/queryUserServiceTest.java (2)
18-18: 클래스명 네이밍 컨벤션을 수정해주세요.Java 클래스명은 PascalCase를 사용해야 합니다.
queryUserServiceTest를QueryUserServiceTest로 변경해주세요.- public class queryUserServiceTest { + public class QueryUserServiceTest {
30-30: Mockito 스터빙에서 구체적인 매개변수를 사용하세요.
any()를 사용하는 대신 실제 매개변수 값을 사용하는 것이 더 정확한 테스트가 됩니다.다음과 같이 수정해보세요:
- when(userReader.findKakaoIdById(any())).thenReturn(Optional.of(kakaoId)); + when(userReader.findKakaoIdById(userId)).thenReturn(Optional.of(kakaoId));- when(userReader.findKakaoIdById(any())).thenReturn(Optional.empty()); + when(userReader.findKakaoIdById(1L)).thenReturn(Optional.empty());Also applies to: 42-42
src/test/resources/application.yml (1)
54-54: 파일 끝에 개행 문자를 추가해주세요.YAML 파일 표준에 따라 파일 마지막에 개행 문자가 필요합니다.
- logout-request-uri: https://kapi.kakao.com/v1/user/logout + logout-request-uri: https://kapi.kakao.com/v1/user/logout +src/test/java/com/dnd/moddo/domain/user/service/implementation/UserReaderTest.java (1)
26-40: 테스트 커버리지를 확장하여 UserReader의 모든 기능을 검증해주세요.현재
findByKakaoId메서드만 테스트하고 있지만,UserReader에는findKakaoIdById메서드도 있습니다. 또한 사용자를 찾지 못하는 경우에 대한 테스트도 추가하면 좋겠습니다.추가 테스트 메서드 예시:
@DisplayName("존재하지 않는 kakaoId로 User를 조회하면 빈 Optional을 반환한다") @Test void whenFindByNonExistentKakaoId_thenReturnEmptyOptional() { // given Long nonExistentKakaoId = 999L; when(userRepository.findByKakaoId(nonExistentKakaoId)).thenReturn(Optional.empty()); // when Optional<User> result = userReader.findByKakaoId(nonExistentKakaoId); // then assertThat(result).isEmpty(); verify(userRepository, times(1)).findByKakaoId(nonExistentKakaoId); } @DisplayName("userId로 kakaoId를 조회하면 해당 kakaoId를 반환한다") @Test void whenFindKakaoIdById_thenReturnKakaoId() { // given Long userId = 1L; Long expectedKakaoId = 12345L; when(userRepository.findKakaoIdById(userId)).thenReturn(Optional.of(expectedKakaoId)); // when Optional<Long> result = userReader.findKakaoIdById(userId); // then assertThat(result).isPresent(); assertThat(result.get()).isEqualTo(expectedKakaoId); verify(userRepository, times(1)).findKakaoIdById(userId); }src/test/java/com/dnd/moddo/domain/user/service/CommandUserServiceTest.java (1)
75-89: 테스트 메서드명을 더 구체적으로 개선하세요.메서드명
getOrCreateUser()는 테스트 의도를 명확히 표현하지 못합니다. 기존 유저를 반환하는 시나리오임을 명시하는 것이 좋겠습니다.- void getOrCreateUser() { + void whenUserExists_thenReturnExistingUser() {src/main/java/com/dnd/moddo/domain/user/service/CommandUserService.java (1)
30-34: getOrCreateUser 메서드의 트랜잭션 범위를 검토하세요.현재
@Transactional이 전체 메서드에 적용되어 있지만,userReader.findByKakaoId()는 읽기 전용 작업입니다. 성능 최적화를 위해 읽기와 쓰기 작업의 트랜잭션을 분리하는 것을 고려해보세요.+ @Transactional(readOnly = true) public User getOrCreateUser(UserSaveRequest request) { - return userReader.findByKakaoId(request.kakaoId()) - .orElseGet(() -> createKakaoUser(request)); + Optional<User> existingUser = userReader.findByKakaoId(request.kakaoId()); + if (existingUser.isPresent()) { + return existingUser.get(); + } + return createKakaoUserTransactional(request); } + + @Transactional + private User createKakaoUserTransactional(UserSaveRequest request) { + return createKakaoUser(request); + }src/test/java/com/dnd/moddo/global/support/UserTestFactory.java (1)
41-54: 하드코딩된 kakaoId 값을 파라미터화하는 것을 고려하세요.현재
kakaoId가1234565L로 하드코딩되어 있습니다. 테스트에서 다양한 kakaoId 값이 필요할 수 있으므로 파라미터로 받을 수 있는 오버로드 메서드를 추가하는 것이 좋겠습니다.+ public static User createWithEmailAndKakaoId(String email, Long kakaoId) { + LocalDateTime time = LocalDateTime.now(); + return User + .builder() + .name("연노른자") + .email(email) + .profile("profile.png") + .isMember(true) + .kakaoId(kakaoId) + .authority(USER) + .createdAt(time) + .expiredAt(time.plusDays(7)) + .build(); + }src/main/java/com/dnd/moddo/global/jwt/service/JwtService.java (1)
15-30: 입력 파라미터 검증 추가를 고려하세요.null 체크나 빈 문자열 검증을 추가하여 더 안전한 서비스를 만들 수 있습니다.
public Long getId(HttpServletRequest request, String key) { + if (request == null || key == null || key.trim().isEmpty()) { + throw new IllegalArgumentException("Request and key must not be null or empty"); + } String token = jwtUtil.resolveToken(request); return jwtUtil.getIdFromToken(token, key); } public Long getUserId(String token) { + if (token == null || token.trim().isEmpty()) { + throw new IllegalArgumentException("Token must not be null or empty"); + } return jwtUtil.getIdFromToken(token, "userId"); }src/main/java/com/dnd/moddo/domain/user/entity/User.java (2)
39-39: 카카오 ID 필드에 대한 데이터베이스 제약 조건 추가 고려카카오 ID의 유일성을 보장하기 위해
@Column(unique = true)어노테이션 추가를 고려해보세요.- private Long kakaoId; + @Column(unique = true) + private Long kakaoId;
48-59: 생성자 파라미터 순서 일관성 검토생성자의 파라미터 순서가 필드 선언 순서와 일치하지 않습니다. 가독성을 위해 일관성을 맞추는 것을 고려해보세요.
@Builder -public User(String name, String email, String profile, Boolean isMember, Authority authority, Long kakaoId, +public User(String name, String email, String profile, Boolean isMember, Long kakaoId, Authority authority, LocalDateTime createdAt, LocalDateTime expiredAt) { this.name = name; this.email = email; this.profile = profile; this.isMember = isMember; this.kakaoId = kakaoId; - this.createdAt = createdAt; - this.expiredAt = expiredAt; this.authority = authority; + this.createdAt = createdAt; + this.expiredAt = expiredAt; }src/main/java/com/dnd/moddo/domain/user/repository/UserRepository.java (1)
19-20: 카카오 ID 조회 쿼리 최적화 고려현재 JPQL 쿼리는 정상 작동하지만, 인덱스 성능을 고려하여 메서드 기반 쿼리 사용을 검토해보세요.
-@Query("SELECT u.kakaoId FROM User u WHERE u.id = :userId") -Optional<Long> findKakaoIdById(Long userId); +Optional<Long> findKakaoIdById(Long userId);만약 Spring Data JPA가 자동으로 생성하는 메서드로 충분하다면
@Query어노테이션을 제거할 수 있습니다.src/test/java/com/dnd/moddo/domain/auth/service/AuthServiceTest.java (1)
107-119: 로그아웃 실패 케이스 테스트 개선 제안예외 메시지 검증은 좋지만, 더 구체적인 예외 타입을 사용하는 것을 고려해보세요.
- assertThatThrownBy(() -> authService.logout(1L)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("로그아웃 실패"); + assertThatThrownBy(() -> authService.logout(1L)) + .isInstanceOf(KakaoLogoutException.class) + .hasMessageContaining("로그아웃 실패");더 구체적인 예외 타입을 사용하면 예외 처리가 더 명확해집니다.
src/test/java/com/dnd/moddo/domain/auth/service/KakaoClientTest.java (1)
176-176: 테스트 메서드명 오타를 수정해주세요.
henCallKakaoLogout→whenCallKakaoLogout으로 수정이 필요합니다.-void henCallKakaoLogout_withServerError_thenThrowException() { +void whenCallKakaoLogout_withServerError_thenThrowException() {src/main/java/com/dnd/moddo/domain/auth/service/AuthService.java (1)
65-77: 로그아웃 로직이 적절히 구현되었습니다.카카오 ID가 없는 경우의 처리와 ID 불일치 검증이 잘 되었습니다. 다만 75번 라인의 불필요한 공백을 제거해주세요.
- } - + } +src/main/java/com/dnd/moddo/domain/auth/controller/AuthController.java (1)
67-74: 로그아웃 엔드포인트가 잘 구현되었습니다.쿠키 만료와 카카오 로그아웃을 함께 처리하는 것이 적절합니다. 다만,
accessToken쿠키가 없는 경우를 대비해required = false옵션 추가를 고려해보세요.-public ResponseEntity<?> kakaoLogout(@CookieValue(value = "accessToken") String token) { +public ResponseEntity<?> kakaoLogout(@CookieValue(value = "accessToken", required = false) String token) { + if (token == null) { + return ResponseEntity.ok() + .body(Collections.singletonMap("message", "Already logged out")); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (40)
.github/workflows/cicd.yml(1 hunks)src/main/java/com/dnd/moddo/ModdoApplication.java(1 hunks)src/main/java/com/dnd/moddo/domain/auth/controller/AuthController.java(4 hunks)src/main/java/com/dnd/moddo/domain/auth/dto/KakaoLogoutResponse.java(1 hunks)src/main/java/com/dnd/moddo/domain/auth/dto/KakaoProfile.java(1 hunks)src/main/java/com/dnd/moddo/domain/auth/dto/KakaoTokenResponse.java(1 hunks)src/main/java/com/dnd/moddo/domain/auth/service/AuthService.java(2 hunks)src/main/java/com/dnd/moddo/domain/auth/service/KakaoClient.java(4 hunks)src/main/java/com/dnd/moddo/domain/auth/service/RefreshTokenService.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/dto/request/GuestUserSaveRequest.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/dto/request/UserSaveRequest.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/entity/User.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/repository/UserRepository.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/service/CommandUserService.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/service/QueryUserService.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/service/implementation/UserCreator.java(1 hunks)src/main/java/com/dnd/moddo/domain/user/service/implementation/UserReader.java(1 hunks)src/main/java/com/dnd/moddo/global/config/CookieProperties.java(1 hunks)src/main/java/com/dnd/moddo/global/config/KakaoProperties.java(1 hunks)src/main/java/com/dnd/moddo/global/config/PropertiesConfig.java(0 hunks)src/main/java/com/dnd/moddo/global/jwt/properties/JwtProperties.java(1 hunks)src/main/java/com/dnd/moddo/global/jwt/service/JwtService.java(1 hunks)src/main/java/com/dnd/moddo/global/jwt/utill/JwtProvider.java(3 hunks)src/main/resources/application.yml(1 hunks)src/main/resources/config(1 hunks)src/test/java/com/dnd/moddo/domain/auth/controller/AuthControllerTest.java(5 hunks)src/test/java/com/dnd/moddo/domain/auth/service/AuthServiceTest.java(2 hunks)src/test/java/com/dnd/moddo/domain/auth/service/KakaoClientTest.java(8 hunks)src/test/java/com/dnd/moddo/domain/auth/service/RefreshTokenServiceTest.java(2 hunks)src/test/java/com/dnd/moddo/domain/group/controller/GroupControllerTest.java(5 hunks)src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupCreatorTest.java(2 hunks)src/test/java/com/dnd/moddo/domain/user/entity/UserTest.java(1 hunks)src/test/java/com/dnd/moddo/domain/user/service/CommandUserServiceTest.java(1 hunks)src/test/java/com/dnd/moddo/domain/user/service/implementation/UserCreatorTest.java(1 hunks)src/test/java/com/dnd/moddo/domain/user/service/implementation/UserReaderTest.java(1 hunks)src/test/java/com/dnd/moddo/domain/user/service/queryUserServiceTest.java(1 hunks)src/test/java/com/dnd/moddo/global/support/UserTestFactory.java(1 hunks)src/test/java/com/dnd/moddo/global/util/ControllerTest.java(2 hunks)src/test/java/com/dnd/moddo/integration/CacheIntegrationTest.java(2 hunks)src/test/resources/application.yml(1 hunks)
💤 Files with no reviewable changes (1)
- src/main/java/com/dnd/moddo/global/config/PropertiesConfig.java
🧰 Additional context used
🧬 Code Graph Analysis (10)
src/test/java/com/dnd/moddo/domain/user/entity/UserTest.java (2)
src/test/java/com/dnd/moddo/global/support/UserTestFactory.java (1)
UserTestFactory(10-55)src/main/java/com/dnd/moddo/domain/user/exception/UserNotFoundException.java (1)
UserNotFoundException(6-12)
src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupCreatorTest.java (1)
src/test/java/com/dnd/moddo/global/support/UserTestFactory.java (1)
UserTestFactory(10-55)
src/main/java/com/dnd/moddo/domain/user/service/implementation/UserCreator.java (2)
src/main/java/com/dnd/moddo/domain/user/service/implementation/UserReader.java (1)
Service(13-26)src/main/java/com/dnd/moddo/domain/user/service/CommandUserService.java (1)
RequiredArgsConstructor(14-35)
src/test/java/com/dnd/moddo/domain/user/service/implementation/UserCreatorTest.java (3)
src/test/java/com/dnd/moddo/global/support/UserTestFactory.java (1)
UserTestFactory(10-55)src/test/java/com/dnd/moddo/domain/user/service/implementation/UserReaderTest.java (1)
ExtendWith(19-41)src/test/java/com/dnd/moddo/domain/user/service/CommandUserServiceTest.java (1)
ExtendWith(21-90)
src/test/java/com/dnd/moddo/domain/auth/service/RefreshTokenServiceTest.java (1)
src/test/java/com/dnd/moddo/global/support/UserTestFactory.java (1)
UserTestFactory(10-55)
src/test/java/com/dnd/moddo/domain/user/service/implementation/UserReaderTest.java (2)
src/test/java/com/dnd/moddo/global/support/UserTestFactory.java (1)
UserTestFactory(10-55)src/test/java/com/dnd/moddo/domain/user/service/implementation/UserCreatorTest.java (1)
ExtendWith(17-40)
src/main/java/com/dnd/moddo/domain/user/entity/User.java (1)
src/main/java/com/dnd/moddo/domain/groupMember/entity/GroupMember.java (1)
NoArgsConstructor(25-82)
src/main/java/com/dnd/moddo/domain/user/service/implementation/UserReader.java (3)
src/main/java/com/dnd/moddo/domain/user/service/QueryUserService.java (1)
RequiredArgsConstructor(9-18)src/main/java/com/dnd/moddo/domain/user/service/CommandUserService.java (1)
RequiredArgsConstructor(14-35)src/main/java/com/dnd/moddo/domain/user/service/implementation/UserCreator.java (1)
RequiredArgsConstructor(11-21)
src/test/java/com/dnd/moddo/domain/auth/service/AuthServiceTest.java (3)
src/test/java/com/dnd/moddo/domain/auth/service/KakaoClientTest.java (1)
ExtendWith(27-188)src/test/java/com/dnd/moddo/domain/user/service/CommandUserServiceTest.java (1)
ExtendWith(21-90)src/test/java/com/dnd/moddo/domain/user/service/queryUserServiceTest.java (1)
ExtendWith(17-51)
src/main/java/com/dnd/moddo/domain/user/repository/UserRepository.java (1)
src/main/java/com/dnd/moddo/domain/user/exception/UserNotFoundException.java (1)
UserNotFoundException(6-12)
🪛 YAMLlint (1.37.1)
src/test/resources/application.yml
[error] 54-54: no new line character at the end of file
(new-line-at-end-of-file)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-and-test
🔇 Additional comments (65)
src/test/java/com/dnd/moddo/integration/CacheIntegrationTest.java (2)
6-6: Import 변경이 적절합니다.@afterall로의 변경이 메서드 시그니처 변경과 일치합니다.
67-70: 테스트 격리성 이슈 없음 확인
CacheIntegrationTest클래스에는 현재@Test메서드가 하나뿐이므로, 테스트 간 캐시 공유로 인한 오염 위험은 없습니다.
향후 추가 테스트가 생길 경우 다음을 고려해 주세요:
- 각 테스트마다 고유한 캐시 키 사용
@AfterEach또는 테스트 종료 시점에 캐시 클리어 로직 추가.github/workflows/cicd.yml (1)
76-76: 앱 서비스 정의 확인 완료 – 변경사항 승인합니다.
.github/workflows/cicd.yml의 배포 단계에sudo docker compose pull app명령이 추가된 것은 최신 이미지를 확실히 사용해 배포 일관성을 높이는 적절한 개선입니다.docker-compose.yml파일에서app서비스 정의(image,container_name,ports,logging,restart등)가 올바르게 확인되었습니다.추가 검증이나 수정 없이 이 변경사항을 승인합니다.
src/main/java/com/dnd/moddo/global/config/CookieProperties.java (1)
1-1: 패키지 이동이 적절합니다.
global.config패키지로의 이동은 설정 관련 클래스들을 일관되게 관리하기 위한 좋은 리팩토링입니다.src/main/resources/config (1)
1-1: 서브모듈 커밋 해시 변경 확인 필요서브모듈 포인터가
1ec2dcd…→6515d7b…로 업데이트되었습니다.
- 실제 서브모듈 디렉터리에도
git submodule update --recursive로 최신 소스가 반영됐는지 확인해 주세요.- CI/CD 파이프라인에서 서브모듈이 올바르게 체크아웃되지 않으면 빌드가 실패할 수 있습니다.
특별한 문제는 보이지 않지만, 의도된 버전 업인지 한 번 더 검증 부탁드립니다.
src/main/java/com/dnd/moddo/global/jwt/properties/JwtProperties.java (1)
3-6: 코드 포맷팅 개선이 잘 되었습니다.임포트문 정리와 들여쓰기 표준화로 코드 가독성이 향상되었습니다. 전체적인 설정 프로퍼티 관리 표준화 작업의 일환으로 적절한 변경입니다.
Also applies to: 14-27
src/main/java/com/dnd/moddo/domain/auth/dto/KakaoLogoutResponse.java (1)
1-4: 카카오 로그아웃 응답 DTO가 잘 설계되었습니다.레코드 클래스를 사용하여 불변성과 간결성을 보장하고, 카카오 API 응답 구조에 맞는 단순하고 명확한 설계입니다.
src/main/java/com/dnd/moddo/ModdoApplication.java (1)
6-6: 설정 프로퍼티 자동 스캔 활성화가 적절합니다.
@ConfigurationPropertiesScan어노테이션 추가로 설정 프로퍼티 클래스들의 자동 스캔과 바인딩이 가능해져, 더 간결하고 유지보수하기 쉬운 설정 관리가 가능합니다.Also applies to: 9-9
src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupCreatorTest.java (1)
60-60: 테스트 사용자 생성 방식이 개선되었습니다.
UserTestFactory.createGuestDefault()사용으로 테스트 코드의 일관성과 재사용성이 향상되었습니다. 수동 객체 생성보다 유지보수하기 쉬운 접근법입니다.src/test/java/com/dnd/moddo/global/util/ControllerTest.java (1)
28-28: 테스트 인프라 확장이 적절합니다.
CookiePropertiesMockBean 추가로 확장된 인증 및 쿠키 처리 기능의 컨트롤러 테스트를 지원할 수 있게 되었습니다.Also applies to: 93-94
src/main/resources/application.yml (1)
28-31: 카카오 API URI 설정이 적절히 외부화되었습니다.하드코딩된 URI를 설정 파일로 이동한 것은 좋은 개선입니다. 향후 카카오에서 API 엔드포인트가 변경될 경우 코드 수정 없이 설정만으로 대응할 수 있습니다.
src/test/java/com/dnd/moddo/domain/user/entity/UserTest.java (2)
3-5: 정적 임포트를 통한 코드 가독성 개선이 좋습니다.UserTestFactory와 assertion 메서드들을 정적 임포트로 처리하여 코드가 더 깔끔해졌습니다.
32-33: 팩토리 메서드 사용으로 테스트 코드 일관성이 향상되었습니다.
createGuestWithNameAndEmail메서드를 사용하여 User 객체 생성을 일관성 있게 처리한 것이 좋습니다. 테스트 데이터 생성 로직이 중앙화되어 유지보수가 용이해집니다.src/test/java/com/dnd/moddo/domain/group/controller/GroupControllerTest.java (2)
26-26: HttpServletRequest 임포트 추가가 적절합니다.JwtService 메서드 시그니처 변경에 맞춰 필요한 임포트가 추가되었습니다.
39-39: Mockito 스터빙의 타입 명시로 타입 안전성이 향상되었습니다.
any()에서any(HttpServletRequest.class)로 변경하여 메서드 매개변수 타입을 명시적으로 지정한 것이 좋습니다. 이는 테스트의 타입 안전성을 높이고 JwtService의 변경된 메서드 시그니처와 일치합니다.Also applies to: 60-60, 81-81, 98-98
src/main/java/com/dnd/moddo/domain/user/service/QueryUserService.java (1)
9-12: 서비스 계층 분리와 의존성 주입이 적절합니다.
@Service어노테이션과@RequiredArgsConstructor를 통한 의존성 주입이 Spring의 모범 사례를 따르고 있습니다. 사용자 조회 로직을 별도 서비스로 분리한 것도 단일 책임 원칙에 부합합니다.src/test/java/com/dnd/moddo/domain/user/service/queryUserServiceTest.java (1)
24-36: 테스트 커버리지와 구조가 훌륭합니다.정상 케이스와 예외 케이스를 모두 다루고 있으며, given-when-then 패턴을 명확히 따르고 있습니다.
verify()를 통한 상호작용 검증도 적절합니다.Also applies to: 38-50
src/test/resources/application.yml (1)
48-54: 카카오 설정 구조 개선이 잘 되었습니다.기존의 중첩된
auth구조에서 평면적인 구조로 변경하여 가독성이 향상되었고, 로그아웃 기능을 위한 새로운 URI들이 적절히 추가되었습니다.src/test/java/com/dnd/moddo/domain/auth/service/RefreshTokenServiceTest.java (3)
3-3: 테스트 팩토리 사용으로 코드 일관성이 향상되었습니다.정적 임포트를 통한
UserTestFactory사용은 테스트 코드의 가독성과 일관성을 개선합니다.
61-61: 팩토리 메서드 사용이 적절합니다.
createGuestDefault()메서드 사용으로 테스트 데이터 생성이 표준화되었습니다.
65-65: generateAccessToken 시그니처 일관성 확인 완료rg 검색 결과,
generateAccessToken메서드 호출은 모두Long id와String role두 파라미터만 사용하고 있으며, 이메일 파라미터 호출은 존재하지 않습니다. 변경 사항이 전체 코드베이스에 올바르게 적용된 것으로 확인됩니다.src/main/java/com/dnd/moddo/domain/user/dto/request/GuestUserSaveRequest.java (3)
8-8: 간결한 레코드 클래스 정의가 적절합니다.게스트 사용자 생성에 필요한 최소한의 필드만 포함하여 명확하고 간결합니다.
9-20: 게스트 사용자 엔티티 변환 로직이 적절합니다.게스트 사용자에 적합한 기본값들이 올바르게 설정되었습니다 (kakaoId=null, isMember=false 등).
18-18: 게스트 사용자 만료 기간을 검토해주세요.게스트 사용자의 1개월 만료 기간이 비즈니스 요구사항에 적합한지 확인해주세요. 일반적으로 게스트 사용자는 더 짧은 기간(예: 7일)을 사용하는 경우가 많습니다.
src/test/java/com/dnd/moddo/domain/user/service/implementation/UserCreatorTest.java (2)
17-22: 테스트 클래스 구조가 잘 설계되었습니다.Mockito 확장과 의존성 주입을 적절히 사용한 단위 테스트 구조입니다.
24-39: 단위 테스트 로직이 적절합니다.Given-When-Then 패턴을 따르고, 모킹과 검증이 올바르게 수행되었습니다. UserTestFactory 사용도 일관성을 유지합니다.
src/main/java/com/dnd/moddo/domain/user/dto/request/UserSaveRequest.java (3)
8-12: 카카오 사용자 DTO 구조가 적절합니다.카카오 사용자에 필요한 필드들이 명확하게 정의되었고,
kakaoId필드가 포함되어 게스트 사용자와 구분됩니다.
13-24: 카카오 사용자 엔티티 변환 로직이 올바릅니다.
isMember=true와kakaoId설정으로 카카오 사용자의 특성이 정확히 반영되었습니다.
22-22: 사용자 유형별 만료 기간 정책을 검토해주세요.게스트 사용자와 카카오 사용자 모두 동일한 1개월 만료 기간을 가집니다. 일반적으로 가입된 사용자(카카오 사용자)는 더 긴 만료 기간을 가지거나 만료 없이 유지되는 경우가 많습니다. 비즈니스 정책에 따라 이 부분을 검토해주세요.
src/main/java/com/dnd/moddo/domain/user/service/implementation/UserCreator.java (1)
11-21: 잘 구현된 사용자 생성 서비스입니다.단일 책임 원칙을 잘 따르고 있으며, 트랜잭션 처리와 의존성 주입이 적절히 설정되어 있습니다. CommandUserService에서 사용되는 구조도 명확하고 직관적입니다.
src/main/java/com/dnd/moddo/domain/auth/dto/KakaoTokenResponse.java (1)
5-8: DTO 변경 승인 및 호환성 검증 완료
- 제거된 필드(
token_type,refresh_token,scope,refresh_token_expires_in)는 코드베이스에서 사용되지 않음을 확인했습니다.JwtConstants.REFRESH_KEY("refresh_token")는 JWT 처리용 상수로, 해당 DTO와 직접적인 연관이 없어 영향이 없습니다.문제 없이 머지 진행 가능합니다.
src/main/java/com/dnd/moddo/domain/auth/service/RefreshTokenService.java (1)
34-34: generateAccessToken(Long id, String role) 시그니처가 JwtProvider 및 테스트에 일관되게 반영되었습니다.하지만 아래 사항은 직접 검토해주세요:
- 기존 토큰과의 호환성: 이메일 클레임 제거가 검증 로직에 미치는 영향
- 보안 영향: 이메일 정보 제거로 인한 리스크
src/main/java/com/dnd/moddo/domain/user/service/implementation/UserReader.java (2)
13-17: 클래스 구조가 잘 설계되었습니다.읽기 전용 트랜잭션 어노테이션과 단일 책임 원칙을 잘 따르고 있습니다. CQRS 패턴의 Query 부분을 담당하는 서비스로 적절합니다.
19-25: 메서드 구현이 깔끔하고 안전합니다.Optional을 반환하여 null safety를 보장하고, repository에 적절히 위임하고 있습니다. 메서드명도 의도를 명확히 표현하고 있습니다.
src/test/java/com/dnd/moddo/domain/user/service/CommandUserServiceTest.java (2)
21-28: 테스트 설정이 적절합니다.Mockito 확장과 의존성 주입을 올바르게 구성했습니다.
30-42: 게스트 유저 생성 테스트가 잘 구성되었습니다.AAA 패턴을 따르고 있으며, 필요한 필드들을 모두 검증하고 있습니다.
src/main/java/com/dnd/moddo/domain/user/service/CommandUserService.java (1)
14-18: 서비스 구조가 잘 설계되었습니다.Command와 Query를 분리한 의존성 구조가 CQRS 패턴을 잘 반영하고 있습니다.
src/test/java/com/dnd/moddo/global/support/UserTestFactory.java (1)
14-24: 빌더 패턴 적용과 UUID 사용이 좋은 개선입니다.생성자 직접 호출에서 빌더 패턴으로 변경하여 가독성이 향상되었고, UUID를 사용한 고유 이메일 생성으로 테스트 간 충돌을 방지할 수 있습니다.
src/main/java/com/dnd/moddo/global/jwt/service/JwtService.java (2)
15-18: 범용적인 getId 메서드 추가가 좋은 리팩토링입니다.중복 코드를 제거하고 재사용성을 높인 좋은 설계입니다.
20-26: 메서드 오버로딩이 적절하게 구현되었습니다.HttpServletRequest에서 토큰을 추출하는 방식과 토큰 문자열을 직접 받는 방식 모두를 지원하여 유연성이 향상되었습니다.
src/main/java/com/dnd/moddo/domain/user/entity/User.java (2)
39-39: 카카오 ID 필드 추가 승인카카오 OAuth 연동을 위한
kakaoId필드 추가가 적절합니다.
27-29: ID 필드 위치 이동 승인엔티티의 식별자인
id필드를 클래스 최상단으로 이동한 것이 가독성 향상에 도움이 됩니다.src/main/java/com/dnd/moddo/domain/user/repository/UserRepository.java (2)
17-17: 카카오 ID로 사용자 조회 메서드 추가 승인카카오 로그인 기능을 위한
findByKakaoId메서드 추가가 적절합니다.
22-30: 기본 메서드 포맷팅 개선 승인기존
default메서드들의 들여쓰기와 포맷팅이 일관성 있게 개선되었습니다.src/test/java/com/dnd/moddo/domain/auth/controller/AuthControllerTest.java (3)
36-36: 서비스 메서드명 변경에 따른 테스트 업데이트 승인
loginWithGuest()메서드로 변경된 것이 더 명확한 의미를 전달합니다.
85-90: 카카오 로그인 테스트 메서드 업데이트 승인
KakaoTokenResponse생성과loginOrRegisterWithKakao()메서드 호출 변경이 리팩토링된 서비스와 일치합니다.
110-125: 로그아웃 테스트 로직 승인JWT 서비스를 통한 사용자 ID 추출과 인증 서비스의 로그아웃 호출을 올바르게 테스트하고 있습니다.
src/main/java/com/dnd/moddo/global/jwt/utill/JwtProvider.java (4)
26-28: 액세스 토큰 생성에서 이메일 제거 승인토큰에서 이메일 정보를 제거하여 토큰 크기를 최적화한 것이 좋습니다.
30-32: User 엔티티 기반 토큰 생성 메서드 추가 승인User 엔티티에서 직접 정보를 추출하여 토큰을 생성하는 방식이 더 깔끔합니다.
47-57: JWT 클레임에서 이메일 제거 승인JWT 페이로드에서 이메일 클레임을 제거하여 토큰을 경량화한 것이 보안과 성능 측면에서 바람직합니다.
34-41: 이메일 파라미터 제거 검증 완료
generateToken호출 시 이메일 인자를 사용하는 부분이 전체 코드베이스에서 발견되지 않았습니다.src/test/java/com/dnd/moddo/domain/auth/service/AuthServiceTest.java (5)
28-30: 서비스 레이어 추상화에 따른 Mock 변경 승인직접적인 레포지토리 의존성 대신
CommandUserService와QueryUserService를 사용하는 것이 더 나은 테스트 구조입니다.
41-46: 게스트 사용자 생성 테스트 업데이트 승인서비스 레이어를 통한 사용자 생성 테스트가 올바르게 구현되었습니다.
49-79: 카카오 로그인 테스트 리팩토링 승인메서드명 변경과 서비스 의존성 업데이트가 적절합니다.
KakaoTokenResponse생성도 단순화되어 좋습니다.
81-93: 카카오 로그아웃 성공 케이스 테스트 승인카카오 ID가 일치할 때의 정상적인 로그아웃 플로우를 잘 테스트하고 있습니다.
95-105: 게스트 사용자 로그아웃 테스트 승인카카오 ID가 null인 경우 카카오 로그아웃 호출을 하지 않는 로직을 올바르게 검증하고 있습니다.
src/main/java/com/dnd/moddo/domain/auth/dto/KakaoProfile.java (1)
1-25: DTO 구조 단순화가 적절합니다.필요한 필드만 유지하여 코드가 깔끔해졌습니다.
@JsonProperty어노테이션을 사용한 snake_case to camelCase 매핑도 적절합니다.src/test/java/com/dnd/moddo/domain/auth/service/KakaoClientTest.java (3)
11-12: KakaoProperties 설정 중앙화가 잘 적용되었습니다.설정값을 하나의 configuration 클래스로 관리하는 것은 좋은 패턴입니다.
Also applies to: 24-24, 29-29, 37-38
49-50: 테스트가 설정 변경사항을 잘 반영했습니다.모든 하드코딩된 URL과 설정값이
kakaoProperties를 통해 관리되도록 일관성 있게 변경되었습니다.Also applies to: 55-56, 59-59, 80-81, 84-84, 106-112, 117-117, 128-128, 138-138
148-172: 로그아웃 테스트가 적절히 추가되었습니다.성공 케이스와 실패 케이스를 모두 검증하는 것이 좋습니다.
Also applies to: 174-187
src/main/java/com/dnd/moddo/domain/auth/service/KakaoClient.java (1)
12-12: 설정 중앙화 및 코드 개선이 잘 되었습니다.
KakaoProperties를 통한 설정 관리와MediaType상수 사용이 코드 품질을 향상시켰습니다.Also applies to: 15-15, 25-25, 31-31, 35-36, 42-42, 60-60
src/main/java/com/dnd/moddo/domain/auth/service/AuthService.java (2)
5-5: 서비스 계층 분리가 잘 이루어졌습니다.
CommandUserService와QueryUserService로 명령과 조회를 분리한 것은 CQRS 패턴을 잘 적용한 사례입니다.Also applies to: 9-10, 12-17, 29-30
35-42: 인증 메서드 리팩토링이 잘 되었습니다.메서드명이 더 명확해졌고, 사용자 생성 책임이 적절한 서비스로 이동되었습니다.
Also applies to: 45-63
src/main/java/com/dnd/moddo/domain/auth/controller/AuthController.java (2)
3-4: 검증 및 의존성 추가가 적절합니다.
@Validated어노테이션으로 요청 파라미터 검증을 활성화한 것이 좋습니다.Also applies to: 8-9, 29-29, 36-36
40-40: 메서드명 변경과 파라미터 검증이 적절합니다.서비스 계층의 메서드명 변경과 일치하며,
@NotBlank검증 추가로 안정성이 향상되었습니다.Also applies to: 55-55, 57-57
| logout-request-uri: https://kapi.kakao.com/v1/user/logout | ||
|
|
||
| cookie: | ||
| secure: true |
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.
💡 Verification agent
🧩 Analysis chain
쿠키 보안 설정 강화를 확인해주세요.
secure: true 설정이 추가되어 HTTPS에서만 쿠키가 전송되도록 보안이 강화되었습니다. 개발 환경에서 HTTP를 사용하는 경우 이 설정으로 인해 쿠키가 작동하지 않을 수 있으니 프로파일별 설정을 고려해보세요.
다음 스크립트로 개발/운영 환경별 쿠키 설정을 확인해보세요:
🏁 Script executed:
#!/bin/bash
# 개발 및 운영 환경별 설정 파일에서 쿠키 보안 설정 확인
echo "=== 개발 환경 설정 확인 ==="
fd "application-dev.yml" --exec cat {}
echo "=== 운영 환경 설정 확인 ==="
fd "application-prod.yml" --exec cat {}Length of output: 180
프로파일별 쿠키 Secure 설정 분리 필요
현재 application.yml(34행)의
server:
servlet:
session:
cookie:
secure: true가 글로벌로 적용되어 있어, 개발 환경(HTTP)에서 쿠키가 전송되지 않습니다. 개발/운영 환경별로 아래처럼 프로파일별 override를 추가해주세요.
• src/main/resources/application-dev.yml
server:
servlet:
session:
cookie:
secure: false• src/main/resources/application-prod.yml
server:
servlet:
session:
cookie:
secure: true🤖 Prompt for AI Agents
In src/main/resources/application.yml at line 34, the cookie secure setting is
globally set to true, causing issues in development environments using HTTP. To
fix this, remove or avoid setting 'secure: true' globally in application.yml and
instead create environment-specific override files: set 'secure: false' in
src/main/resources/application-dev.yml for development and 'secure: true' in
src/main/resources/application-prod.yml for production.
src/main/java/com/dnd/moddo/domain/user/service/QueryUserService.java
Outdated
Show resolved
Hide resolved
src/test/java/com/dnd/moddo/domain/user/service/implementation/UserReaderTest.java
Outdated
Show resolved
Hide resolved
src/test/java/com/dnd/moddo/domain/auth/controller/AuthControllerTest.java
Outdated
Show resolved
Hide resolved
src/test/java/com/dnd/moddo/domain/auth/controller/AuthControllerTest.java
Outdated
Show resolved
Hide resolved
📝 테스트 커버리지 리포트입니다!
|
#️⃣연관된 이슈
#140
🔀반영 브랜치
feat/#140-kakao-login -> develop
🔧변경 사항
카카오 및 서비스 로그아웃 기능 추가
로그인 플로우 리팩토링
JWT 토큰의 Payload에서 이메일(email) Claim을 삭제하였습니다.
💬리뷰 요구사항(선택)
Summary by CodeRabbit
신규 기능
버그 수정
리팩터링
테스트
문서화