Skip to content

[fix] 탈퇴 후 카카오 재로그인 시 계정 복구/완전삭제 후 재가입 옵션 제공#184

Merged
geunyong16 merged 4 commits into
mainfrom
fix/183-restore-or-purge-on-kakao-relogin
May 11, 2026
Merged

[fix] 탈퇴 후 카카오 재로그인 시 계정 복구/완전삭제 후 재가입 옵션 제공#184
geunyong16 merged 4 commits into
mainfrom
fix/183-restore-or-purge-on-kakao-relogin

Conversation

@geunyong16
Copy link
Copy Markdown
Collaborator

@geunyong16 geunyong16 commented May 8, 2026

🔖 관련 GitHub Issue

📝 변경 사항

주요 변경 내용

  • 카카오 로그인 시 탈퇴 계정 발견하면 예외 대신 status=WITHDRAWN_PENDING 응답으로 사용자 선택 안내
  • 신규 엔드포인트 POST /api/auth/kakao/restore 추가 (탈퇴 취소)
  • 신규 엔드포인트 POST /api/auth/kakao/purge-and-register 추가 (완전 삭제 후 재가입)
  • 탈퇴 시 UserSettings 보존 → 복구 시 이전 알림 설정 그대로 유지

상세 설명

배경

기존에는 탈퇴(soft delete) 후 30일 hard-delete 스케줄러가 돌기 전에 동일 카카오 계정으로 재로그인 시 BadRequestException("탈퇴한 계정입니다. 다시 가입해주세요.")로 모든 진입이 차단되었습니다. 사용자에게는 30일을 기다리는 것 외에 선택지가 없었습니다.

새로운 흐름

탈퇴 후 30일 이내 재로그인 시 사용자에게 두 가지 선택지를 제공합니다:

  1. 계정 복구 (POST /api/auth/kakao/restore)

    • User.deletedAt = null로 되돌림
    • UserSettings는 탈퇴 시 보존되어 사용자가 이전에 설정한 알림 옵션이 그대로 유지됨
    • 비활성화된 사업장/계약/근무기록은 자동 복구하지 않음 (다른 사용자 데이터 일관성 보호)
  2. 완전 삭제 후 재가입 (POST /api/auth/kakao/purge-and-register)

    • 기존 UserHardDeleteService.hardDeleteUser()(30일 스케줄러와 동일 경로) 재활용
    • 모든 산하 데이터 영구 삭제 후 신규 가입 진행
    • 요청 DTO는 기존 KakaoRegisterRequest 그대로 재사용

API 응답 형식

  • 정상 로그인:
    { "success": true, "data": { "status": "LOGGED_IN", "login": { "accessToken": "...", "refreshToken": "...", "userId": 9, "name": "...", "userType": "EMPLOYER" } } }
  • 탈퇴 계정 발견:
    { "success": true, "data": { "status": "WITHDRAWN_PENDING", "withdrawnAccount": { "name": "...", "userType": "EMPLOYER", "withdrawnAt": "...", "profileImageUrl": "..." } } }

⚠️ 클라이언트 영향: POST /api/auth/kakao/login 응답 페이로드 형식이 변경되었습니다 (status 분기 추가).

미복구 항목 (정책)

  • FCM Token: 클라이언트 재등록 필요
  • 과거 Notification: 복구 불가 (탈퇴 시 hard delete됨)
  • 비활성화된 Workplace/Contract/WorkRecord: 자동 복구하지 않음

✅ 체크리스트

  • PR 제목이 형식에 맞는가? ([fix] 작업 요약)
  • 코드가 정상적으로 빌드되는가?
  • 새로운 기능에 대한 테스트 코드를 작성했는가? (AuthServiceTest 5건 추가/변경)
  • 모든 테스트가 통과하는가? (전체 ./gradlew test BUILD SUCCESSFUL)
  • 코드 스타일 가이드를 따랐는가?
  • 관련 문서를 업데이트했는가? (API_SPECIFICATION.md 업데이트는 후속 작업으로 분리 가능)

🔗 관련 PR

🤖 Generated with Claude Code

Summary by CodeRabbit

