Skip to content

Conversation

@move-hoon
Copy link
Member

@move-hoon move-hoon commented Aug 6, 2025

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)
  • 🎨 style (코드 스타일 수정)

📙 작업 내역

1. 카카오 회원탈퇴 기능 구현

1.1 카카오 API 연동 구현

  • KakaoRestClient: 카카오 연결 끊기 API (POST /v1/user/unlink) 호출 구현
  • KakaoApi: API 호출 래퍼 및 에러 처리
  • KakaoApiManager: 비즈니스 로직 처리 및 응답 검증
  • KakaoUnlinkResponse: 카카오 응답 DTO 구현

1.2 카카오 회원탈퇴 전략 구현

  • KakaoWithdrawStrategy: 카카오 회원탈퇴 전략 패턴 구현
  • KakaoOauthProperties: 카카오 어드민 키 설정 관리
  • 이중 검증: @validated + @Valid 어노테이션으로 안전성 강화

1.3 에러 처리 개선

  • AuthErrorCode: 카카오 회원탈퇴 전용 에러 코드 추가
  • KAKAO_UNLINK_FAILED (400): 카카오 회원탈퇴 처리 실패
  • KAKAO_UNLINK_RESPONSE_MISMATCH (500): 응답 ID 불일치
  • 세분화된 에러 처리: HTTP 상태 코드별 적절한 에러 메시지 제공

2. 회원탈퇴 API 개선

2.1 WithdrawRequest 제거

  • 기존: 클라이언트에서 providerType을 전송해야 함
  • 개선: 서버에서 userId로 사용자 정보 조회하여 providerType 자동 판단
  • 장점: 클라이언트가 어떤 소셜로 가입했는지 알 필요 없음

2.2 API 인터페이스 개선

  • AuthController: @RequestBody 파라미터 제거
  • AuthControllerApi: 인터페이스에서 WithdrawRequest 제거
  • AuthUseCase: 서버에서 providerType 자동 판단 로직 구현

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

기능 미리보기 기능 미리보기
기능 설명 기능 설명

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다
  • PR 제목이 컨벤션에 맞습니다
  • 관련 이슈 번호를 작성했습니다
  • 기능이 정상적으로 작동합니다
  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트 (선택)

Summary by CodeRabbit

  • 신규 기능

    • 카카오 회원탈퇴(연결 해제) 기능이 추가되었습니다.
    • 카카오 OAuth 관련 설정을 위한 프로퍼티 클래스가 도입되었습니다.
  • 버그 수정

    • 회원탈퇴 API에서 별도의 요청 본문 없이 인증된 사용자만으로 탈퇴가 가능하도록 변경되었습니다.
  • 개선 사항

    • 회원탈퇴 전략 요청에 대한 유효성 검사가 강화되었습니다.
    • 카카오 회원탈퇴 과정에서 상세한 오류 코드와 메시지가 추가되었습니다.
    • Apple 및 Kakao 회원탈퇴 전략에 Spring Validation이 적용되었습니다.
  • 기타

    • 내부적으로 카카오 API 연동 및 예외 처리 로직이 개선되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Aug 6, 2025

Warning

Rate limit exceeded

@hoonyworld has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 56 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 7d1df73 and c30c41e.

📒 Files selected for processing (2)
  • apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt (2 hunks)
  • infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/KakaoRestClient.kt (1 hunks)

Walkthrough

카카오 회원 탈퇴 기능이 추가되었습니다. 기존의 WithdrawRequest DTO 및 관련 요청 파라미터가 제거되고, 카카오 Admin Key를 사용하여 카카오 API의 /v1/user/unlink 엔드포인트로 회원 탈퇴 요청을 보내는 로직이 구현되었습니다. 카카오 회원 탈퇴 전략, 에러 코드, 설정 프로퍼티, 응답 DTO 등이 새로 도입되었습니다.

Changes

