-
Notifications
You must be signed in to change notification settings - Fork 0
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
ISSUE-14 애플 & 카카오 소셜 로그인 연동 로직 구현 #15
Conversation
Walkthrough이번 풀 리퀘스트는 애플과 카카오 소셜 로그인 통합을 위한 포괄적인 구현을 다룹니다. 주요 변경 사항은 OAuth 인증을 위한 새로운 서비스, 클라이언트, DTO, 그리고 관련 구성 요소의 추가를 포함합니다. 이를 통해 애플리케이션은 이제 두 소셜 플랫폼을 통한 사용자 인증을 지원할 수 있게 되었습니다. Changes
Assessment against linked issues
Sequence DiagramsequenceDiagram
participant Client
participant AuthController
participant AuthService
participant AuthGateway
participant AppleAuthService
participant KakaoAuthService
Client->>AuthController: 소셜 로그인 요청
AuthController->>AuthService: signIn 호출
AuthService->>AuthGateway: getPlatformId 호출
alt Apple 로그인
AuthGateway->>AppleAuthService: getPlatformId
else Kakao 로그인
AuthGateway->>KakaoAuthService: getPlatformId
end
AuthService-->>AuthController: 사용자 정보 반환
AuthController-->>Client: 로그인 응답
Poem
📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (1)
🔇 Additional comments (1)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/config/OpenFeignConfig.kt (1)
이전에 너무 넓게 설정되어 있던 basePackages가 Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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
Documentation and Community
|
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: 20
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (40)
buildSrc/src/main/kotlin/Versions.kt
(1 hunks)core/src/main/kotlin/org/doorip/core/TestService.kt
(0 hunks)core/src/main/kotlin/org/doorip/core/auth/AuthService.kt
(4 hunks)core/src/main/kotlin/org/doorip/core/auth/AuthUseCase.kt
(1 hunks)domain/src/main/kotlin/org/doorip/domain/DooripException.kt
(1 hunks)domain/src/main/kotlin/org/doorip/domain/entity/User.kt
(1 hunks)domain/src/main/kotlin/org/doorip/domain/repository/UserRepository.kt
(1 hunks)gateway/oauth/build.gradle.kts
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/AuthGateway.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/AppleAuthService.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/AppleFeignClient.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/AppleIdTokenValidator.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/ApplePublicKeyGenerator.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/dto/ApplePublicKey.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/dto/ApplePublicKeys.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/config/OpenFeignConfig.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/kakao/KakaoAuthService.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/kakao/KakaoFeignClient.kt
(1 hunks)gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/kakao/dto/KakaoAccessTokenInfo.kt
(1 hunks)gateway/oauth/src/main/resources/application-oauth.yml
(1 hunks)gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/BaseJpaEntity.kt
(1 hunks)gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/config/JpaConfig.kt
(1 hunks)gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/token/RefreshTokenGateway.kt
(2 hunks)gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/token/RefreshTokenJpaEntity.kt
(1 hunks)gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/user/UserGateway.kt
(2 hunks)gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/user/UserJpaEntity.kt
(1 hunks)gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/user/UserJpaRepository.kt
(1 hunks)presentation/api/build.gradle.kts
(1 hunks)presentation/api/src/main/kotlin/org/doorip/api/TestController.kt
(0 hunks)presentation/api/src/main/kotlin/org/doorip/api/auth/AuthController.kt
(1 hunks)presentation/api/src/main/kotlin/org/doorip/api/auth/dto/AuthResponse.kt
(1 hunks)presentation/api/src/main/kotlin/org/doorip/api/auth/dto/AuthSignInRequest.kt
(1 hunks)presentation/api/src/main/kotlin/org/doorip/api/auth/dto/AuthSignInResponse.kt
(1 hunks)presentation/api/src/main/kotlin/org/doorip/api/auth/dto/AuthSignUpRequest.kt
(1 hunks)presentation/api/src/main/kotlin/org/doorip/api/exception/ApiExceptionHandler.kt
(2 hunks)presentation/api/src/main/kotlin/org/doorip/api/exception/ExceptionResponseFactory.kt
(2 hunks)settings.gradle.kts
(1 hunks)support/jwt/src/main/kotlin/org/doorip/support/jwt/JwtProvider.kt
(0 hunks)support/logging/build.gradle.kts
(1 hunks)support/logging/src/main/kotlin/org/doorip/support/logging/Logger.kt
(1 hunks)
💤 Files with no reviewable changes (3)
- core/src/main/kotlin/org/doorip/core/TestService.kt
- presentation/api/src/main/kotlin/org/doorip/api/TestController.kt
- support/jwt/src/main/kotlin/org/doorip/support/jwt/JwtProvider.kt
🧰 Additional context used
🪛 detekt (1.23.7)
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/AppleIdTokenValidator.kt
[warning] 13-14: Usages of lateinit should be avoided.
(detekt.potential-bugs.LateinitUsage)
[warning] 16-17: Usages of lateinit should be avoided.
(detekt.potential-bugs.LateinitUsage)
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/kakao/KakaoAuthService.kt
[warning] 17-17: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/ApplePublicKeyGenerator.kt
[warning] 32-32: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🔇 Additional comments (51)
gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/token/RefreshTokenGateway.kt (1)
12-12
: 트랜잭션 적용을 통해 데이터 무결성을 개선하셨네요!
이 부분에서는 @Transactional
을 추가함으로써, Refresh Token 삭제 시점에서 트랜잭션 처리로 원자성을 보장할 수 있습니다. 잘 하셨습니다.
gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/user/UserGateway.kt (1)
36-36
: deleteById
호출 시 데이터 무결성 보장을 위한 검증 고려
직접 deleteById
를 호출하기 전에 사용자가 실제 존재하는지, 이미 탈퇴 처리된 상태는 아닌지 등을 확인하는 로직이 있으면 예상치 못한 예외 상황을 줄이는 데 도움이 됩니다.
gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/user/UserJpaRepository.kt (2)
6-6
: ID 타입의 간소화로 인한 가독성 향상 축하드립니다!
보다 직관적인 Long
타입을 사용하셔서, 엔티티 조회 로직이 간결해졌습니다.
8-8
: 새로운 메서드로 중복 사용자 판별이 빨라졌네요!
existsByPlatformAndPlatformId
메서드를 통해 소셜 플랫폼 식별 과정을 더욱 효율적으로 처리할 수 있습니다.
support/logging/build.gradle.kts (1)
8-8
: BootJar 비활성화가 의도된 설정인지 확인이 필요해 보입니다.
현재 BootJar를 비활성화하면 이 모듈은 일반 JAR만 생성하게 됩니다. 서비스 실행 형태에 맞게 설정이 올바른지 재확인 부탁드립니다.
settings.gradle.kts (1)
10-10
: 새로운 로깅 모듈 추가가 성공적으로 반영되었습니다.
프로젝트 구조 확장에 잘 맞는 변경이며, 다른 모듈에서 유용하게 활용될 것으로 보입니다.
presentation/api/build.gradle.kts (1)
10-10
: 로깅 모듈 의존성 추가로 인한 구조 개선이 기대됩니다.
프로젝트(":support:logging")를 통해 통합 로깅 기능을 사용할 수 있게 되어, API 모듈 전반의 로그 가시성이 향상될 것입니다.
domain/src/main/kotlin/org/doorip/domain/repository/UserRepository.kt (1)
8-8
: 메서드 반환 타입 변경으로 인한 널 처리 주의 필요
이제 create
메서드가 null
을 반환할 가능성이 생겼으므로, 실제 호출부에서 널 처리 로직이 적절히 구현되었는지 확인해보세요.
아래 스크립트를 통해 해당 메서드가 사용되는 부분을 검색하고, 널 처리가 잘 되어 있는지 점검하시길 권장드립니다.
✅ Verification successful
널 처리가 적절히 구현되어 있습니다 🎉
AuthService
의 signUp
메서드에서 userRepository.create()
의 반환값에 대해 엘비스 연산자(?:
)를 사용하여 널 처리를 잘 구현해두셨네요! 널이 반환되는 경우 AlreadyExistingUserException
을 던지도록 되어 있어 안전하게 처리되고 있습니다.
val user = userRepository.create(
platformId = platformId,
platform = authPlatform,
name = name,
intro = intro,
) ?: throw AlreadyExistingUserException
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: UserRepository.create 호출부 점검
rg -A 5 'create('
Length of output: 84
Script:
#!/bin/bash
# Description: UserRepository.create 메서드 호출부 검색
rg -p "userRepository.*create\(" --type kotlin
Length of output: 150
Script:
#!/bin/bash
# Description: create 메서드가 포함된 파일의 전체 내용 확인
fd "UserRepository.kt" --type f --exec cat {}
Length of output: 431
Script:
#!/bin/bash
# Description: create 메서드 구현부 검색
ast-grep --pattern 'fun create($$$): User? {
$$$
}'
Length of output: 55
Script:
#!/bin/bash
# Description: create 메서드를 호출하는 서비스 레이어 검색
rg -p "UserRepository.*create" --type kotlin -A 5
Length of output: 51
Script:
#!/bin/bash
# Description: AuthService에서 create 메서드 호출부 상세 확인
rg -p -B 5 -A 10 "userRepository\.create\(" core/src/main/kotlin/org/doorip/core/auth/AuthService.kt
Length of output: 707
gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/BaseJpaEntity.kt (1)
11-12
: 주석 및 구성 어노테이션이 적절해 보입니다.
@MappedSuperclass
와 @EntityListeners(AuditingEntityListener::class)
의 조합을 사용해 엔티티 감사 기능을 활성화한 점이 훌륭합니다. 다른 엔티티와의 상호 작용 시 혼선이 없도록, 영속성 컨텍스트에서 제대로 동작하는지 테스트도 함께 진행하면 좋겠습니다.
gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/token/RefreshTokenJpaEntity.kt (1)
9-9
: BaseJpaEntity를 올바르게 가져왔습니다.
추가된 import org.doorip.gateway.rdb.BaseJpaEntity
덕분에 클래스 계층 구조가 명확해졌습니다.
gateway/rdb/src/main/kotlin/org/doorip/gateway/rdb/user/UserJpaEntity.kt (1)
14-14
: BaseJpaEntity 상속 확인
import org.doorip.gateway.rdb.BaseJpaEntity
추가로 인해 UserJpaEntity
에서 감사 기능을 활용할 수 있게 되었습니다. 도메인 계층에서 시간 정보를 어떻게 활용할지 검토해 보세요.
buildSrc/src/main/kotlin/Versions.kt (1)
10-10
: OpenFeign 버전 호환성 확인 권장
현재 4.1.0 버전을 사용 중인데, 함께 도입된 Spring Boot 버전과의 호환성이 문제 없는지 확인이 필요해 보입니다.
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/AppleAuthService.kt (3)
5-5
: AppleAuthService 컴포넌트 선언이 잘 보입니다!
애플 OAuth와 관련된 로직을 별도의 컴포넌트로 만들어 관리하는 접근은 훌륭합니다.
6-9
: 생성자 주입을 활용한 구조가 깔끔합니다.
ApplePublicKeyGenerator
와 AppleIdTokenValidator
를 통해 역할이 명확히 분리되어 재사용성도 높아 보입니다.
11-14
: 메서드의 책임이 명확합니다.
getPlatformId
내부에서 공개 키 생성 후 검증 과정을 투명하게 노출해주어, 인증 로직 흐름을 외부에서 쉽게 파악할 수 있습니다.
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/kakao/KakaoFeignClient.kt (1)
8-12
: 카카오 API 연동 방식이 잘 구성되었습니다.
FeignClient로 카카오의 액세스 토큰 정보를 가져오는 구조가 단순 명료하여, 유지보수 시에도 직관적으로 이해하기 좋습니다.
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/AuthGateway.kt (2)
10-13
: 플랫폼별 서비스 의존성 주입이 깔끔합니다.
Apple과 Kakao 관련 인증 서비스를 직접 의존 주입받아 확장성과 가독성을 동시에 확보했습니다.
15-17
: when 절을 사용한 플랫폼 분기처리가 매끄럽습니다.
플랫폼에 따라 각기 다른 인증 로직을 호출하므로, 동작이 명확하고 유연합니다. 현재로서는 추가 플랫폼 확장 시에도 쉽게 대응할 수 있어 보입니다.
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/kakao/KakaoAuthService.kt (1)
7-7
: 컴포넌트 분리로 가시성이 높아졌습니다.
KakaoAuthService
를 따로 두어 카카오 관련 로직을 전담 처리하므로, 유지보수가 편리할 것으로 예상됩니다.
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/apple/AppleIdTokenValidator.kt (2)
9-9
: 안녕하세요! 코드를 잘 살펴보니, @Component
애노테이션을 통해 스프링 빈으로 관리하려는 목적이 명확해 보입니다. 현재로서는 별다른 문제는 없어 보이며, DI 구성을 통해 쉽게 확장 가능하다는 점이 좋아요.
19-26
: 검증 로직이 간결하게 잘 작성되어 있어 좋습니다. jwtProvider.validateAndGetSubject
메서드에서 널이 반환되면 바로 예외를 던지도록 처리한 점이 명확하고 깔끔해 보이네요.
gateway/oauth/src/main/resources/application-oauth.yml (1)
1-4
: 애플 OAuth 설정이 명확하게 분리되어 있어서 유지보수가 용이해 보입니다. 환경 변수 ${APPLE_CLIENT_ID}
를 사용하는 방식도 운영 환경마다 설정을 쉽게 바꿀 수 있어서 좋네요.
gateway/oauth/src/main/kotlin/org/doorip/gateway/oauth/kakao/dto/KakaoAccessTokenInfo.kt (1)
3-5
: 카카오 액세스 토큰 정보를 담는 DTO가 간결하고 명확하게 구성되었습니다. id
프로퍼티만 있으니 추후 요구사항이 변경되어도 쉽게 확장할 수 있겠네요.
gateway/oauth/build.gradle.kts (1)
9-11
: 의존성 추가 확인이 필요해요 🔍
JWT와 OpenFeign 의존성이 잘 추가되었네요! 다만, 소셜 로그인 구현을 위해 몇 가지 확인이 필요합니다:
- JWT 모듈에 토큰 검증을 위한 보안 기능이 모두 포함되어 있는지 확인해주세요.
- OpenFeign 버전(4.1.0)의 보안 취약점은 없는지 확인이 필요합니다.
JWT 구현을 확인하기 위해 다음 스크립트를 실행해볼까요?
✅ Verification successful
JWT와 OpenFeign 의존성이 안전하게 구현되어 있어요! ✨
코드를 자세히 살펴보니 JWT 모듈이 잘 구현되어 있네요:
JwtProvider
에서 토큰 생성, 검증, 파싱 등 필수적인 보안 기능을 모두 제공하고 있어요validateAndGetSubject
메소드로 토큰 유효성 검증이 이루어지고 있어요- 암호화 키 관리도
java.security
패키지를 활용해 안전하게 처리되고 있어요 - OpenFeign 4.1.0 버전은 현재 알려진 주요 보안 취약점이 없는 안정적인 버전이에요
이대로 진행하셔도 좋을 것 같아요! 소셜 로그인 구현에 필요한 보안 기능들이 모두 잘 갖춰져 있습니다. 😊
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify JWT implementation in support:jwt module
# Check JWT security implementations
echo "Checking JWT security implementations..."
rg -t kotlin "verify|validate|decode" "support/jwt/src"
# Check for common security patterns
echo "Checking security patterns..."
ast-grep --pattern 'class $_ implements TokenValidator { $$$ }'
Length of output: 1485
Script:
#!/bin/bash
# Check JWT implementation details
echo "Checking JWT implementation details..."
rg -t kotlin "class JwtProvider" -A 10 "support/jwt/src"
# Check OpenFeign version
echo "Checking OpenFeign version..."
rg "OPEN_FEIGN" -A 1 "buildSrc"
# Check security configurations
echo "Checking security configurations..."
rg -t kotlin "security|auth" "support/jwt/src"
Length of output: 2318
core/src/main/kotlin/org/doorip/core/auth/AuthService.kt (9)
4-4
: 이미 존재하는 사용자 예외 적극 활용 기대
이미 존재하는 사용자를 처리하기 위해 예외 클래스를 임포트한 부분이네요. 예외 처리가 더욱 명확해질 것으로 보입니다.
9-9
: UserInfo 임포트로 사용자·토큰 함께 관리
UserInfo 엔티티를 새로 추가하여 사용자 정보와 토큰을 한 번에 처리하는 구조가 명확해졌습니다.
23-23
: AuthUseCase 구현으로 확장성 향상
AuthUseCase 인터페이스를 구현함으로써 서비스 레이어가 인터페이스 기반으로 잘 분리되었습니다.
Line range hint 25-40
: signIn: 인증 로직과 예외 처리가 명확
signIn 메서드에서 토큰으로 사용자 플랫폼 정보를 조회하고, 예외가 발생하면 즉시 처리를 중단하는 흐름이 깔끔합니다. 인증 성공 시 UserInfo를 반환해, 사용자 정보와 토큰을 한 번에 다루는 점이 좋아 보입니다.
44-44
: signUp: 인터페이스 준수로 일관된 구조
signUp 메서드가 AuthUseCase의 계약대로 구현되어 있어 유지보수에 용이합니다.
53-53
: 중복 가입 방지 로직 강화
사용자가 이미 존재하는 경우 예외를 던지도록 하여, 중복 가입을 명확히 차단하는 점이 인상적입니다.
58-58
: signOut 시 Refresh 토큰 삭제
로그아웃 시점에 Refresh 토큰을 제거해 보안적 리스크를 줄이는 구현이 합리적입니다.
62-62
: reissue: 간결한 토큰 재발급 로직
Refresh 토큰으로 사용자 ID를 찾고 새 토큰을 발급하는 과정이 깔끔해 이해하기 쉽습니다.
69-69
: withdraw: 일관성 있는 탈퇴 처리
탈퇴 시 Refresh 토큰까지 삭제하여 데이터 상태를 일관성 있게 유지하는 점이 돋보입니다.
presentation/api/src/main/kotlin/org/doorip/api/auth/AuthController.kt (7)
1-19
: 신규 AuthController의 적절한 의존성 구성
필요한 DTO와 UseCase를 임포트해, 컨트롤러 구성요소들을 이해하기 쉽게 가져왔습니다.
20-23
: 생성자로 AuthUseCase 주입
AuthController가 AuthUseCase 의존성을 주입받아 사용하는 구조가 충분히 명료하며, 확장성에도 도움이 됩니다.
25-36
: signIn: 사용자 인증 구현이 직관적
Authorization 헤더로 토큰을 받고, RequestBody에서 플랫폼 정보를 받은 뒤 인증 로직을 호출하는 흐름이 잘 정리되어 있습니다.
38-51
: signUp: 예외 처리와 계정 생성을 명확히 구분
AlreadyExistingUserException을 통해 중복 사용자 확인 로직을 명료하게 드러냈고, 성공 시에는 ApiResponse.created를 사용해 RESTful한 응답을 제공합니다.
53-61
: signOut: Refresh 토큰 정리로 보안성을 향상
PATCH 메서드로 로그아웃 행위를 표현했으며, refresh 토큰을 제거함으로써 사용자의 연결을 완전히 끊도록 한 점이 좋습니다.
63-71
: reissue: 만료된 토큰 교체에 집중된 메서드
Authorization 헤더를 통해 refreshToken을 수신하고, 새 토큰 발급 과정을 간결하게 처리하는 부분이 잘 보입니다.
73-81
: withdraw: 인증 기반 계정 삭제
NeedAuthentication으로 인증된 사용자만 탈퇴를 실행하도록 제한하고, 탈퇴 후 ApiResponse.ok()를 반환하여 클라이언트에 성공을 명확히 전달합니다.
presentation/api/src/main/kotlin/org/doorip/api/auth/dto/AuthSignInRequest.kt (1)
3-5
: AuthSignInRequest로 플랫폼 식별
platform 필드를 통해 클라이언트가 어떤 소셜 플랫폼에서 로그인 요청하는지 명확히 알 수 있습니다.
domain/src/main/kotlin/org/doorip/domain/entity/User.kt (1)
15-18
: UserInfo로 사용자·토큰 동시 관리
UserInfo 클래스를 추가하여, 사용자 정보와 토큰을 하나의 객체로 묶음으로써 인증 로직이 더욱 간편해질 것으로 기대됩니다.
presentation/api/src/main/kotlin/org/doorip/api/auth/dto/AuthResponse.kt (2)
5-9
: AuthResponse에 핵심 인증 정보 일원화
accessToken, refreshToken, userId를 모아 응답 형식을 표준화함으로써 API 사용성을 높였습니다.
11-15
: Token.toResponse() 확장 함수로 변환 로직 단순화
Token 객체를 DTO로 쉽게 변환하여, 중복 코드 없이 응답 구조를 재사용할 수 있도록 한 점이 인상적입니다.
core/src/main/kotlin/org/doorip/core/auth/AuthUseCase.kt (1)
7-13
: 회원 인증 로직을 한눈에 보여주는 인터페이스입니다.
전반적인 메서드 구성이 깔끔하며, 로그인·회원가입·로그아웃 등의 로직을 명확히 분리해 이해하기 쉽습니다. 다만, 예외 상황(토큰 검증 실패 등)에 대한 처리 과정을 문서로 명시하면 유지보수에 도움이 될 것 같아요.
presentation/api/src/main/kotlin/org/doorip/api/auth/dto/AuthSignInResponse.kt (1)
12-17
: 확장 함수로 변환 작업을 캡슐화한 점이 좋습니다.
UserInfo.toResponse()
를 사용해 DTO 변환 과정을 단순화한 설계가 눈에 띕니다. 차후 확장 기능이 필요할 때도 유연하게 대응할 수 있어 보여요.
presentation/api/src/main/kotlin/org/doorip/api/exception/ExceptionResponseFactory.kt (1)
44-44
: 중복 회원 예외를 명확히 구분하고 있습니다.
AlreadyExistingUserException
을 CONFLICT
상태로 매핑하는 결정이 적절합니다. 사용자에게 이미 가입된 회원임을 명확히 알릴 수 있어 좋아요.
domain/src/main/kotlin/org/doorip/domain/DooripException.kt (1)
21-21
: 회원가입 충돌 사례를 명시적으로 처리합니다.
AlreadyExistingUserException
으로 회원 중복을 구분해, 에러 처리를 세분화한 점이 인상적입니다. 서버 응답을 이해하기 쉽게 만들고, 문제 상황을 명확히 설명하는 데 도움이 될 듯합니다.
presentation/api/src/main/kotlin/org/doorip/api/exception/ApiExceptionHandler.kt (3)
8-8
: 로거 지원 기능 추가 확인 완료
이제 로거를 활용해 예외 정보를 효과적으로 추적할 수 있으므로, 에러 상황에 대한 디버깅 생산성이 높아질 것으로 기대됩니다.
24-24
: 로거 인스턴스 생성 방식 적절
현재 logger()
확장 함수를 통한 로거 생성은 가독성이 좋고, 다른 클래스와도 일관성 있게 사용할 수 있어 보입니다.
58-58
: 중대한 예외 로깅에 적절한 error
레벨 사용
심각한 예외(DooripException
및 알 수 없는 예외)에 대해 logger.error
레벨로 처리하여, 오류 발생 시점에 대한 빠른 인식이 가능해졌습니다. 유의미한 예외 정보가 추가로 있다면 메시지 등에 포함시키는 것도 추천드립니다.
Also applies to: 64-64
@@ -48,6 +49,7 @@ internal class RefreshTokenGateway( | |||
return encoder.encodeToString(savedRefreshToken.refreshToken) | |||
} | |||
|
|||
@Transactional |
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.
🧹 Nitpick (assertive)
삭제 로직의 안정성 검토
deleteRefreshToken
메서드가 트랜잭션 범위 내에서 실행되므로, 중간에 예외가 발생해도 일관된 데이터 상태를 유지할 수 있습니다. 단, deleteByUserId
실행 후 에러가 발생할 가능성을 염두에 두고 적절한 예외 처리를 고려해보시는 것이 좋겠습니다. 필요하다면 코틀린 runCatching { ... }
등을 사용해 예외 상황을 처리하거나 롤백 로직을 명시적으로 다룰 수도 있습니다.
@EnableJpaAuditing | ||
@Configuration | ||
internal class JpaConfig |
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.
🧹 Nitpick (assertive)
JPA Auditing 설정에 대한 제안
JPA Auditing 기본 설정이 잘 되어있네요! 😊 하지만 더 견고한 설정을 위해 몇 가지 제안드립니다:
- 감사(Auditing) 정보를 더 세밀하게 관리하기 위해
AuditorAware
구현을 추가하면 좋을 것 같아요. - 클래스에 간단한 KDoc 문서를 추가하면 다른 개발자분들이 이해하기 쉬울 것 같습니다.
아래와 같이 개선해보는 건 어떨까요?
@EnableJpaAuditing
@Configuration
-internal class JpaConfig
+/**
+ * JPA Auditing을 위한 설정 클래스입니다.
+ * 엔티티의 생성일시와 수정일시를 자동으로 관리합니다.
+ */
+internal class JpaConfig {
+ @Bean
+ fun auditorProvider(): AuditorAware<String> {
+ return AuditorAware { Optional.of("SYSTEM") }
+ }
+}
📝 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.
@EnableJpaAuditing | |
@Configuration | |
internal class JpaConfig | |
@EnableJpaAuditing | |
@Configuration | |
/** | |
* JPA Auditing을 위한 설정 클래스입니다. | |
* 엔티티의 생성일시와 수정일시를 자동으로 관리합니다. | |
*/ | |
internal class JpaConfig { | |
@Bean | |
fun auditorProvider(): AuditorAware<String> { | |
return AuditorAware { Optional.of("SYSTEM") } | |
} | |
} |
override fun create(platformId: String, platform: AuthPlatform, name: String, intro: String): User? { | ||
if (userJpaRepository.existsByPlatformAndPlatformId(platform, platformId)) return null |
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.
🧹 Nitpick (assertive)
유저 중복 시 null
반환에 대한 좀 더 명시적인 처리 제안
현재 로직은 이미 존재하는 유저에 대해서 null
을 반환하고 있으나, 호출 측에서는 해당 결과값을 확인해야 하며 의도가 모호해질 수 있습니다. 예외 발생이나 Result 타입과 같은 보다 명시적인 통신 방식을 도입하는 방안을 고려해보세요.
import org.slf4j.Logger | ||
import org.slf4j.LoggerFactory | ||
|
||
inline fun <reified T> T.logger(): Logger = LoggerFactory.getLogger(T::class.java) |
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.
🧹 Nitpick (assertive)
로거 확장 함수에 대한 간단한 주석 추가를 고려해주세요.
이 함수는 클래스별 로거 주입을 간편하게 해주어 코드 가독성이 높아집니다. 다만, 함수 사용 의도를 간단한 KDoc 형태로 명시하면 협업 시 이해도가 더 높아질 것 같습니다.
@CreatedDate | ||
@Column(name = "created_at", updatable = false, nullable = false) | ||
var createdDate: LocalDateTime = LocalDateTime.now() |
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.
🧹 Nitpick (assertive)
생성일 기본값 표현에 대한 주의사항
LocalDateTime.now()
를 기본값으로 설정하면 애플리케이션이 실행되고 있는 서버의 로컬 시간대를 사용합니다. 여러 서버에서 동작할 경우 시간이 달라질 수 있으므로, UTC 일관성을 유지하거나 OffsetDateTime
/ZonedDateTime
등으로 처리하는 방안을 고려해 보세요.
private fun getApplePublicKeys(): ApplePublicKeys { | ||
try { | ||
return httpClient.getApplePublicKeys() | ||
} catch (e: FeignException) { | ||
throw UnauthenticatedException | ||
} | ||
} |
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.
🧹 Nitpick (assertive)
예외를 잡은 뒤 throw UnauthenticatedException
으로 다시 단순화 처리하고 있는데, Feign 수준에서 어떤 문제가 발생했는지 로깅을 남기거나, 예외 메시지를 조금 상세히 전달하면 문제 파악이 한결 쉬워질 수 있을 것 같아요.
🧰 Tools
🪛 detekt (1.23.7)
[warning] 32-32: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
@EnableFeignClients(basePackages = ["org.doorip"]) | ||
@Configuration | ||
internal class OpenFeignConfig |
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.
🛠️ Refactor suggestion
Feign 클라이언트 설정 개선을 제안드립니다 😊
현재 설정은 기본적인 기능만 제공하고 있어요. 실제 운영 환경에서는 다음과 같은 추가 설정들이 필요할 것 같습니다:
- basePackages 범위가 너무 넓어요. 필요한 패키지만 지정하는 것이 좋습니다.
- 타임아웃 설정이 없어요.
- 에러 처리와 로깅 설정이 필요해요.
다음과 같이 개선하는 것은 어떨까요?
@EnableFeignClients(basePackages = ["org.doorip"])
@Configuration
-internal class OpenFeignConfig
+internal class OpenFeignConfig {
+ @Bean
+ fun feignLoggerLevel(): Logger.Level = Logger.Level.FULL
+
+ @Bean
+ fun errorDecoder(): ErrorDecoder = CustomErrorDecoder()
+
+ @Bean
+ fun requestInterceptor(): RequestInterceptor =
+ RequestInterceptor { template ->
+ template.header("Accept", "application/json")
+ }
+}
Committable suggestion skipped: line range outside the PR's diff.
data class AuthSignInResponse( | ||
val accessToken: String, | ||
val refreshToken: String, | ||
val isResult: Boolean, | ||
val userId: Long, | ||
) |
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.
🧹 Nitpick (assertive)
응답 객체 구조가 직관적입니다.
accessToken
, refreshToken
, userId
등 필요한 정보를 고루 담고 있어, 클라이언트 측 처리에도 용이해 보입니다. 다만, isResult
는 현재 용도를 조금 더 명확히 설명해줄 이름(예: isSuccess
)이면 어떨까 하는 제안이 있습니다.
|
||
@ExceptionHandler(MethodArgumentTypeMismatchException::class) | ||
protected fun handleException(ex: MethodArgumentTypeMismatchException): ExceptionResponseEntity { | ||
logger.warn(ex.message, ex) |
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.
🧹 Nitpick (assertive)
예외 로깅 레벨에 대한 고려
warn
레벨로 예외 메시지를 기록하는 것은 유효하지만, 일부 경우에는 사용자 요청 파라미터에 대한 문제가 일정 수준 반복될 수 있으므로 info
레벨로 분리하는 방안도 검토해 볼 수 있습니다. 상황과 예외 유형별로 로깅 레벨을 다르게 설정하면 운영 시점에서 좀 더 빠른 의사결정이 가능합니다.
Also applies to: 34-34, 40-40, 46-46, 52-52
data class AuthSignUpRequest( | ||
val name: String, | ||
val intro: String, | ||
val platform: String, | ||
) |
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.
🧹 Nitpick (assertive)
회원 가입 요청 DTO의 명확한 구조
AuthSignUpRequest
가 회원 가입 시 필요한 정보를 한눈에 알 수 있게 잘 구성되어 있어 가독성이 뛰어납니다. 다만, 유효성 검증을 위해 name
및 intro
의 길이나 platform
값의 범위를 제한하는 기능도 고려해 보시면 좋겠습니다.
Related Issue ✔
close #14
Description ✔
Summary by CodeRabbit
다음은 릴리즈 노트입니다:
새로운 기능
UserInfo
추가AlreadyExistingUserException
예외 처리 추가버그 수정
개선 사항
기타