카카오 로그인 및 계정 관리 개선

  • 새 기능

    • 탈퇴한 카카오 계정 로그인 시 상태 표기(status: WITHDRAWN_PENDING)와 탈퇴 계정 정보 제공
    • 탈퇴 계정 복구(재활성화) 엔드포인트 추가
    • 탈퇴 계정 완전삭제 후 재가입(퍼지+재가입) 흐름 추가
  • 개선사항

    • 정상 로그인 응답에 상태(status)와 토큰/사용자 정보 명확화
    • 계정 탈퇴 시 사용자 설정(UserSettings) 보존
  • 문서

    • 인증 API 명세 및 예제에 위 변경사항과 오류/응답 예시 추가

Review Change Stack

geunyong16 added 3 commits May 5, 2026 18:21
User 엔티티에 추가된 @Version 필드에 대응하는 DB 마이그레이션 누락으로
모든 API 요청이 500 Internal Server Error를 반환하는 문제 해결.

Closes #181
JPA @Version 필드는 낙관적 잠금을 위해 항상 non-null이어야 하므로
NOT NULL 제약 조건을 추가. DEFAULT 0이 설정되어 있어 기존 행은
안전하게 0으로 초기화됨.

CodeRabbit 리뷰 반영.
- POST /api/auth/kakao/login 응답 변경: 탈퇴 계정 발견 시 예외 대신
  status=WITHDRAWN_PENDING 페이로드 반환하여 클라이언트가 사용자 선택 안내 가능
- POST /api/auth/kakao/restore 신규: User.deletedAt=null로 복구 (탈퇴 취소).
  사업장/계약/근무기록은 다른 사용자 데이터 일관성 보호 위해 자동 복구 안 함
- POST /api/auth/kakao/purge-and-register 신규: 30일 스케줄러와 동일 경로
  (UserHardDeleteService.hardDeleteUser)로 영구 삭제 후 신규 가입
- UserWithdrawService.cleanupCommonData에서 UserSettings 삭제 제거 →
  복구 시 사용자 알림 설정 그대로 유지. 30일 hard delete 시점에 정리됨
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 540943c9-c7c6-40cb-a23a-8429463225bc

📥 Commits

Reviewing files that changed from the base of the PR and between d6c47e8 and 0edea2c.

📒 Files selected for processing (4)
  • docs/API_SPECIFICATION.md
  • src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java
  • src/main/java/com/example/paycheck/domain/auth/service/AuthService.java
  • src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java
  • src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java
  • src/main/java/com/example/paycheck/domain/auth/service/AuthService.java

Walkthrough

카카오 로그인이 탈퇴 계정을 발견하면 200 + 상태형 응답을 반환하고, 복구(/kakao/restore) 또는 완전삭제 후 재가입(/kakao/purge-and-register)을 수행하는 서비스·컨트롤러·엔티티·테스트·마이그레이션을 추가합니다.

Changes

카카오 계정 탈퇴 라이프사이클

Layer / File(s) Summary
데이터 계약 및 타입
src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java, src/main/java/com/example/paycheck/common/exception/ErrorCode.java
KakaoLoginResult(status: LOGGED_IN/WITHDRAWN_PENDING) 및 WithdrawnAccountInfo 추가. USER_NOT_WITHDRAWN 에러 코드 추가.
컨트롤러: 엔드포인트 업데이트
src/main/java/com/example/paycheck/api/auth/AuthController.java
/kakao/login 응답 타입을 ApiResponse<AuthDto.KakaoLoginResult>로 변경. /kakao/restore/kakao/purge-and-register 엔드포인트 추가(POST).
인증 서비스 메서드
src/main/java/com/example/paycheck/domain/auth/service/AuthService.java
loginWithKakao 반환을 AuthDto.KakaoLoginResult로 변경해 탈퇴 계정은 WITHDRAWN_PENDING 반환. restoreWithKakao, purgeAndRegisterWithKakao, registerWithKakaoInternal, buildLoginResponse 추가 및 UserHardDeleteService 주입.
사용자 엔티티 및 탈퇴 정책
src/main/java/com/example/paycheck/domain/user/entity/User.java, src/main/java/com/example/paycheck/domain/user/service/UserWithdrawService.java
User.restore() 추가로 deletedAt 초기화. UserWithdrawService.cleanupCommonData에서 UserSettings 삭제 제거(보존 후 하드 삭제 시점에 정리).
테스트·문서·마이그레이션
src/test/java/.../AuthServiceTest.java, src/test/java/.../UserWithdrawServiceTest.java, docs/API_SPECIFICATION.md, src/main/resources/db/migration/V20260505__Add_version_column_to_users.sql
AuthService 테스트들의 로그인/탈퇴/복구/완전삭제 흐름 검증 추가·수정. API 명세 및 JSON 예제 업데이트. users 테이블에 version BIGINT NOT NULL DEFAULT 0 마이그레이션 추가.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AuthController
  participant AuthService
  participant UserHardDeleteService
  participant UserService
  Client->>AuthController: POST /api/auth/kakao/login\n(kakaoAccessToken)
  AuthController->>AuthService: loginWithKakao(kakaoAccessToken)
  alt 활성 사용자
    AuthService->>AuthController: KakaoLoginResult(LOGGED_IN with tokens)
    AuthController->>Client: 200 ApiResponse{data: LOGGED_IN}
  else 탈퇴 계정
    AuthService->>AuthController: KakaoLoginResult(WITHDRAWN_PENDING withdrawnAccount)
    AuthController->>Client: 200 ApiResponse{data: WITHDRAWN_PENDING}
    Client->>AuthController: POST /api/auth/kakao/restore\n(kakaoAccessToken)
    AuthController->>AuthService: restoreWithKakao(kakaoAccessToken)
    AuthService->>AuthService: user.restore()\ngenerateTokens()
    AuthService->>AuthController: LoginResponse(tokens)
    AuthController->>Client: 200 ApiResponse{data: LoginResponse}
    Client->>AuthController: POST /api/auth/kakao/purge-and-register\n(registerRequest)
    AuthController->>AuthService: purgeAndRegisterWithKakao(request)
    AuthService->>UserHardDeleteService: hardDeleteUser(user)
    AuthService->>UserService: register(newUser)
    AuthService->>AuthController: LoginResponse(new tokens)
    AuthController->>Client: 200 ApiResponse{data: LoginResponse}
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

개요

카카오 소셜 로그인을 통해 탈퇴한 계정의 복구 및 재가입 워크플로우를 구현했습니다. 탈퇴 계정 로그인 시 오류 반환 대신 탈퇴 상태를 알리고, 복구 또는 완전 삭제 후 재가입 중 선택할 수 있도록 변경했으며, 탈퇴 시 사용자 설정을 30일간 보존하도록 정책을 수정했습니다.

변경 사항

카카오 계정 탈퇴 라이프사이클

레이어 / 파일(s) 요약
데이터 계약 및 타입
src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java, src/main/java/com/example/paycheck/common/exception/ErrorCode.java
로그인 상태를 나타내는 KakaoLoginResult (status: LOGGED_IN 또는 WITHDRAWN_PENDING, 조건부 login 또는 withdrawnAccount 필드)와 탈퇴 계정 정보를 담는 WithdrawnAccountInfo DTO 추가. USER_NOT_WITHDRAWN 에러 코드 추가.
인증 서비스 메서드
src/main/java/com/example/paycheck/domain/auth/service/AuthService.java
loginWithKakao 반환 타입을 AuthDto.KakaoLoginResult로 변경하여 탈퇴 계정은 오류 대신 WITHDRAWN_PENDING 응답 반환. restoreWithKakao 메서드로 탈퇴 계정 복구. purgeAndRegisterWithKakao 메서드로 완전 삭제 후 재가입. registerWithKakaoInternal 메서드로 가입 로직 중앙화.
사용자 엔티티 및 탈퇴 정책
src/main/java/com/example/paycheck/domain/user/entity/User.java, src/main/java/com/example/paycheck/domain/user/service/UserWithdrawService.java
User.restore() 메서드 추가로 deletedAt 필드 초기화. UserWithdrawService에서 탈퇴 시 UserSettings 삭제 제거 및 30일 후 하드 삭제 시점으로 연기.
API 엔드포인트 업데이트
src/main/java/com/example/paycheck/api/auth/AuthController.java
/kakao/login 응답 타입 변경 (ApiResponse<AuthDto.KakaoLoginResult>). /kakao/restore 엔드포인트 구현. /kakao/purge-and-register 엔드포인트 신규 추가 (POST).
테스트 및 마이그레이션
src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java, src/test/java/com/example/paycheck/domain/user/service/UserWithdrawServiceTest.java, src/main/resources/db/migration/V20260505__Add_version_column_to_users.sql
새로운 로그인 응답 구조 반영 및 복구/재가입 테스트 추가. 탈퇴 시 UserSettings 삭제 검증 제거. 낙관적 잠금을 위해 users 테이블에 version 컬럼(BIGINT, 기본값 0) 추가.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 [fix]로 시작하며 탈퇴 후 카카오 재로그인 시 계정 복구/재가입 옵션 제공이라는 주요 변경 사항을 명확하게 설명합니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 관련 이슈, 주요 변경 내용, 상세 설명, 체크리스트를 모두 포함하며 API 응답 형식까지 구체적으로 제시합니다.
Linked Issues check ✅ Passed 코드 변경이 #183의 모든 주요 요구사항을 충족합니다: 탈퇴 계정 시 WITHDRAWN_PENDING 응답, 복구/재가입 엔드포인트 추가, UserSettings 보존, 정책 명시.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #183에 명시된 범위 내에서 이루어졌으며, 탈퇴/복구 흐름 구현에 필요한 최소한의 변경만 포함됩니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/183-restore-or-purge-on-kakao-relogin

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (3)
src/main/java/com/example/paycheck/domain/auth/service/AuthService.java (1)

