Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ public class Chat {
@Lob
private String message;

@OneToMany(mappedBy = "chatId")
@OneToMany(mappedBy = "chatId", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ChatPrecedent> chatPrecedents;

@OneToMany(mappedBy = "chatId")
@OneToMany(mappedBy = "chatId", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ChatLaw> chatLaws;

@CreationTimestamp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

import com.ai.lawyer.domain.chatbot.entity.ChatLaw;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface ChatLawRepository extends JpaRepository<ChatLaw, Long> {

/**
* member_id에 해당하는 모든 ChatLaw 삭제 (회원 탈퇴 시 사용)
*/
@Modifying
@Query("DELETE FROM ChatLaw cl WHERE cl.chatId.historyId.memberId.memberId = :memberId")
void deleteByMemberIdValue(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

import com.ai.lawyer.domain.chatbot.entity.ChatPrecedent;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface ChatPrecedentRepository extends JpaRepository<ChatPrecedent, Long> {

/**
* member_id에 해당하는 모든 ChatPrecedent 삭제 (회원 탈퇴 시 사용)
*/
@Modifying
@Query("DELETE FROM ChatPrecedent cp WHERE cp.chatId.historyId.memberId.memberId = :memberId")
void deleteByMemberIdValue(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

import com.ai.lawyer.domain.chatbot.entity.Chat;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface ChatRepository extends JpaRepository<Chat, Long> {

/**
* member_id에 해당하는 모든 Chat 삭제 (회원 탈퇴 시 사용)
*/
@Modifying
@Query("DELETE FROM Chat c WHERE c.historyId.memberId.memberId = :memberId")
void deleteByMemberIdValue(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import com.ai.lawyer.domain.post.repository.PostRepository;
import com.ai.lawyer.domain.poll.repository.PollVoteRepository;
import com.ai.lawyer.domain.chatbot.repository.HistoryRepository;
import com.ai.lawyer.domain.chatbot.repository.ChatRepository;
import com.ai.lawyer.domain.chatbot.repository.ChatPrecedentRepository;
import com.ai.lawyer.domain.chatbot.repository.ChatLawRepository;
import com.ai.lawyer.global.jwt.TokenProvider;
import com.ai.lawyer.global.jwt.CookieUtil;
import com.ai.lawyer.global.email.service.EmailService;
Expand All @@ -33,6 +36,9 @@ public class MemberService {
private final PostRepository postRepository;
private final PollVoteRepository pollVoteRepository;
private final HistoryRepository historyRepository;
private final ChatRepository chatRepository;
private final ChatPrecedentRepository chatPrecedentRepository;
private final ChatLawRepository chatLawRepository;

public MemberService(
MemberRepository memberRepository,
Expand All @@ -43,7 +49,10 @@ public MemberService(
EmailAuthService emailAuthService,
PostRepository postRepository,
PollVoteRepository pollVoteRepository,
HistoryRepository historyRepository) {
HistoryRepository historyRepository,
ChatRepository chatRepository,
ChatPrecedentRepository chatPrecedentRepository,
ChatLawRepository chatLawRepository) {
this.memberRepository = memberRepository;
this.passwordEncoder = passwordEncoder;
this.tokenProvider = tokenProvider;
Expand All @@ -53,6 +62,9 @@ public MemberService(
this.postRepository = postRepository;
this.pollVoteRepository = pollVoteRepository;
this.historyRepository = historyRepository;
this.chatRepository = chatRepository;
this.chatPrecedentRepository = chatPrecedentRepository;
this.chatLawRepository = chatLawRepository;
}

@org.springframework.beans.factory.annotation.Autowired(required = false)
Expand Down Expand Up @@ -225,37 +237,32 @@ public void deleteMember(String loginId) {
// 2. 연관된 데이터 명시적 삭제 (순서 중요: FK 제약조건 고려)
log.info("연관 데이터 삭제 시작: memberId={}", memberId);

// 2-1. 채팅 히스토리 삭제 (Chat 엔티티도 cascade로 함께 삭제됨)
try {
historyRepository.deleteByMemberIdValue(memberId);
log.info("채팅 히스토리 삭제 완료: memberId={}", memberId);
} catch (Exception e) {
log.error("채팅 히스토리 삭제 실패: memberId={}, error={}", memberId, e.getMessage());
}
// 2-1. ChatPrecedent, ChatLaw 삭제 (Chat의 FK 참조)
chatPrecedentRepository.deleteByMemberIdValue(memberId);
log.info("채팅 판례 삭제 완료: memberId={}", memberId);

// 2-2. 투표 내역 삭제
try {
pollVoteRepository.deleteByMemberIdValue(memberId);
log.info("투표 내역 삭제 완료: memberId={}", memberId);
} catch (Exception e) {
log.error("투표 내역 삭제 실패: memberId={}, error={}", memberId, e.getMessage());
}
chatLawRepository.deleteByMemberIdValue(memberId);
log.info("채팅 법령 삭제 완료: memberId={}", memberId);

// 2-3. 게시글 삭제 (Poll 엔티티도 cascade로 함께 삭제됨)
try {
postRepository.deleteByMemberIdValue(memberId);
log.info("게시글 삭제 완료: memberId={}", memberId);
} catch (Exception e) {
log.error("게시글 삭제 실패: memberId={}, error={}", memberId, e.getMessage());
}
// 2-2. Chat 삭제 (History의 FK 참조)
chatRepository.deleteByMemberIdValue(memberId);
log.info("채팅 삭제 완료: memberId={}", memberId);

// 2-3. History 삭제 (Member의 FK 참조)
historyRepository.deleteByMemberIdValue(memberId);
log.info("채팅 히스토리 삭제 완료: memberId={}", memberId);

// 2-4. 투표 내역 삭제
pollVoteRepository.deleteByMemberIdValue(memberId);
log.info("투표 내역 삭제 완료: memberId={}", memberId);

// 2-5. 게시글 삭제 (Poll 엔티티도 cascade로 함께 삭제됨)
postRepository.deleteByMemberIdValue(memberId);
log.info("게시글 삭제 완료: memberId={}", memberId);

// 3. Redis 토큰 삭제
try {
tokenProvider.deleteAllTokens(loginId);
log.info("Redis 토큰 삭제 완료: loginId={}", loginId);
} catch (Exception e) {
log.error("Redis 토큰 삭제 실패: loginId={}, error={}", loginId, e.getMessage());
}
tokenProvider.deleteAllTokens(loginId);
log.info("Redis 토큰 삭제 완료: loginId={}", loginId);

// 4. 회원 정보 삭제
final Long finalMemberId = memberId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ class MemberServiceOAuth2Test {
@Mock
private com.ai.lawyer.domain.chatbot.repository.HistoryRepository historyRepository;

@Mock
private com.ai.lawyer.domain.chatbot.repository.ChatRepository chatRepository;

@Mock
private com.ai.lawyer.domain.chatbot.repository.ChatPrecedentRepository chatPrecedentRepository;

@Mock
private com.ai.lawyer.domain.chatbot.repository.ChatLawRepository chatLawRepository;

@Mock
private HttpServletResponse response;

Expand All @@ -86,7 +95,10 @@ void setUp() {
emailAuthService,
postRepository,
pollVoteRepository,
historyRepository
historyRepository,
chatRepository,
chatPrecedentRepository,
chatLawRepository
);
memberService.setOauth2MemberRepository(oauth2MemberRepository);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ class MemberServiceTest {
@Mock
private com.ai.lawyer.domain.chatbot.repository.HistoryRepository historyRepository;

@Mock
private com.ai.lawyer.domain.chatbot.repository.ChatRepository chatRepository;

@Mock
private com.ai.lawyer.domain.chatbot.repository.ChatPrecedentRepository chatPrecedentRepository;

@Mock
private com.ai.lawyer.domain.chatbot.repository.ChatLawRepository chatLawRepository;

@Mock
private HttpServletResponse response;

Expand All @@ -85,7 +94,10 @@ void setUp() {
emailAuthService,
postRepository,
pollVoteRepository,
historyRepository
historyRepository,
chatRepository,
chatPrecedentRepository,
chatLawRepository
);
memberService.setOauth2MemberRepository(oauth2MemberRepository);

Expand Down Expand Up @@ -315,7 +327,10 @@ void withdraw_Success() {
// 1. 회원 조회
verify(memberRepository).findByLoginId(loginId);

// 2. 연관 데이터 명시적 삭제 (순서 중요)
// 2. 연관 데이터 명시적 삭제 (순서 중요: FK 제약조건 고려)
verify(chatPrecedentRepository).deleteByMemberIdValue(member.getMemberId());
verify(chatLawRepository).deleteByMemberIdValue(member.getMemberId());
verify(chatRepository).deleteByMemberIdValue(member.getMemberId());
verify(historyRepository).deleteByMemberIdValue(member.getMemberId());
verify(pollVoteRepository).deleteByMemberIdValue(member.getMemberId());
verify(postRepository).deleteByMemberIdValue(member.getMemberId());
Expand Down