Cohort / File(s) Change Summary
AuthController 및 API 인터페이스
apis/src/main/kotlin/org/yapp/apis/auth/controller/AuthController.kt, apis/src/main/kotlin/org/yapp/apis/auth/controller/AuthControllerApi.kt
withdraw 엔드포인트에서 WithdrawRequest 파라미터 및 관련 검증 제거, withdraw 메서드 시그니처 단순화
WithdrawRequest DTO 제거
apis/src/main/kotlin/org/yapp/apis/auth/dto/request/WithdrawRequest.kt
WithdrawRequest DTO 파일 및 관련 메서드 삭제
WithdrawStrategyRequest 검증 강화
apis/src/main/kotlin/org/yapp/apis/auth/dto/request/WithdrawStrategyRequest.kt
userId, providerType, providerId 필드에 NotNull/NotBlank 검증 어노테이션 추가
AuthErrorCode 확장
apis/src/main/kotlin/org/yapp/apis/auth/exception/AuthErrorCode.kt
카카오 회원탈퇴 실패 및 응답 불일치 관련 에러코드 2종 추가
KakaoApiManager 기능 확장
apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt
unlink 메서드 추가, getUserInfo 예외 처리 단순화, KakaoUnlinkResponse 도입
Apple/KakaoWithdrawStrategy 검증 및 기능 강화
apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/AppleWithdrawStrategy.kt, apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/KakaoWithdrawStrategy.kt
클래스에 @validated 추가, withdraw 파라미터에 @Valid 적용, KakaoWithdrawStrategy에 카카오 회원탈퇴 로직 및 로그 추가
AuthUseCase 로직 변경
apis/src/main/kotlin/org/yapp/apis/auth/usecase/AuthUseCase.kt
withdraw 메서드에서 WithdrawRequest 제거, providerType 검증 로직 삭제, 전략 패턴 적용 방식 변경
OAuth 설정 프로퍼티 확장
apis/src/main/kotlin/org/yapp/apis/config/AuthConfig.kt, apis/src/main/kotlin/org/yapp/apis/config/KakaoOauthProperties.kt
AuthConfig에 KakaoOauthProperties 등록, KakaoOauthProperties 클래스 신설(adminKey 포함)
Kakao API/RestClient/응답 DTO 신설 및 확장
infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/KakaoApi.kt, infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/KakaoRestClient.kt, infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/response/KakaoUnlinkResponse.kt
KakaoApi에 unlink 메서드 추가, KakaoRestClient에 unlink API 호출 메서드 및 상수 정의, KakaoUnlinkResponse DTO 신설

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthController
    participant AuthUseCase
    participant UserAccountService
    participant KakaoWithdrawStrategy
    participant KakaoApiManager
    participant KakaoApi
    participant KakaoRestClient

    Client->>AuthController: DELETE /auth/withdraw (with JWT)
    AuthController->>AuthUseCase: withdraw(userId)
    AuthUseCase->>UserAccountService: findWithdrawUserById(userId)
    UserAccountService-->>AuthUseCase: User (with providerType, providerId)
    AuthUseCase->>KakaoWithdrawStrategy: withdraw(WithdrawStrategyRequest)
    KakaoWithdrawStrategy->>KakaoApiManager: unlink(adminKey, providerId)
    KakaoApiManager->>KakaoApi: unlink(adminKey, providerId)
    KakaoApi->>KakaoRestClient: unlink(adminKey, providerId)
    KakaoRestClient-->>KakaoApi: KakaoUnlinkResponse
    KakaoApi-->>KakaoApiManager: KakaoUnlinkResponse
    KakaoApiManager-->>KakaoWithdrawStrategy: KakaoUnlinkResponse
    KakaoWithdrawStrategy-->>AuthUseCase: (완료)
    AuthUseCase-->>AuthController: (완료)
    AuthController-->>Client: 204 No Content
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
카카오 회원 탈퇴 기능 구현 (#56)
카카오 Admin Key를 사용해 카카오 API(/v1/user/unlink)로 회원 탈퇴 요청 (#56)
요청 성공 시 서비스 측에서 해당 사용자의 커스텀 Refresh Token을 삭제 (#56) Refresh Token 삭제 로직이 본 변경 내역에 명확히 포함되어 있는지 불분명함.
카카오 회원 탈퇴 관련 에러 처리 및 에러코드 제공 (#56)

Assessment against linked issues: Out-of-scope changes

해당 변경 내역에는 명확히 범위를 벗어난 기능적 코드 변경이 발견되지 않았습니다.

Possibly related PRs

Suggested labels

✨ feat

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BOOK-180-feature/#56

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6a15018 and e62fd9b.

📒 Files selected for processing (14)
  • apis/src/main/kotlin/org/yapp/apis/auth/controller/AuthController.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/controller/AuthControllerApi.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/dto/request/WithdrawRequest.kt (0 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/dto/request/WithdrawStrategyRequest.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/exception/AuthErrorCode.kt (2 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt (2 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/AppleWithdrawStrategy.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/KakaoWithdrawStrategy.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/usecase/AuthUseCase.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/config/AuthConfig.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/config/KakaoOauthProperties.kt (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/KakaoApi.kt (2 hunks)
  • infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/KakaoRestClient.kt (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/response/KakaoUnlinkResponse.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • apis/src/main/kotlin/org/yapp/apis/auth/dto/request/WithdrawRequest.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 로그인 작업에서는 외부 api 호출(소셜 인증, apple 토큰 발급)과 db 작업을 분리하여, authusecase는 트랜잭션 없이 외부 호출을 먼저 처리하는 오케스트레이터 역할...
Learnt from: hoonyworld
PR: YAPP-Github/Reed-Server#76
File: apis/src/main/kotlin/org/yapp/apis/auth/usecase/AuthUseCase.kt:33-46
Timestamp: 2025-08-06T08:18:36.255Z
Learning: 로그인 작업에서는 외부 API 호출(소셜 인증, Apple 토큰 발급)과 DB 작업을 분리하여, AuthUseCase는 트랜잭션 없이 외부 호출을 먼저 처리하는 오케스트레이터 역할을 하고, UserSignInService는 Transactional로 DB 작업만 처리하는 실행자 역할을 한다. 이는 DB 커넥션 점유 시간 최소화와 시스템 안정성 향상을 위한 패턴이다.

Applied to files:

  • apis/src/main/kotlin/org/yapp/apis/auth/controller/AuthController.kt
  • apis/src/main/kotlin/org/yapp/apis/auth/usecase/AuthUseCase.kt
⏰ 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-validation
🔇 Additional comments (20)
infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/KakaoApi.kt (1)

22-26: LGTM! 기존 패턴과 일관성 있게 구현되었습니다.

unlink 메서드가 기존의 fetchUserInfo 메서드와 동일한 패턴을 따라 구현되어 있어 일관성이 좋습니다. runCatching을 사용한 예외 처리와 Result 타입 반환이 적절합니다.

infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/response/KakaoUnlinkResponse.kt (1)

5-8: 검증 결과: private 생성자 사용 유지해도 무방합니다

프로젝트 전반에서 DTO에 private constructor 패턴을 일관되게 적용하고 있으며, Jackson의 기본 설정(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS 활성화)으로도 private 생성자를 통한 역직렬화가 정상 작동합니다.
따라서 KakaoUnlinkResponse는 현 상태 그대로 두고 승인합니다.

  • infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/response/KakaoUnlinkResponse.kt
apis/src/main/kotlin/org/yapp/apis/config/AuthConfig.kt (1)

7-7: LGTM! 설정 프로퍼티 바인딩이 올바르게 추가되었습니다.

KakaoOauthProperties가 기존 AppleOauthProperties와 함께 올바르게 활성화되었습니다. Spring Boot의 설정 프로퍼티 패턴을 정확히 따르고 있습니다.

apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/AppleWithdrawStrategy.kt (3)

3-3: LGTM! 검증 어노테이션 import가 적절합니다.

Jakarta Validation과 Spring Validation 어노테이션을 위한 import가 올바르게 추가되었습니다.

Also applies to: 5-5


13-13: LGTM! 클래스 레벨 검증이 활성화되었습니다.

@Validated 어노테이션이 클래스 레벨에서 올바르게 적용되어 Spring의 검증 프레임워크를 활성화합니다.


19-19: LGTM! 메서드 파라미터 검증이 추가되었습니다.

@Valid 어노테이션이 request 파라미터에 올바르게 적용되어 WithdrawStrategyRequest 객체의 검증을 활성화합니다. 이는 다른 철회 전략과의 일관성도 보장합니다.

apis/src/main/kotlin/org/yapp/apis/auth/controller/AuthControllerApi.kt (1)

110-112: API 단순화로 사용성이 개선되었습니다

WithdrawRequest 파라미터를 제거하여 클라이언트가 provider type을 명시할 필요가 없어졌습니다. 서버가 userId로부터 provider type을 자동으로 결정하는 방식으로 변경되어 API 사용이 더 간단해지고 클라이언트 측 실수 가능성이 줄어들었습니다.

apis/src/main/kotlin/org/yapp/apis/auth/controller/AuthController.kt (1)

38-42: 인터페이스 변경사항과 일관된 구현

AuthControllerApi의 변경사항과 완전히 일치하게 구현되었습니다. UseCase 호출도 단순화된 시그니처에 맞춰 적절히 수정되었습니다.

apis/src/main/kotlin/org/yapp/apis/auth/exception/AuthErrorCode.kt (3)

54-54: 카카오 응답 불일치 에러 코드 적절합니다

서버 내부 처리 중 발생하는 응답 불일치 문제로 500 상태 코드가 적절하며, 에러 메시지도 명확합니다.


25-25: 에러 코드 일관성 확인 완료

AUTH_400_13AUTH_400_14가 코드베이스 어디에도 사용되지 않으므로, KAKAO_UNLINK_FAILED(HttpStatus.BAD_REQUEST, "AUTH_400_15", …) 형태의 코드 번호 순서를 유지해도 문제가 없습니다.


25-25: HTTP 상태 코드 설정이 적절합니다

  • KakaoApiManager에서 HttpClientErrorException(4xx) 발생 시에만 KAKAO_UNLINK_FAILED(HttpStatus.BAD_REQUEST)를 사용하고,
    그 외 서버 오류는 OAUTH_SERVER_ERROR(500)로 처리되고 있습니다.
  • 따라서 KAKAO_UNLINK_FAILED의 HTTP 상태 코드를 변경할 필요가 없습니다.
apis/src/main/kotlin/org/yapp/apis/auth/usecase/AuthUseCase.kt (1)

64-70: 보안과 데이터 일관성이 향상된 리팩토링

외부 요청에서 받은 provider type을 검증하는 대신, 사용자 데이터에서 직접 provider type을 추출하는 방식으로 변경되어 데이터 일관성과 보안이 향상되었습니다. 클라이언트가 잘못된 provider type을 전달할 가능성을 원천적으로 차단합니다.

apis/src/main/kotlin/org/yapp/apis/auth/dto/request/WithdrawStrategyRequest.kt (2)

4-5: 적절한 validation 어노테이션 추가

필수 필드들에 대한 validation 어노테이션이 적절히 추가되었습니다.


12-31: 필드별 validation이 적절합니다

각 필드 특성에 맞는 validation이 적용되었습니다:

  • UUID 타입 필드에는 @NotNull
  • String 타입 필드에는 @notblank (null과 공백 모두 체크)
  • 에러 메시지도 명확하게 한국어로 작성되었습니다
apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/KakaoWithdrawStrategy.kt (3)

3-4: 검증 어노테이션 적용이 적절합니다.

클래스 레벨에 @Validated와 메서드 파라미터에 @Valid 어노테이션을 추가하여 Spring의 메서드 레벨 검증을 활성화한 것은 좋은 접근입니다. 이를 통해 WithdrawStrategyRequest의 필드 검증을 강제할 수 있습니다.

Also applies to: 6-6, 13-13, 22-22


15-16: 의존성 주입 구조가 깔끔합니다.

KakaoApiManagerKakaoOauthProperties를 주입받는 구조가 명확하고, 카카오 관리자 키 설정을 분리한 것이 좋습니다.


18-18: 로깅 구현이 적절합니다.

KotlinLogging을 사용한 private 로거 인스턴스 생성이 올바릅니다.

infra/src/main/kotlin/org/yapp/infra/external/oauth/kakao/KakaoRestClient.kt (2)

12-24: 상수 중앙화가 잘 구현되었습니다.

companion object를 통해 URL, 헤더, 파라미터 상수들을 중앙화한 것은 좋은 접근입니다. 코드의 가독성과 유지보수성이 향상됩니다.


27-27: 기존 메서드의 상수 활용이 적절합니다.

BASE_URL과 HEADER_AUTHORIZATION 상수를 사용하도록 업데이트한 것이 일관성을 높입니다.

Also applies to: 33-33

apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt (1)

27-37: 예외 처리 로직이 간소화되고 명확해졌습니다.

기존의 복잡한 예외 처리를 두 가지 케이스로 간소화한 것이 좋습니다. HttpClientErrorException은 토큰 오류로, 그 외는 서버 오류로 처리하는 것이 적절합니다.

Comment on lines 40 to 67
fun unlink(adminKey: String, targetId: String): KakaoUnlinkResponse {
return kakaoApi.unlink(adminKey, targetId)
.onSuccess { response ->
log.info("Successfully unlinked Kakao user with targetId: $targetId, responseId: ${response.id}")

if (response.id != targetId) {
throw AuthException(
AuthErrorCode.KAKAO_UNLINK_RESPONSE_MISMATCH,
"Kakao unlink response ID does not match target ID. Expected: $targetId, Actual: ${response.id}"
)
}
}
.getOrElse { exception ->
log.error("Failed to unlink Kakao user with targetId: $targetId", exception)

when (exception) {
is HttpClientErrorException -> throw AuthException(
AuthErrorCode.KAKAO_UNLINK_FAILED,
"Failed to unlink Kakao user due to client error: ${exception.message}"
)

else -> throw AuthException(
AuthErrorCode.OAUTH_SERVER_ERROR,
"Failed to unlink Kakao user due to server error: ${exception.message}"
)
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

🛠️ Refactor suggestion

unlink 메서드 구현이 견고하지만 개선점이 있습니다.

응답 ID와 요청 ID 일치 검증, 적절한 로깅, 구체적인 오류 코드 처리가 잘 구현되어 있습니다.

보안상 민감한 정보 로깅을 개선하세요:

-                log.info("Successfully unlinked Kakao user with targetId: $targetId, responseId: ${response.id}")
+                log.info("Successfully unlinked Kakao user")

-                log.error("Failed to unlink Kakao user with targetId: $targetId", exception)
+                log.error("Failed to unlink Kakao user", exception)

targetId와 responseId는 개인정보에 해당할 수 있으므로 로그에서 제외하는 것이 GDPR 등 개인정보 보호 규정 준수에 도움이 됩니다.

응답 검증 로직을 더 명확하게 분리할 수 있습니다:

+            .onSuccess { response ->
+                log.info("Successfully unlinked Kakao user")
+                validateUnlinkResponse(response, targetId)
+                response
+            }

+    private fun validateUnlinkResponse(response: KakaoUnlinkResponse, expectedTargetId: String) {
+        if (response.id != expectedTargetId) {
+            throw AuthException(
+                AuthErrorCode.KAKAO_UNLINK_RESPONSE_MISMATCH,
+                "Kakao unlink response ID does not match target ID"
+            )
+        }
+    }

이렇게 하면 메서드의 책임이 더 명확해지고 테스트하기 쉬워집니다.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt between
lines 40 and 67, remove targetId and responseId from log messages to avoid
logging sensitive personal information, ensuring compliance with privacy
regulations like GDPR. Additionally, refactor the response ID verification into
a separate private method to clarify the unlink method's responsibility and
improve testability.

Comment on lines 22 to 31
override fun withdraw(@Valid request: WithdrawStrategyRequest) {
log.info("Starting Kakao withdrawal for user: ${request.userId}, providerId: ${request.providerId}")

val unlinkResponse = kakaoApiManager.unlink(
adminKey = kakaoOauthProperties.adminKey,
targetId = request.providerId
)

log.info("Successfully unlinked Kakao user. Response ID: ${unlinkResponse.id}")
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

회원 탈퇴 로직 구현이 완료되었지만 보안 고려사항이 있습니다.

실제 카카오 unlink API 호출을 구현하고 적절한 로깅을 추가한 것은 좋습니다. 하지만 보안상 민감한 정보 로깅에 주의가 필요합니다.

민감한 정보 로깅을 개선하세요:

-        log.info("Starting Kakao withdrawal for user: ${request.userId}, providerId: ${request.providerId}")
+        log.info("Starting Kakao withdrawal for user: ${request.userId}")

-        log.info("Successfully unlinked Kakao user. Response ID: ${unlinkResponse.id}")
+        log.info("Successfully unlinked Kakao user for userId: ${request.userId}")

providerId와 response ID는 민감한 개인정보일 수 있으므로 로그에서 제외하는 것이 안전합니다.

📝 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.

Suggested change
override fun withdraw(@Valid request: WithdrawStrategyRequest) {
log.info("Starting Kakao withdrawal for user: ${request.userId}, providerId: ${request.providerId}")
val unlinkResponse = kakaoApiManager.unlink(
adminKey = kakaoOauthProperties.adminKey,
targetId = request.providerId
)
log.info("Successfully unlinked Kakao user. Response ID: ${unlinkResponse.id}")
}
override fun withdraw(@Valid request: WithdrawStrategyRequest) {
log.info("Starting Kakao withdrawal for user: ${request.userId}")
val unlinkResponse = kakaoApiManager.unlink(
adminKey = kakaoOauthProperties.adminKey,
targetId = request.providerId
)
log.info("Successfully unlinked Kakao user for userId: ${request.userId}")
}
🤖 Prompt for AI Agents
In
apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/KakaoWithdrawStrategy.kt
between lines 22 and 31, the current logging includes sensitive information such
as providerId and unlinkResponse.id. To fix this, remove these sensitive details
from the log messages and instead log only non-sensitive information like the
action status or anonymized identifiers to ensure security and privacy
compliance.

Comment on lines +5 to +8
@ConfigurationProperties(prefix = "oauth.kakao")
data class KakaoOauthProperties(
val adminKey: String
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

관리자 키에 대한 검증 추가를 고려해보세요.

설정 프로퍼티가 올바르게 구현되었지만, adminKey는 중요한 정보이므로 빈 값이나 null 값에 대한 검증을 추가하는 것이 좋겠습니다.

다음과 같이 검증 어노테이션을 추가할 수 있습니다:

+import jakarta.validation.constraints.NotBlank
+
 @ConfigurationProperties(prefix = "oauth.kakao")
 data class KakaoOauthProperties(
+    @field:NotBlank(message = "Kakao admin key must not be blank")
     val adminKey: String
 )
📝 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.

Suggested change
@ConfigurationProperties(prefix = "oauth.kakao")
data class KakaoOauthProperties(
val adminKey: String
)
import jakarta.validation.constraints.NotBlank
@ConfigurationProperties(prefix = "oauth.kakao")
data class KakaoOauthProperties(
@field:NotBlank(message = "Kakao admin key must not be blank")
val adminKey: String
)
🤖 Prompt for AI Agents
In apis/src/main/kotlin/org/yapp/apis/config/KakaoOauthProperties.kt around
lines 5 to 8, the adminKey property lacks validation to prevent null or empty
values. Add validation annotations such as @field:NotBlank to the adminKey
property and ensure the class is annotated with @Validated to enforce these
constraints at runtime, thereby preventing invalid configuration values.

Copy link

@coderabbitai coderabbitai bot left a 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 (2)
apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/KakaoWithdrawStrategy.kt (1)

21-21: 민감한 정보 로깅을 개선해주세요.

이전 리뷰에서 지적된 보안 이슈가 여전히 존재합니다. providerId와 response ID는 개인정보에 해당할 수 있으므로 로그에서 제외해야 합니다.

다음과 같이 수정하여 민감한 정보를 제거하세요:

-        log.info("Starting Kakao withdrawal for user: ${request.userId}, providerId: ${request.providerId}")
+        log.info("Starting Kakao withdrawal for user: ${request.userId}")

-        log.info("Successfully unlinked Kakao user. Response ID: ${unlinkResponse.id}")
+        log.info("Successfully unlinked Kakao user for userId: ${request.userId}")

Also applies to: 25-25

apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt (1)

45-45: 민감한 정보 로깅 보안 이슈가 여전히 존재합니다.

이전 리뷰에서 지적된 보안 문제가 해결되지 않았습니다. targetId와 responseId는 개인정보에 해당할 수 있으므로 로그와 예외 메시지에서 제거해야 합니다.

다음과 같이 수정하여 GDPR 등 개인정보 보호 규정을 준수하세요:

-                log.info("Successfully unlinked Kakao user with targetId: $targetId, responseId: ${response.id}")
+                log.info("Successfully unlinked Kakao user")

-                        "Kakao unlink response ID does not match target ID. Expected: $targetId, Actual: ${response.id}"
+                        "Kakao unlink response ID does not match target ID"

-                log.error("Failed to unlink Kakao user with targetId: $targetId", exception)
+                log.error("Failed to unlink Kakao user", exception)

Also applies to: 50-50, 55-55

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e62fd9b and 7d1df73.

📒 Files selected for processing (3)
  • apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt (2 hunks)
  • apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/KakaoWithdrawStrategy.kt (1 hunks)
  • apis/src/main/resources/application.yml (1 hunks)
⏰ 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-validation
🔇 Additional comments (3)
apis/src/main/resources/application.yml (1)

82-83: 카카오 OAuth 설정이 적절히 추가되었습니다.

기존 Apple OAuth 설정과 일관된 패턴을 따르며, 개발 환경에 적합한 더미 키를 사용하고 있습니다. 설정 구조가 명확하고 KakaoOauthProperties와 잘 연동될 것으로 보입니다.

apis/src/main/kotlin/org/yapp/apis/auth/strategy/withdraw/KakaoWithdrawStrategy.kt (1)

3-3: 검증 어노테이션 추가가 적절합니다.

@validated@Valid 어노테이션을 통한 메서드 레벨 검증이 잘 구현되었습니다. 이는 비즈니스 로직 실행 전 조기 검증을 가능하게 하여 안정성을 향상시킵니다.

Also applies to: 6-6, 12-12, 20-20

apis/src/main/kotlin/org/yapp/apis/auth/manager/KakaoApiManager.kt (1)

15-16: KakaoOauthProperties 통합이 깔끔하게 구현되었습니다.

설정 프로퍼티 의존성 주입과 사용이 적절하며, Spring Boot의 설정 바인딩 패턴을 잘 따르고 있습니다.

Also applies to: 43-43

@sonarqubecloud
Copy link

sonarqubecloud bot commented Aug 6, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
5.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@move-hoon move-hoon merged commit 80300e9 into develop Aug 6, 2025
2 of 3 checks passed
@move-hoon move-hoon deleted the BOOK-180-feature/#56 branch August 12, 2025 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOOK-180/feat] 카카오 회원 탈퇴 기능 구현

2 participants