262-265: ⚡ Quick win

registerWithKakaoInternal의 가시성/트랜잭션 책임 재정리 권장

현재 public + @Transactional이지만 두 호출처(registerWithKakao, purgeAndRegisterWithKakao) 모두 동일 클래스 내부에서 this.로 호출하기 때문에 이 메서드의 @Transactional은 어느 경로에서도 직접 효력을 발휘하지 못합니다(외곽 메서드의 트랜잭션을 단순히 상속할 뿐). 가시성 또한 public일 필요가 없습니다. 위 critical 코멘트와 함께 다음 중 하나로 정리하는 것을 추천합니다:

  • 외곽 두 메서드 모두 @Transactional을 갖도록 보장하고, 내부 메서드는 private로 강등 + 어노테이션 제거
  • 또는 이 메서드를 별도 빈으로 분리하여 프록시를 통해 호출
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/example/paycheck/domain/auth/service/AuthService.java`
around lines 262 - 265, The registerWithKakaoInternal method is declared public
and annotated with `@Transactional` but is only called internally via this., so
its transaction proxy never applies; make registerWithKakaoInternal private and
remove its `@Transactional`, and instead annotate the two callers
registerWithKakao and purgeAndRegisterWithKakao with `@Transactional` (or extract
registerWithKakaoInternal into a separate `@Component/`@Service bean so it can be
called via proxy) so transactional behavior is actually applied when needed.
src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java (1)

587-654: 💤 Low value

테스트 보강 권장 — purgeAndRegisterWithKakao에서 기존 사용자가 없는 경우의 분기

production 코드 라인 165-174는 userRepository.findByKakaoId(...)가 비어 있을 때 hard delete를 건너뛰고 등록만 진행하도록 되어 있는데, 이 분기를 검증하는 테스트가 없습니다. 정책상 흔한 호출 케이스는 아니지만(탈퇴 후 재가입 의도가 전제), ifPresent 분기 회귀 방지를 위해 verify(userHardDeleteService, never()).hardDeleteUser(anyLong()) + 정상 가입 결과 검증 테스트를 한 건 추가해두면 좋습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java`
around lines 587 - 654, Add a unit test for the
purgeAndRegisterWithKakao(UserDto.KakaoRegisterRequest) success path when
userRepository.findByKakaoId(...) returns Optional.empty(): mock
oAuthService.getKakaoUserInfo(...) to return kakaoUserInfo, mock
userRepository.findByKakaoId(...) to return Optional.empty(), mock
userService.register(...) to return a RegisterResponse and
tokenService.generateTokenPair(...) to return tokenPair, then call
authService.purgeAndRegisterWithKakao(request) and verify that
userHardDeleteService.hardDeleteUser(...) is never called,
userService.register(...) is called once, and the returned LoginResponse
contains the expected accessToken, refreshToken, and userId; reference methods:
purgeAndRegisterWithKakao, userRepository.findByKakaoId,
userHardDeleteService.hardDeleteUser, userService.register,
tokenService.generateTokenPair.
src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java (1)

