Skip to content

feat(S15P11A705-65): 회원 탈퇴 구현 (소프트 삭제·마스킹·세션 무효화) #34

Description

@cherry-go-round

배경 / 목적

MVP 기능범위에 회원 탈퇴가 포함되어 있고 API 명세 §2.1에 DELETE /me가 정의되어 있습니다. 정책 정의서 10장이 소프트 삭제 원칙을, ERD가 마스킹 대상을 정의합니다. 로그인과 독립적으로 검증·배포할 수 있어 별도 티켓으로 분리합니다.

Jira (필수)

상위/관련 GitHub Issue

상세 내용

상세 계약은 08_API_명세 §3.6에 이미 있습니다.

  • DELETE /api/core/v1/me, 204. 본인 인증 요구
  • member·social_account deleted_at 소프트 삭제
  • social_accountprovider_user_id·email 마스킹 (개인정보 파기 대상)
  • 해당 회원의 Refresh를 전부 무효화 — 탈퇴는 모든 기기에서 즉시 끊겨야 합니다. /me는 Refresh 쿠키 Path 밖이라 Access 쿠키로 회원을 식별합니다
  • 인증 쿠키와 logged_in 표시 쿠키 만료

구현 주의 — repository.delete()를 쓰지 마세요

Member가 쓰는 @SQLDelete + @SQLRestriction 패턴을 SocialAccount에 그대로 적용하면, delete() 호출 시점에 Hibernate가 엔티티를 removed 상태로 보고 마스킹 변경이 flush되지 않습니다. @SQLRestriction 때문에 다시 조회해서 고칠 수도 없습니다.

도메인 메서드로 마스킹과 deleted_at한 UPDATE에 담습니다.

public void withdraw() {
    this.providerUserId = "deleted:" + this.id;   // 부분 유니크 충돌을 피할 유일값
    this.email = null;
    softDelete();
}

"마스킹 후 delete()" 순서로도 동작할 가능성이 있지만, removed 상태 엔티티에 UPDATE가 스케줄되는지는 Hibernate 7 기준으로 확인되지 않았습니다. 그 방식을 택한다면 아래 검증 테스트로 먼저 확인하고 결과를 구현 리포트에 남겨주세요.

검증은 native 쿼리로

삭제 표시된 행은 @SQLRestriction 때문에 리포지토리로 보이지 않습니다. 마스킹 확인은 JdbcTemplate으로 합니다 (#25의 MemberSoftDeleteTests와 같은 방식).

이번 범위 밖

해당 테이블이 아직 없어 구현할 수 없는 항목입니다. 문서에 남기고 후속으로 넘깁니다.

  • record·context·collection·collection_record·follow 연쇄 소프트 삭제 (정책 10장)
  • AI 파생 데이터 무효화ai.context_ai_state의 두 status → CANCELLED, ai.context_embedding.is_deleted = true (docs#14). context가 생긴 뒤 붙습니다. 물리 삭제가 아니라 무효화 표시입니다

place는 공용 데이터라 삭제 대상이 아닙니다.

할 일

  • SocialAccount.withdraw() 도메인 메서드
  • DELETE /me 컨트롤러·서비스
  • 회원 단위 Refresh 전체 무효화
  • 쿠키 3종 만료 (Access·Refresh·logged_in)
  • native 쿼리 기반 검증 테스트
  • 범위 밖 항목과 후속 조건을 문서에 기록

완료 조건

  • 인증된 사용자가 DELETE /me를 호출하면 membersocial_accountdeleted_at이 설정된다
  • provider_user_idemail이 마스킹되어 원본 값이 조회되지 않는다 (native 쿼리로 검증)
  • 마스킹과 deleted_at한 트랜잭션에서 모두 반영된다 — 둘 중 하나만 적용되는 경우가 없다
  • 탈퇴 후 기존 인증 쿠키로 보호 경로를 요청하면 401
  • 탈퇴 후 Redis에 해당 회원의 Refresh Token이 하나도 남지 않는다
  • 응답에서 인증 쿠키와 logged_in 쿠키가 모두 만료된다
  • 미인증 DELETE /me는 401
  • 탈퇴한 계정과 동일한 provider·provider_user_id로 다시 로그인하면 신규 회원으로 가입된다
  • 연쇄 소프트 삭제·AI 파생 데이터 무효화가 범위 밖인 사실과 후속 조건이 문서에 기록된다
  • PostgreSQL Testcontainers 기반 통합 테스트로 위 항목을 검증한다
  • ./gradlew clean check --no-daemon 통과

Metadata

Metadata

Labels

enhancement새 기능·개선 (feat)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions