배경 / 목적
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_account의 provider_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는 공용 데이터라 삭제 대상이 아닙니다.
할 일
완료 조건
배경 / 목적
MVP 기능범위에 회원 탈퇴가 포함되어 있고 API 명세 §2.1에
DELETE /me가 정의되어 있습니다. 정책 정의서 10장이 소프트 삭제 원칙을, ERD가 마스킹 대상을 정의합니다. 로그인과 독립적으로 검증·배포할 수 있어 별도 티켓으로 분리합니다.Jira (필수)
[BE] 소셜 로그인 및 계정 관리상위/관련 GitHub Issue
상세 내용
상세 계약은 08_API_명세 §3.6에 이미 있습니다.
DELETE /api/core/v1/me, 204. 본인 인증 요구member·social_accountdeleted_at소프트 삭제social_account의provider_user_id·email마스킹 (개인정보 파기 대상)/me는 Refresh 쿠키Path밖이라 Access 쿠키로 회원을 식별합니다logged_in표시 쿠키 만료구현 주의 —
repository.delete()를 쓰지 마세요Member가 쓰는@SQLDelete+@SQLRestriction패턴을SocialAccount에 그대로 적용하면,delete()호출 시점에 Hibernate가 엔티티를 removed 상태로 보고 마스킹 변경이 flush되지 않습니다.@SQLRestriction때문에 다시 조회해서 고칠 수도 없습니다.도메인 메서드로 마스킹과
deleted_at을 한 UPDATE에 담습니다."마스킹 후
delete()" 순서로도 동작할 가능성이 있지만, removed 상태 엔티티에 UPDATE가 스케줄되는지는 Hibernate 7 기준으로 확인되지 않았습니다. 그 방식을 택한다면 아래 검증 테스트로 먼저 확인하고 결과를 구현 리포트에 남겨주세요.검증은 native 쿼리로
삭제 표시된 행은
@SQLRestriction때문에 리포지토리로 보이지 않습니다. 마스킹 확인은JdbcTemplate으로 합니다 (#25의MemberSoftDeleteTests와 같은 방식).이번 범위 밖
해당 테이블이 아직 없어 구현할 수 없는 항목입니다. 문서에 남기고 후속으로 넘깁니다.
record·context·collection·collection_record·follow연쇄 소프트 삭제 (정책 10장)ai.context_ai_state의 두 status →CANCELLED,ai.context_embedding.is_deleted = true(docs#14).context가 생긴 뒤 붙습니다. 물리 삭제가 아니라 무효화 표시입니다place는 공용 데이터라 삭제 대상이 아닙니다.할 일
SocialAccount.withdraw()도메인 메서드DELETE /me컨트롤러·서비스logged_in)완료 조건
DELETE /me를 호출하면member와social_account의deleted_at이 설정된다provider_user_id와email이 마스킹되어 원본 값이 조회되지 않는다 (native 쿼리로 검증)deleted_at이 한 트랜잭션에서 모두 반영된다 — 둘 중 하나만 적용되는 경우가 없다logged_in쿠키가 모두 만료된다DELETE /me는 401provider·provider_user_id로 다시 로그인하면 신규 회원으로 가입된다./gradlew clean check --no-daemon통과