107-129: ⚡ Quick win

status 값을 enum/상수로 승격 권장

현재 statusString이고, loggedIn()/withdrawnPending() 팩토리, 컨트롤러 응답, 테스트 단언(AuthServiceTest에서 "LOGGED_IN", "WITHDRAWN_PENDING" 직접 비교)에서 동일한 리터럴이 중복 등장합니다. 향후 신규 상태 추가나 리네이밍 시 누락 위험이 있으니 enum 또는 public static final String 상수로 단일 출처화하는 것을 권장합니다.

♻️ 제안 — enum 도입 예시
     public static class KakaoLoginResult {
+        public enum Status { LOGGED_IN, WITHDRAWN_PENDING }
+
         `@Schema`(description = "로그인 결과 상태", allowableValues = {"LOGGED_IN", "WITHDRAWN_PENDING"})
-        private String status;
+        private Status status;
         ...
         public static KakaoLoginResult loggedIn(LoginResponse login) {
             return KakaoLoginResult.builder()
-                    .status("LOGGED_IN")
+                    .status(Status.LOGGED_IN)
                     .login(login)
                     .build();
         }

테스트와 직렬화 출력은 enum의 name()이 동일 문자열을 내보내므로 호환됩니다(Jackson 기본 직렬화).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java` around lines
107 - 129, Convert the String-typed status in KakaoLoginResult to a
single-source enum or constants to avoid repeated literals: introduce a new enum
KakaoLoginStatus (values LOGGED_IN, WITHDRAWN_PENDING) or public static final
Strings with those names, change the field "status" to use that enum/type,
update the factory methods KakaoLoginResult.loggedIn(LoginResponse) and
KakaoLoginResult.withdrawnPending(WithdrawnAccountInfo) to set status using the
enum/constant, and adjust the `@Schema` allowableValues/description to reference
the enum names; then update any callers/tests (e.g., AuthServiceTest and
controller responses) to compare against KakaoLoginStatus.LOGGED_IN /
.WITHDRAWN_PENDING or the new constants.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/example/paycheck/api/auth/AuthController.java`:
- Around line 22-32: The kakaoLogin response type was changed from
ApiResponse<LoginResponse> to ApiResponse<KakaoLoginResult>, breaking clients
that expect top-level fields like data.accessToken, data.refreshToken,
data.userId; update AuthController.kakaoLogin and related service/output DTOs to
restore backward compatibility or provide a migration path: either (A) keep the
existing endpoint signature (ApiResponse<LoginResponse>) and map the new
AuthDto.KakaoLoginResult into the old flat AuthDto.LoginResponse shape when
status==LOGGED_IN, or (B) introduce a new versioned endpoint (e.g.,
/api/v2/auth/kakao/login) that returns ApiResponse<KakaoLoginResult> and leave
the current /api/auth/kakao/login unchanged; additionally update API docs
(docs/API_SPECIFICATION.md) to reflect the new response branching (status +
login/withdrawnAccount) and add docs/examples for /api/auth/kakao/restore and
/api/auth/kakao/purge-and-register so clients can migrate safely.

In `@src/main/java/com/example/paycheck/domain/auth/service/AuthService.java`:
- Around line 161-177: Add a transactional boundary to make hard delete and
registration atomic: annotate the public method purgeAndRegisterWithKakao with
`@Transactional` (default propagation REQUIRED) so the call to
userHardDeleteService.hardDeleteUser(...) and the subsequent
registerWithKakaoInternal(...) execute in the same transaction and will roll
back together on failure; ensure the class is a Spring bean and imports javax/
spring transaction annotation as appropriate so the proxy applies.

---

Nitpick comments:
In `@src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java`:
- Around line 107-129: Convert the String-typed status in KakaoLoginResult to a
single-source enum or constants to avoid repeated literals: introduce a new enum
KakaoLoginStatus (values LOGGED_IN, WITHDRAWN_PENDING) or public static final
Strings with those names, change the field "status" to use that enum/type,
update the factory methods KakaoLoginResult.loggedIn(LoginResponse) and
KakaoLoginResult.withdrawnPending(WithdrawnAccountInfo) to set status using the
enum/constant, and adjust the `@Schema` allowableValues/description to reference
the enum names; then update any callers/tests (e.g., AuthServiceTest and
controller responses) to compare against KakaoLoginStatus.LOGGED_IN /
.WITHDRAWN_PENDING or the new constants.

In `@src/main/java/com/example/paycheck/domain/auth/service/AuthService.java`:
- Around line 262-265: The registerWithKakaoInternal method is declared public
and annotated with `@Transactional` but is only called internally via this., so
its transaction proxy never applies; make registerWithKakaoInternal private and
remove its `@Transactional`, and instead annotate the two callers
registerWithKakao and purgeAndRegisterWithKakao with `@Transactional` (or extract
registerWithKakaoInternal into a separate `@Component/`@Service bean so it can be
called via proxy) so transactional behavior is actually applied when needed.

In `@src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java`:
- Around line 587-654: Add a unit test for the
purgeAndRegisterWithKakao(UserDto.KakaoRegisterRequest) success path when
userRepository.findByKakaoId(...) returns Optional.empty(): mock
oAuthService.getKakaoUserInfo(...) to return kakaoUserInfo, mock
userRepository.findByKakaoId(...) to return Optional.empty(), mock
userService.register(...) to return a RegisterResponse and
tokenService.generateTokenPair(...) to return tokenPair, then call
authService.purgeAndRegisterWithKakao(request) and verify that
userHardDeleteService.hardDeleteUser(...) is never called,
userService.register(...) is called once, and the returned LoginResponse
contains the expected accessToken, refreshToken, and userId; reference methods:
purgeAndRegisterWithKakao, userRepository.findByKakaoId,
userHardDeleteService.hardDeleteUser, userService.register,
tokenService.generateTokenPair.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 151407ac-730e-4cdd-a0a7-9a63d7530b88

📥 Commits

Reviewing files that changed from the base of the PR and between cd8cebc and d6c47e8.

📒 Files selected for processing (9)
  • src/main/java/com/example/paycheck/api/auth/AuthController.java
  • src/main/java/com/example/paycheck/common/exception/ErrorCode.java
  • src/main/java/com/example/paycheck/domain/auth/dto/AuthDto.java
  • src/main/java/com/example/paycheck/domain/auth/service/AuthService.java
  • src/main/java/com/example/paycheck/domain/user/entity/User.java
  • src/main/java/com/example/paycheck/domain/user/service/UserWithdrawService.java
  • src/main/resources/db/migration/V20260505__Add_version_column_to_users.sql
  • src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java
  • src/test/java/com/example/paycheck/domain/user/service/UserWithdrawServiceTest.java

Comment thread src/main/java/com/example/paycheck/api/auth/AuthController.java
- KakaoLoginResult를 평탄 구조로 재설계: status + accessToken/refreshToken/userId/name/userType
  를 top-level에 두어 기존 클라이언트(data.accessToken 등)와 호환 유지. 탈퇴 케이스는
  status=WITHDRAWN_PENDING + withdrawnAccount만 채움.
- purgeAndRegisterWithKakao에 @transactional 추가하여 hardDelete + register를 하나의
  트랜잭션으로 묶음. register 실패 시 hardDelete도 함께 롤백되어 데이터 영구 손실 방지.
- hardDeleteUser 직후 userRepository.flush() 명시 호출. JPA 기본 flush 순서(INSERT→DELETE)
  로 인한 unique kakao_id 제약 충돌을 회피.
- AuthServiceTest: 평탄 응답 접근 방식으로 수정, hardDelete→flush→register 호출 순서 검증,
  register 실패 시 예외 전파 검증 추가.
- docs/API_SPECIFICATION.md: 1.1 카카오 로그인 응답을 평탄 구조로 동기화하고
  1.5 탈퇴 계정 복구, 1.6 완전삭제 후 재가입 항목 신규 추가.
@geunyong16 geunyong16 merged commit e4a621e into main May 11, 2026
2 checks passed
@geunyong16 geunyong16 deleted the fix/183-restore-or-purge-on-kakao-relogin branch May 11, 2026 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 회원 탈퇴 후 카카오 재가입 시 '탈퇴한 계정' 오류로 로그인 불가

1 participant