Skip to content

Conversation

@whqtker
Copy link
Member

@whqtker whqtker commented Nov 20, 2025

관련 이슈

작업 내용

FK의 ON DELETE CASCADE 옵션을 사용하여 DB 레벨에서 연관 레코드를 삭제하도록 구현했습니다.
FK를 재설정하면서 컨벤션에 맞지 않았던 FK 제약조건 이름도 같이 수정했습니다.

deleteAllByXXX 메서드로 스케쥴러에서 사용자 관련 데이터를 삭제하도록 변경했습니다.

특이 사항

UserRemovalScheduler 에 의하면 탈퇴 후 30일이 지나면 DB에서 Hard Delete가 이루어집니다.

public void scheduledUserRemoval() {
	LocalDate cutoffDate = LocalDate.now().minusDays(ACCOUNT_RECOVER_DURATION);
	List<SiteUser> usersToRemove = siteUserRepository.findUsersToBeRemoved(cutoffDate);
	siteUserRepository.deleteAll(usersToRemove);
}

이전에 불필요한 연관 관계를 끊고 간접 참조로 리팩터링을 진행한 바 있습니다. 이전에는 JPA의 cascade 옵션으로 연관 객체들 또한 잘 삭제되었으나, 연관 관계를 끊은 현재는 SiteUser 을 삭제하기 전, 연관 레코드를 먼저 삭제해야 합니다.

interestedCountryRepository.deleteAllBySiteUserIdIn(userIdsToRemove);

다만, SiteUser 와 간접적으로 관계를 맺는 객체가 정말 많기에, 위처럼 직접 연관된 레코드를 삭제하는 경우 코드가 길어지게 됩니다. SiteUser 를 참조하는 새로운 엔티티를 생성하는 경우 스케쥴러에서 삭제하는 로직 또한 작성해주어야 하는데, 실수할 여지가 있다고 생각했습니다.

리뷰 요구사항 (선택)

  1. 빠뜨린 부분이 있는지 확인 부탁드립니다 !
  2. 현재는 모든 사용자 삭제가 하나의 트랜잭션으로 묶어 처리되는데(== 한 명 삭제 실패하면 모두 롤백), 별도의 서비스로 분리할지, 유지할지

@whqtker whqtker self-assigned this Nov 20, 2025
@whqtker whqtker added the 버그 Something isn't working label Nov 20, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Walkthrough

1. 저장소 메서드 추가: 여러 Repository 인터페이스에 deleteAllBySiteUserId(...) 및 유사한 파생 삭제 메서드들이 일괄적으로 추가되었습니다.
2. 채팅 관련 확장: ChatParticipantRepository에 ID 조회 메서드와 deleteAllBySiteUserId(...)가, ChatReadStatusRepository에 컬렉션 기반 삭제 메서드가 추가되었습니다.
3. 차단·신고 연관 삭제: UserBlockRepositoryReportRepository 등에서 식별자 기반 대량 삭제 메서드가 도입되었습니다.
4. 성적·점수 도메인 변경: GpaScoreRepository, LanguageTestScoreRepository 등 점수 저장소에 siteUserId 기반 삭제 메서드가 추가되었습니다.
5. 대학·뉴스·멘토링 등 확장: News, LikedUnivApplyInfo, Mentor, MentorApplication, Mentoring 등 여러 도메인 저장소에 일괄 삭제 메서드가 추가되었습니다.
6. 스케줄러 재구성: UserRemovalScheduler가 전체 일괄 삭제 호출을 제거하고 사용자별 트랜잭션 내 순차 삭제(관련 엔티티 및 S3 프로필 제거 포함)로 대체되었습니다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • wibaek
  • JAEHEE25
  • lsy1307
  • Gyuhyeok99

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경 사항의 핵심을 명확하게 설명하고 있습니다. '탈퇴한 사용자가 물리적 삭제가 되지 않았던 문제를 해결한다'는 해결 대상 버그와 솔루션을 잘 나타냅니다.
Description check ✅ Passed PR 설명이 필수 섹션(관련 이슈, 작업 내용, 특이 사항)을 포함하고 있으며, 변경 배경과 의도가 명확합니다. 다만 리뷰 요구사항의 일부 질문에는 명확한 답변이 누락되어 있습니다.
Linked Issues check ✅ Passed PR이 #556 이슈의 모든 핵심 목표를 달성하고 있습니다. 16개 repository에 deleteAllByXXX 메서드를 추가하고, UserRemovalScheduler에서 연관 레코드 삭제를 구현하여 SiteUser의 Hard Delete 문제를 해결했습니다.
Out of Scope Changes check ✅ Passed 모든 변경 사항이 #556 이슈의 범위 내에 있습니다. 추가된 메서드들은 모두 사용자 탈퇴 시 연관 데이터 삭제를 위한 것이며, UserRemovalScheduler의 수정도 동일한 목적입니다.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f5c555 and bf1a6db.

📒 Files selected for processing (1)
  • src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java
⏰ 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

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.

@whqtker whqtker changed the title refactor: FK에 ON DELETE CASCADE 옵션 추가 refactor: 탈퇴한 사용자가 물리적 삭제가 되지 않았던 문제를 해결한다 Nov 20, 2025
@whqtker whqtker changed the title refactor: 탈퇴한 사용자가 물리적 삭제가 되지 않았던 문제를 해결한다 fix: 탈퇴한 사용자가 물리적 삭제가 되지 않았던 문제를 해결한다 Nov 20, 2025
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: 0

🧹 Nitpick comments (3)
src/main/resources/db/migration/V38__add_delete_cascade_option_on_fk.sql (3)

1-89: 마이그레이션 접근법은 명확하지만, 적용 범위와 롤백 전략 확인 필요합니다.

전반적으로 마이그레이션 구조는 건전합니다. site_user 테이블 삭제 시 관련 레코드를 연쇄적으로 삭제하는 방식으로 하드 딜리트 문제를 해결하는 것이 PR 목표와 일치합니다. 다음 몇 가지를 확인해 주세요:

  1. 외래 키 적용 범위 검증
    현재 마이그레이션이 site_user를 참조하는 모든 FK를 다루고 있는지 확인이 필요합니다. 마이그레이션 후 누락된 FK가 있으면 일부 연관 레코드가 여전히 삭제되지 않을 수 있습니다.

  2. 롤백 전략 부재
    역방향 마이그레이션(undo 스크립트)이 없으면 문제 발생 시 이전 상태로 복구하기 어렵습니다. Flyway는 일반적으로 단방향이지만, 이 구조적 변경에 대해 롤백 전략이 있는지 확인해 주세요.

  3. 프로덕션 배포 시 고려 사항
    DDL 작업은 영향을 받는 테이블을 잠금합니다. 특히 post, comment 같은 대형 테이블의 경우 마이그레이션 시간을 확인하고 적절한 점검 시간에 배포하세요.


1-89: 제약 조건 네이밍 컨벤션이 거의 일관성 있으나, 소수 불규칙성 정리 권장합니다.

대부분의 새 제약 조건 이름이 fk_[테이블]_[칼럼] 패턴을 따르고 있어 좋습니다. 단, 아래 두 가지 예외가 있습니다:

  1. Line 33-34 (fk_app_site_user): 테이블 약자와 칼럼명 생략 패턴으로 다른 네이밍과 톤이 다릅니다.
  2. Line 88-89 (fk_mentor_application_site_user): 다른 제약과 달리 _id 접미사가 없습니다.

장기 유지보수 관점에서 모든 FK 제약을 fk_[테이블]_[칼럼] 형식(예: fk_app_site_user_id, fk_mentor_application_site_user_id)으로 정렬하면 일관성이 높아집니다.


1-89: ON DELETE CASCADE 적용 시 의도하지 않은 연쇄 삭제 리스크를 모니터링하세요.

이 마이그레이션 후 site_user 레코드 삭제 시 위 18개 FK를 통해 관련된 모든 하위 레코드가 자동으로 삭제됩니다. 이는 의도된 동작이지만, 배포 후 몇 가지를 관찰해야 합니다:

  1. 의도하지 않은 데이터 손실 - 비즈니스 로직상 보존해야 할 데이터가 연쇄 삭제로 인해 손실되지 않는지 확인
  2. 애플리케이션 코드 정리 - PR 배경에 언급된 대로 UserRemovalScheduler의 연관 레코드 삭제 코드(siteUserRepository.deleteAll 전 개별 삭제 로직)가 이제 불필요할 가능성이 있으니 정리 검토 권장
  3. 데이터베이스 트리거/프로시저 - 기존에 수동으로 처리하던 삭제 로직이 있다면 중복 처리로 인한 오류를 피하도록 검토
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4da854b and 46df0f3.

📒 Files selected for processing (1)
  • src/main/resources/db/migration/V38__add_delete_cascade_option_on_fk.sql (1 hunks)
🔇 Additional comments (1)
src/main/resources/db/migration/V38__add_delete_cascade_option_on_fk.sql (1)

46-46: 일부 제약 조건에서 이미 같은 이름으로 존재하는 FK를 삭제 후 재생성하고 있습니다.

Line 46, 51, 56, 61, 71, 76, 81, 86에서 기존 제약 조건과 동일한 이름으로 FK를 재생성하고 있습니다. 이는 현재 스키마에서 이 제약들이 이미 사람이 정의한 이름으로 존재한다는 의미입니다.

확인 사항:

  • 이 제약 조건들이 정말로 같은 이름을 유지하는 것이 의도인지, 아니면 버전 관리 과정에서 일부는 이미 수정된 것인지 검증해 주세요.
  • 특히 application 테이블(Line 31)의 경우 이미 fk_app_site_user 이름으로 존재하는 것으로 보아, 이전 마이그레이션에서 수동으로 명명한 제약으로 추정됩니다.

Also applies to: 51-51, 56-56, 61-61, 71-71, 76-76, 81-81, 86-86

Copy link
Contributor

@Hexeong Hexeong left a comment

Choose a reason for hiding this comment

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

수고하십니다~ FK ID 관련하여 질문 있어서 comment 남겨뒀습니다~

@@ -0,0 +1,89 @@
ALTER TABLE interested_country DROP FOREIGN KEY FK26u5am55jefclcd7r5smk8ai7;
ALTER TABLE interested_country
Copy link
Contributor

Choose a reason for hiding this comment

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

FK ID가 로컬에서와 인스턴스에서가 다를 것 같은데, 하드 코딩된 이유가 따로 있을까요??

Copy link
Member Author

Choose a reason for hiding this comment

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

flyway가 stage, prod 환경에서만 동작하고, 확인한 결과 두 환경 모두 FK가 같아서 단순 하드 코딩했습니다

Copy link
Contributor

@sukangpunch sukangpunch left a comment

Choose a reason for hiding this comment

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

잘 작성해주신 것 같습니다!!
근데 고민이 하나 있는데, 엔티티 클래스 에서 jpa 연관관계를 다 끊어 놓은 상황에서 db 에서 casecade 구현하는게 괜찮을까? 라는 생각이 들었습니다.
제가 까먹어서 그런데, 연관관계 매핑을 끊었던 이유를 혹시 알고 계신가요? 들었던것 같은데 기억이 안나네요...

@Gyuhyeok99
Copy link
Contributor

음 이러면 코드와 디비간의 불일치가 발생할 거 같긴한데 문제는 없어보이네요!

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: 14

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46df0f3 and d17592f.

📒 Files selected for processing (16)
  • src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java
  • src/main/java/com/example/solidconnection/chat/repository/ChatParticipantRepository.java
  • src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java
  • src/main/java/com/example/solidconnection/community/post/repository/PostLikeRepository.java
  • src/main/java/com/example/solidconnection/community/post/repository/PostRepository.java
  • src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java
  • src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java
  • src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java
  • src/main/java/com/example/solidconnection/news/repository/LikedNewsRepository.java
  • src/main/java/com/example/solidconnection/news/repository/NewsRepository.java
  • src/main/java/com/example/solidconnection/report/repository/ReportRepository.java
  • src/main/java/com/example/solidconnection/scheduler/UserRemovalScheduler.java
  • src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java
  • src/main/java/com/example/solidconnection/score/repository/LanguageTestScoreRepository.java
  • src/main/java/com/example/solidconnection/siteuser/repository/UserBlockRepository.java
  • src/main/java/com/example/solidconnection/university/repository/LikedUnivApplyInfoRepository.java
🔇 Additional comments (7)
src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java (1)

45-46: 메서드 추가 확인 완료

deleteAllBySiteUserId 메서드가 올바르게 추가되었습니다. Spring Data JPA의 메서드 네이밍 규칙을 따르고 있어 Comment 엔티티에서 siteUserId 필드를 기준으로 삭제 쿼리가 자동 생성됩니다.

src/main/java/com/example/solidconnection/score/repository/LanguageTestScoreRepository.java (1)

17-18: 메서드 추가 확인 완료

deleteAllBySiteUserId 메서드가 다른 Repository들과 일관된 패턴으로 추가되었습니다.

src/main/java/com/example/solidconnection/report/repository/ReportRepository.java (1)

10-11: 메서드 추가 확인 완료

deleteAllByReporterId 메서드가 Report 도메인에 맞게 올바르게 추가되었습니다.

src/main/java/com/example/solidconnection/chat/repository/ChatParticipantRepository.java (1)

12-13: 메서드 추가 확인 완료

deleteAllBySiteUserId 메서드가 올바르게 추가되었습니다.

src/main/java/com/example/solidconnection/community/post/repository/PostLikeRepository.java (1)

19-20: 메서드 추가 확인 완료

deleteAllBySiteUserId 메서드가 올바르게 추가되었습니다.

src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java (1)

42-43: 메서드 추가 확인 완료

deleteAllByMenteeId 메서드가 Mentoring 도메인에 맞게 올바르게 추가되었습니다.

src/main/java/com/example/solidconnection/siteuser/repository/UserBlockRepository.java (1)

27-28: 메서드 추가 확인 완료

deleteAllByBlockerIdOrBlockedId 메서드가 올바르게 추가되었습니다. 사용자가 차단한 경우와 차단당한 경우 모두를 처리하기 위해 OR 조건을 사용한 것이 적절합니다.

Comment on lines 60 to +69
@Scheduled(cron = EVERY_MIDNIGHT)
@Transactional
public void scheduledUserRemoval() {
LocalDate cutoffDate = LocalDate.now().minusDays(ACCOUNT_RECOVER_DURATION);
List<SiteUser> usersToRemove = siteUserRepository.findUsersToBeRemoved(cutoffDate);
siteUserRepository.deleteAll(usersToRemove);

usersToRemove.forEach(this::deleteUserAndRelatedData);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

2. 트랜잭션 경계 문제

@Transactional 애노테이션이 scheduledUserRemoval 메서드에 추가되어 모든 사용자 삭제가 하나의 트랜잭션으로 처리됩니다. 이는 심각한 문제를 초래할 수 있습니다:

  1. 대량 데이터 처리 시 트랜잭션 타임아웃: 삭제할 사용자가 많을 경우 트랜잭션이 너무 길어져 타임아웃이 발생할 수 있습니다.
  2. 부분 실패 시 전체 롤백: 100명 중 99번째 사용자 삭제 중 오류가 발생하면 앞의 98명도 모두 롤백됩니다.
  3. 테이블 락 장기 점유: 긴 트랜잭션으로 인해 다른 작업들이 대기하게 됩니다.
🔎 개별 사용자별 트랜잭션 처리로 개선
  @Scheduled(cron = EVERY_MIDNIGHT)
- @Transactional
  public void scheduledUserRemoval() {
      LocalDate cutoffDate = LocalDate.now().minusDays(ACCOUNT_RECOVER_DURATION);
      List<SiteUser> usersToRemove = siteUserRepository.findUsersToBeRemoved(cutoffDate);
      usersToRemove.forEach(this::deleteUserAndRelatedData);
  }

+ @Transactional
  private void deleteUserAndRelatedData(SiteUser user) {
+     try {
          long siteUserId = user.getId();
          
          likedNewsRepository.deleteAllBySiteUserId(siteUserId);
          // ... 나머지 삭제 로직
          
          siteUserRepository.delete(user);
+     } catch (Exception e) {
+         log.error("Failed to delete user and related data for userId: {}", user.getId(), e);
+         // 개별 사용자 삭제 실패 시에도 다음 사용자 처리 계속
+     }
  }

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

🤖 Prompt for AI Agents
In src/main/java/com/example/solidconnection/scheduler/UserRemovalScheduler.java
around lines 60 to 67, the @Transactional on scheduledUserRemoval makes the
entire batch run in one transaction; remove the @Transactional from this method,
ensure each deletion runs in its own transaction (e.g., annotate
deleteUserAndRelatedData with @Transactional(propagation =
Propagation.REQUIRES_NEW) or execute each delete via TransactionTemplate), and
wrap each per-user delete call in a try/catch to log failures and continue so a
single failure does not roll back or stop the whole job.

interestedCountryRepository.deleteAllBySiteUserId(siteUserId);
interestedRegionRepository.deleteAllBySiteUserId(siteUserId);

s3Service.deleteExProfile(siteUserId);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

4. S3 삭제 실패 처리

Line 94에서 S3 프로필 삭제 중 오류가 발생하면 현재 트랜잭션이 롤백되어 DB 삭제도 취소됩니다. S3 삭제는 외부 서비스 호출이므로:

  1. 네트워크 오류 가능성: S3 서비스가 일시적으로 불안정하면 전체 사용자 삭제가 실패합니다.
  2. 트랜잭션 일관성 문제: S3는 트랜잭션에 참여하지 않으므로, 롤백 시에도 S3에서는 파일이 삭제된 상태로 남을 수 있습니다.
🔎 S3 삭제 오류 격리 처리
+ try {
      s3Service.deleteExProfile(siteUserId);
+ } catch (Exception e) {
+     log.warn("Failed to delete S3 profile for userId: {}, continuing with user deletion", siteUserId, e);
+     // S3 삭제 실패해도 사용자 삭제는 진행
+ }
  
  siteUserRepository.delete(user);

또는 S3 삭제를 별도의 보상 트랜잭션으로 처리하는 방안을 고려하세요.

📝 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
s3Service.deleteExProfile(siteUserId);
try {
s3Service.deleteExProfile(siteUserId);
} catch (Exception e) {
log.warn("Failed to delete S3 profile for userId: {}, continuing with user deletion", siteUserId, e);
// S3 삭제 실패해도 사용자 삭제는 진행
}
🤖 Prompt for AI Agents
In src/main/java/com/example/solidconnection/scheduler/UserRemovalScheduler.java
around line 94, calling s3Service.deleteExProfile(siteUserId) directly can cause
DB transaction rollback when S3 fails; change to perform S3 deletion outside the
DB transaction (e.g., register an after-commit action via
TransactionSynchronizationManager or publish a transactional
event/@TransactionalEventListener that runs after commit), wrap the S3 call in
retry logic and exception handling so failures do not throw into the DB
transaction, log detailed errors, and if deletion still fails enqueue a
compensating job or mark the user record with a flag for async cleanup to ensure
idempotent retry and eventual consistency.

@whqtker whqtker force-pushed the fix/delete-siteuser-correctly branch from d17592f to 07b7851 Compare December 29, 2025 10:40
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 (8)
src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java (1)

17-17: 구현이 올바릅니다.

Derived delete 메서드는 별도 애노테이션 없이 정상 동작합니다. 과거 리뷰 코멘트는 부정확한 정보였습니다.

src/main/java/com/example/solidconnection/news/repository/NewsRepository.java (1)

12-12: 정상적으로 동작합니다.

src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java (1)

44-44: 구현이 올바릅니다.

src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java (1)

46-46: 정상적으로 동작합니다.

src/main/java/com/example/solidconnection/scheduler/UserRemovalScheduler.java (3)

60-67: 트랜잭션 경계 설정으로 인한 심각한 위험이 있습니다.

@Transactional 애노테이션이 scheduledUserRemoval 메서드에 적용되어 있어, 모든 사용자 삭제 작업이 하나의 거대한 트랜잭션으로 처리됩니다. 이는 다음과 같은 심각한 문제를 초래할 수 있습니다:

  1. 대량 데이터 처리 시 트랜잭션 타임아웃: 삭제 대상 사용자가 많을 경우 트랜잭션 지속 시간이 너무 길어져 타임아웃 발생 가능
  2. 부분 실패 시 전체 롤백: 100명 중 99번째 사용자 삭제 중 오류 발생 시 앞의 98명도 모두 롤백됨
  3. 테이블 락 장기 점유: 긴 트랜잭션으로 인해 다른 작업들이 블로킹될 수 있음
🔎 개별 사용자별 트랜잭션으로 개선하는 방법
  @Scheduled(cron = EVERY_MIDNIGHT)
- @Transactional
  public void scheduledUserRemoval() {
      LocalDate cutoffDate = LocalDate.now().minusDays(ACCOUNT_RECOVER_DURATION);
      List<SiteUser> usersToRemove = siteUserRepository.findUsersToBeRemoved(cutoffDate);
      
      usersToRemove.forEach(this::deleteUserAndRelatedData);
  }

+ @Transactional
  private void deleteUserAndRelatedData(SiteUser user) {
+     try {
          long siteUserId = user.getId();
          
          // ... 기존 삭제 로직 ...
          
          siteUserRepository.delete(user);
+     } catch (Exception e) {
+         log.error("Failed to delete user and related data for userId: {}", user.getId(), e);
+         // 개별 사용자 삭제 실패 시에도 다음 사용자 처리 계속
+     }
  }

이렇게 변경하면:

  • 각 사용자별로 독립적인 트랜잭션 실행
  • 한 사용자 삭제 실패가 다른 사용자에게 영향 없음
  • 트랜잭션 타임아웃 위험 최소화

94-94: S3 삭제 실패 시 DB 트랜잭션 롤백으로 인한 데이터 불일치 위험이 있습니다.

Line 94에서 S3 프로필 삭제를 트랜잭션 내부에서 수행하고 있습니다. 이는 다음과 같은 문제를 야기합니다:

  1. 네트워크 오류 시 전체 사용자 삭제 실패: S3 서비스가 일시적으로 불안정하면 DB 삭제도 롤백됨
  2. 데이터 불일치 가능성: S3는 트랜잭션에 참여하지 않으므로, 롤백 시에도 S3에서는 파일이 이미 삭제된 상태로 남을 수 있음
🔎 S3 삭제 오류 격리 처리 방법

방법 1: S3 삭제 실패를 격리하여 DB 삭제는 진행

+ try {
      s3Service.deleteExProfile(siteUserId);
+ } catch (Exception e) {
+     log.warn("Failed to delete S3 profile for userId: {}, continuing with user deletion", siteUserId, e);
+     // S3 삭제 실패해도 사용자 DB 삭제는 진행
+ }
  
  siteUserRepository.delete(user);

방법 2: S3 삭제를 트랜잭션 커밋 후에 실행 (권장)

- s3Service.deleteExProfile(siteUserId);
- 
  siteUserRepository.delete(user);
+ 
+ // 트랜잭션 커밋 후 S3 삭제 (TransactionSynchronizationManager 활용)
+ TransactionSynchronizationManager.registerSynchronization(
+     new TransactionSynchronization() {
+         @Override
+         public void afterCommit() {
+             try {
+                 s3Service.deleteExProfile(siteUserId);
+             } catch (Exception e) {
+                 log.error("Failed to delete S3 profile after user deletion for userId: {}", siteUserId, e);
+                 // 보상 트랜잭션 큐에 등록하거나 재시도 로직 구현
+             }
+         }
+     }
+ );

방법 2를 사용하면 DB 삭제가 안전하게 커밋된 후에 S3 삭제를 시도하므로, S3 실패가 DB 트랜잭션에 영향을 주지 않습니다.


69-97: ChatReadStatus 엔티티 삭제가 누락되어 고아 레코드가 남습니다.

Line 83에서 chatParticipantRepository.deleteAllBySiteUserId(siteUserId)로 ChatParticipant를 삭제하지만, ChatReadStatus 엔티티는 삭제하지 않고 있습니다.

ChatReadStatus는 chatParticipantId를 참조하고 있으며 cascade 설정이 없어 ChatParticipant 삭제 시 자동으로 제거되지 않습니다. 이로 인해 ChatReadStatus 레코드가 고아(orphan) 상태로 데이터베이스에 남게 됩니다.

🔎 ChatReadStatus 삭제 추가 방법

Line 83 앞에 ChatReadStatus 삭제 로직을 추가하세요:

+ // ChatParticipant 삭제 전에 먼저 ChatReadStatus를 삭제해야 함
+ List<ChatParticipant> participants = chatParticipantRepository.findAllBySiteUserId(siteUserId);
+ List<Long> participantIds = participants.stream()
+         .map(ChatParticipant::getId)
+         .toList();
+ if (!participantIds.isEmpty()) {
+     chatReadStatusRepository.deleteAllByChatParticipantIdIn(participantIds);
+ }
  chatParticipantRepository.deleteAllBySiteUserId(siteUserId);

또는 ChatReadStatusRepository에 deleteAllByChatParticipantSiteUserId 메서드가 있다면:

+ chatReadStatusRepository.deleteAllByChatParticipantSiteUserId(siteUserId);
  chatParticipantRepository.deleteAllBySiteUserId(siteUserId);

참고: ChatReadStatusRepository를 의존성으로 주입받아야 합니다.

src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java (1)

31-31: 필수 애노테이션 @Modifying이 누락되어 런타임 오류가 발생합니다.

Spring Data JPA의 파생 삭제 쿼리 메서드는 반드시 @Modifying 애노테이션이 필요합니다. 이 애노테이션 없이 실행하면 InvalidDataAccessApiUsageException이 발생합니다.

🔎 수정 제안
+    @Modifying
     void deleteAllBySiteUserId(long siteUserId);

파일 상단에 import 추가:

import org.springframework.data.jpa.repository.Modifying;

참고: 호출하는 측(UserRemovalScheduler)에서 이미 @Transactional 컨텍스트를 제공하고 있으므로, 이 메서드에는 @Transactional을 추가하지 않아도 됩니다.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d17592f and 07b7851.

📒 Files selected for processing (16)
  • src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java
  • src/main/java/com/example/solidconnection/chat/repository/ChatParticipantRepository.java
  • src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java
  • src/main/java/com/example/solidconnection/community/post/repository/PostLikeRepository.java
  • src/main/java/com/example/solidconnection/community/post/repository/PostRepository.java
  • src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java
  • src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java
  • src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java
  • src/main/java/com/example/solidconnection/news/repository/LikedNewsRepository.java
  • src/main/java/com/example/solidconnection/news/repository/NewsRepository.java
  • src/main/java/com/example/solidconnection/report/repository/ReportRepository.java
  • src/main/java/com/example/solidconnection/scheduler/UserRemovalScheduler.java
  • src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java
  • src/main/java/com/example/solidconnection/score/repository/LanguageTestScoreRepository.java
  • src/main/java/com/example/solidconnection/siteuser/repository/UserBlockRepository.java
  • src/main/java/com/example/solidconnection/university/repository/LikedUnivApplyInfoRepository.java
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/main/java/com/example/solidconnection/siteuser/repository/UserBlockRepository.java
  • src/main/java/com/example/solidconnection/report/repository/ReportRepository.java
  • src/main/java/com/example/solidconnection/community/post/repository/PostLikeRepository.java
  • src/main/java/com/example/solidconnection/university/repository/LikedUnivApplyInfoRepository.java
  • src/main/java/com/example/solidconnection/score/repository/LanguageTestScoreRepository.java
🔇 Additional comments (5)
src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java (1)

43-43: 메서드 구현이 적절합니다.

deleteAllByMenteeId는 멘티가 탈퇴할 때 해당 멘티와 관련된 멘토링 관계를 정리하는 데 적합합니다. Spring Data JPA가 자동으로 트랜잭션 내에서 처리하므로 정상 동작합니다.

src/main/java/com/example/solidconnection/community/post/repository/PostRepository.java (1)

63-63: 구현이 정확합니다.

이 파일의 다른 메서드들(decreaseLikeCount, increaseLikeCount 등)은 @Query를 사용하므로 @Modifying이 필요하지만, derived delete 메서드인 deleteAllBySiteUserId는 애노테이션 없이도 정상 작동합니다.

src/main/java/com/example/solidconnection/mentor/repository/MentorApplicationRepository.java (1)

12-12: 애플리케이션 레벨 삭제 방식이 적절합니다.

과거 리뷰에서 DB 레벨 ON DELETE CASCADE 미적용을 지적했으나, PR 목적에 따르면 의도적으로 애플리케이션 레벨에서 삭제를 처리하기로 결정되었습니다. 이는 다음과 같은 이유로 타당합니다:

  1. 명시적 제어: 삭제 순서와 로직을 코드에서 명확하게 관리할 수 있습니다.
  2. 유연성: 향후 삭제 전 로깅, 검증 등 추가 로직 삽입이 용이합니다.
  3. 추적성: 애플리케이션 로그에서 삭제 과정을 추적할 수 있습니다.

UserRemovalScheduler가 올바른 순서로 연관 레코드를 삭제하는지는 위 LikedNewsRepository 리뷰의 검증 스크립트를 통해 확인해주세요.

src/main/java/com/example/solidconnection/news/repository/LikedNewsRepository.java (1)

13-13: 파생 삭제 메서드는 정상 동작합니다.

Spring Data JPA의 파생 삭제 메서드(예: deleteAllBySiteUserId)는 다음과 같이 작동합니다:

  1. 자동 트랜잭션 처리: SimpleJpaRepository 구현체가 자동으로 트랜잭션을 관리합니다.
  2. 애노테이션 불필요: @Modifying@Transactional@Query를 사용한 커스텀 메서드에만 필수입니다.

현재 구현은 정상적입니다. UserRemovalScheduler@Transactional이 모든 삭제 작업을 감싸고 있으며, 삭제 순서도 올바르게 의존성을 처리하고 있습니다.

성능 고려사항이 있습니다:

파생 삭제 메서드는 내부적으로 SELECT 후 개별 DELETE를 수행합니다(N+1 패턴). 삭제 대상이 많지 않다면 문제없으나, 대량 삭제 시 최적화를 고려할 수 있습니다.

src/main/java/com/example/solidconnection/scheduler/UserRemovalScheduler.java (1)

3-28: 의존성 추가 및 애플리케이션 레벨 삭제 구조를 확인했습니다.

변경 사항:

  1. 사용자 관련 데이터를 삭제하기 위해 15개 이상의 Repository 의존성 추가
  2. @Transactional 애노테이션 추가로 스케줄링 메서드를 트랜잭션 컨텍스트에서 실행

애플리케이션 레벨에서 연관 레코드를 명시적으로 삭제하는 방식으로 JPA cascade 제거 이후 발생한 Hard Delete 문제를 해결하는 접근은 타당합니다. 다만, 아래 리뷰 코멘트에서 지적하는 트랜잭션 경계 및 누락된 삭제 로직 문제를 반드시 확인해 주세요.

@whqtker whqtker force-pushed the fix/delete-siteuser-correctly branch from 07b7851 to 2f5c555 Compare December 29, 2025 11:06
Copy link
Contributor

@Hexeong Hexeong left a comment

Choose a reason for hiding this comment

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

확인했습니다~ 고생많으셨어용

@whqtker whqtker merged commit 48d0f48 into solid-connection:develop Jan 12, 2026
2 checks passed
whqtker added a commit that referenced this pull request Jan 19, 2026
* fix: yml 들여쓰기 수정 (#555)

* fix: yml 들여쓰기 수정

* fix: jdk 변경

* refactor: 멘토 및 채팅 관련 API 응답 수정 (#537)

* refactor: 멘토의 멘토링 조회 응답에서 mentoringId가 아니라 roomId를 포함하도록

* refactor: 파트너가 멘토인 경우 partnerId는 mentorId로

- AS IS: 멘토/멘티 모두 partnerId가 siteUserId
- TO BE: 멘티: siteUserId, 멘토: mentorId

* refactor: 응답의 senderId가 mentorId/siteUserId가 되도록

* refactor: senderId에 해당하는 chatParticipant가 없을 경우 예외 처리하는 로직 추가

* refactor: 메서드명에 맞게 시그니처 변경

* refactor: getChatMessages 메서드에서 응답으로 siteUserId를 넘겨주도록

- AS IS: mentorId(mentor) / siteUserId(mentee)
- TO BE: siteUserId(all)

* refactor: 헬퍼 메서드로 메서드 복잡성을 분산한다

* refactor: getChatPartner 메서드의 응답으로 siteUserId를 넘겨주도록

- AS IS: mentorId(mentor) / siteUserId(mentee)
- TO BE: siteUserId(all)

* refactor: CD 성능 개선 (#552)

* fix: deprecated된 base image를 eclipse-temurin:17-jdk로 변경

* refactor: scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 변경

* fix: GHCR image 제거시 Org의 GITHUB_TOKEN 사용하도록 변경

* refactor : scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 prod-cd.yml과 docker-compose.prod.yml 변경

* fix: prod 인스턴스 old image 이름 통일

* fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정

* fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정

* fix: dev-cd.yml Old images 정리 작업 중 이미지 이름 불일치 문제 해결

* chore: 마지막 줄 개행 추가

* chore: 마지막 줄 개행 추가

* feat: stage 인스턴스에 대한 최신 이미지 5개 유지 기능 및 old 이미지 제거 기능 추가

* chore: 중복된 환경변수 지정 제거

* chore: 중복된 pem키 생성 로직 제거

* fix: 잘못된 pem키 이름 수정

* refactor: 원격 호스트에서 pull할 경우, 최소 권한으로 실행하도록 Github App으로 임시토큰 발급하도록 수정

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 (#565)

* fix: GitHub app token permission 문제 해결 (#566)

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가

* fix: GitHub app token permission 문제 오류 해결 (#567)

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* fix: GitHub app token permission이 repo 레벨에서 부여되는 문제 해결 (#568)

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* fix: GitHub app token permission 권한 오류 해결 (#569)

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* test: fork repo의 작업 branch에서 해당 workflows가 실행되도록 임시 수정

* refactor: test용 설정 제거

* feat: claude.md 파일 추가 (#560)

* fix : 동일 멘토 멘티 중복 신청 불가능하도록 수정 (#563)

* fix : 동일 멘토 멘티 중복 신청 불가능하도록 수정
- UK 제약조건 추가
- flyway script 추가
- CustomException 추가
- Service 로직 수정
- Test code 추가

* fix : column명 오류 수정
- column명 camelCase -> snake_case로 변경

* fix : column명 오류 수정
- column명 name으로 명시

* fix: GitHub app token permission 권한 오류 해결 (#570)

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정

* fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가

* test: fork repo의 작업 branch에서 해당 workflows가 실행되도록 임시 수정

* refactor: test용 설정 제거

* fix: docker login username 불일치 문제

* refactor: 최소권한 원칙 적용을 위한 Action Job 분리

* refactor: 필요없는 주석 제거

* fix: GHCR 정리 권한 PAT로 해결 (#573)

* feat: 지원서가 APPROVED 인 유저의 멘토 생성 기능 추가 (#562)

* feat: 지원서가 APPROVED 인 유저의 멘토 생성 기능 추가

* refactor: submitMentorApplication 메서드의 멘토 지원 유효 검증 부분을 메서드로 추출

* refactor: MentorMyPage 생성, 수정 부분의 channel 생성, 업데이트 부분 중복 제거

* test: Mentor 생성 관련 테스트 추가

* fix: 코드래빗 리뷰 적용

* refactor: 멘토 생성 시 channelRequest가 null 일 떄 예외 처리

* feat: MentorApplicationRequest 필드에 유효성 어노테이션 추가

* test: 채널 검색 시 siteUserId로 조회하는 문제 해결

* fix: 리뷰 수정사항 적용

* fix: 파일 끝에 개행 추가

* refactor: 멘토 생성 메서드에서 siteUser의 검증 제외

* refactor: dto 단에서 채널 리스트 null 검증

* feat: MentorApplication에 termId 추가 flyway 스크립트 추가

* fix: flyway 버전 충돌 해결

* feat: 어드민 멘토 승격 요청 페이징 조회 기능 추가 (#576)

* feat: 어드민 멘토 지원서 페이징 조회 기능 추가

* feat: mentor/repository 패키지에 custom 패키지 추가

- custom 패키지에 페이징 조회를 책임지는 MentorApplicationFilterRepository 추가

- MentorApplicationSearchCondition 에서 넘긴 keyword 기반으로 닉네임, 권역, 나라, 학교명으로 필터링 검색 기능 추가

- MentorApplicationSearchCondition 에서 넘긴 mentorApplicationStatus 기반으로 승인, 거절, 진행중 으로 필터링 기능 추가

* test: 어드민 멘토 지원서 페이징 조회 테스트 추가

* feat: MentorApplication 엔티티에 approved_at 필드 추가 flyway 스크립트 작성

* fix: 파일 끝에 개행 추가

* refactor: 페이징 조회 시 count 쿼리에 불필요한 조인 막기

* fix: 코드래빗 리뷰 적용

* fix: flyway V39 스크립트 파일명 수정

* test: 테스트 코드 오류 수정, 검증 추가  

* test: 기대하는 값이랑 다른 테스트 응답을 수정합니다

* feat: 어드민 멘토 승격 지원서 승인/거절 기능, 상태 별 지원서 개수 조회 기능 추가 (#577)

* feat: 어드민 멘토 승격 지원서 승인/거절 기능 추가

* test: 어드민 멘토 지원서 승인/거절 테스트 추가

* feat: 멘토 지원서 상태별 개수 조회 기능 추가

* test: 멘토 지원서 상태별 개수 조회 테스트 추가

* fix: 대학이 선택되지 않은 멘토 지원서 승인 시 예외 발생하도록 수정

* refactor: 리뷰 내용 반영

* refactor: MENTOR_APPLICATION_ALREADY_CONFIRM -> MENTOR_APPLICATION_ALREADY_CONFIRMED 로 수정

* refactor: 멘토 지원서 거절 사유 관련하여 기획에 명시되지 않은 길이 제한 제거

* refactor: 리뷰 적용

* refactor: 변수명, 필드명 일관성 맞추기

* test: assertAll 적용

* feat: region 관련 관리 기능 추가 (#561)

* feat: 지역 생성 기능 구현 (AdminRegion)

지역을 생성하는 기능을 구현했습니다:
- AdminRegionCreateRequest: 지역 생성 요청 DTO
- AdminRegionResponse: 지역 응답 DTO
- AdminRegionService.createRegion(): 중복 검사를 포함한 지역 생성 로직
- AdminRegionController.createRegion(): HTTP POST 엔드포인트

중복 검사:
- 지역 코드 중복 확인
- 한글명 중복 확인

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: 지역 수정/삭제/조회 기능 구현 및 테스트 추가 (AdminRegion)

지역 관리 기능을 완성했습니다:

구현 기능:
- AdminRegionUpdateRequest: 지역 수정 요청 DTO
- AdminRegionService.updateRegion(): 한글명 중복 검사를 포함한 지역 수정
- AdminRegionService.deleteRegion(): 지역 삭제
- AdminRegionService.getAllRegions(): 전체 지역 조회
- AdminRegionController: 수정/삭제/조회 HTTP 엔드포인트

테스트 코드 (AdminRegionServiceTest):
- CREATE: 정상 생성, 코드 중복, 한글명 중복 테스트
- UPDATE: 정상 수정, NOT_FOUND, 중복 한글명, 동일 한글명 테스트
- DELETE: 정상 삭제, NOT_FOUND 테스트
- READ: 빈 목록, 전체 조회 테스트

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: 지역 관리 관련 에러코드 추가 (ErrorCode)

지역 관리 기능에 필요한 에러코드를 추가했습니다:
- REGION_NOT_FOUND: 존재하지 않는 지역
- REGION_ALREADY_EXISTS: 이미 존재하는 지역

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: jpa 오류 수정

* refactor: 코드리뷰 반영

---------

Co-authored-by: Claude <noreply@anthropic.com>

* fix: config.alloy 파일 경로 불일치 문제 해결 (#586)

* fix: config.alloy 파일 경로 불일치 문제 해결

* refactor: docker-compose를 수정하는게 아닌 cd.yml의 경로를 수정하여 해결

* feat: 소셜 로그인 사용자는 비밀번호 변경을 할 수 없다. (#582)

* feat: 소셜 로그인 사용자는 비밀번호 변경을 할 수 없도록

* test: 소셜 로그인 사용자 비밀번호 변경 관련 테스트 코드 작성

* chore: 컨벤션에 맞게 메서드명 변경

- ~~ 예외가 발생한다

* chore: 충돌 해결

* fix: Upgrade 헤더 유무에 따라 Connection 헤더의 값을 동적으로 설정하도록 (#581)

* fix: Upgrade 헤더 유무에 따라 Connection 헤더의 값을 동적으로 설정하도록

- Upgrade 헤더가 존재하면(e.g. WebSocket) upgrade로 설정
- Upgrade 헤더가 존재하지 않으면 keep-alive로 설정

* chore: 서브모듈 업데이트

* feat: 멘토 지원서 대학교 매핑 기능, 대학 선택 상태 페이징 조건 추가 (#583)

* feat: 멘토 지원서 검색 조건에 UniversitySelectType 추가

* feat: 어드민 멘토 지원서 페이징 조회 응답에 UniversitySelectType 추가

* test: 멘토 지원서 조회 테스트 추가

- test: UniversitySelectType 기반 페이징 조회 테스트 추가

* feat: 멘토 지원서에 대학 매핑 기능 추가

* test: 멘토 지원서 대학 매핑 테스트 추가

* refactor: 의미 없는 import 제거

* refactor: 리뷰 내용 반영

* refactor: 개행 및 공백 추가

* refactor: pathVariable 네이밍을 kebab-case 로 통일

* refactor: Service 레이어의 검증 로직을 도메인으로 이동

* refactor: PENDING 상태 및 OTHER 타입 검증을 도메인 메서드로 관리

* refactor: assignUniversity() 호출 전 검증 책임을 도메인 엔티티에 위임

* test : assertAll 로 검증 그룹화

* refactor: 스프링 부트 앱 외의 사이드 인프라 배포 과정을 분리 (#592)

* refactor: dev 환경에서의 side-infra 배포 과정 분리

* refactor: prod 환경에서의 side-infra 배포 과정 분리

* refactor: docker-compose 가 실행되고 있지 않아도 스크립트가 실패하지 않게 변경

* fix: docker compose up 시에 사용할 환경변수 중 누락된 변수를 추가

* fix: S3 이름 불일치 문제 해결 (#594)

* fix: s3 이름 불일치 문제 해결

* fix: s3와의 연동된 cloudfront URL로 수정

* refactor: 분리한 사이드 인프라에 대해서 필요없는 파일 정리 (#596)

* test: flyway 스크립트를 검증하는 테스트 코드 작성 (#588)

* test: flyway 스크립트를 검증하는 테스트 코드 작성

* fix: DirtiesContext 어노테이션을 통해 기존 컨텍스트를 폐기하도록

- 새로운 MySQL 환경에서 마이그레이션이 이루어지도록 수정

* fix: flyway 검증용의 별도의 MySQL 컨테이너를 사용하도록

* chore: 테스트 의도를 쉽게 이해할 수 있도록 주석 추가

* chore: 명시적으로 컨테이너를 시작하도록

- 또한 MySQLTestContainer 코드와 유사한 컨벤션을 가지도록 수정

* refactor: 게시글 조회 응답에 댓글 deprecated 여부 포함하도록 (#599)

* feat: 유저의 멘토 지원서 신청 이력 조회 기능 추가 (#603)

* feat: 유저의 멘토 지원 이력 조회 기능 추가

* refactor: 매개변수 타입 통일

* refactor: long 타입을 Long 으로 수정

* test: 멘토 지원서 이력 조회 테스트 추가

* test: MentorApplicationFixtureBuilder 에 rejectedReason 필드 및 빌더 메서드 추가

* refactor: 리뷰 사항 적용

* test: 멘토 지원서 이력 조회 에서 user와 university 재사용

* refactor: 긴 uri 를 짧게 수정

* refactor: 서브모듈 해시값 되돌리기

* refactor: 개행 지우기

* refactor: applicationOrder 자료형을 long 으로 수정

* fix: applicationOrder 를 int 자료형으로 처리하도록 복구

- 순서를 나타내고, 해당 값이 21억을 넘길 수 없다 판단하여 더 적합한 int 자료형으로 복구

* test: long type 을 기대하던 테스트 에러 해결

* fix: 탈퇴한 사용자가 물리적 삭제가 되지 않았던 문제를 해결한다 (#574)

* refactor: FK에 ON DELETE CASCADE 옵션 추가

* refactor: 삭제 메서드로 사용자 연관 데이터를 삭제하도록

* feat: 어드민 유저 차단 기능 추가 (#604)

* feat: 어드민 차단 기능

* test: 어드민 차단 기능

* feat: API 성능 로깅, 쿼리 별 메트릭 전송 추가 (#602)

* feat: HTTP 요청/응답 로깅 필터 구현

- traceId 기반 요청 추적
- 요청/응답 로깅
- CustomExceptionHandler와 중복 로깅 방지
- Actuator 엔드포인트 로깅 제외

* feat: ExceptionHandler에 중복 로깅 방지 플래그 및 userId 로깅 추가

* feat: API 수행시간 로깅 인터셉터 추가

* feat: ApiPerf 인터셉터, Logging 필터 빈 등록

* refactor: logback 설정 변경

- info, warn, error, api_perf 로 로그 파일 분리해서 관리

* feat: 쿼리 별 수행시간 메트릭 모니터링 추가

* feat: 데이터소스 프록시 의존성 및 config 파일 추가

* feat: 데이터 소스 프록시가 metric을 찍을 수 있도록 listener 클래스 추가

* feat: 요청 시 method, uri 정보를 listener에서 활용하기 위해 RequestContext 및 관련 interceptor 추가

* refactor: 비효율적인 Time 빌더 생성 개선

- Time.builder 를 사용하면 매번 빌더를 생성하여 비효율적인 문제를 meterRegistry.timer 방식으로 해결

* feat: 로깅을 위해 HttpServeletRequest 속성에 userId 추가

* refactor: logback 설정 중 local은 console만 찍도록 수정

* refactor: FILE_PATTERN -> LOG_PATTERN 으로 수정

* test: TokenAuthenticationFilter에서 request에 userId 설정 검증 추가

- principal 조회 예외를 막기 위해 siteUserDetailsService given 추가

* refacotr: 코드 래빗 리뷰사항 반영

* test: 중복되는 테스트 제거

* refactor: 사용하지 않는 필드 제거

* refactor: 리뷰 내용 반영

* refactor: ApiPerformanceInterceptor에서 uri 정규화 관련 코드 제거

* refactor: ApiPerformanceInterceptor에서 if-return 문을 if-else 문으로 수정

* refactor: 추가한 interceptor 의 설정에 actuator 경로 무시하도록 셋팅

* refactor: 중복되는 의존성 제거

* refactor: 로깅 시 민감한 쿼리 파라미터 마스킹

- EXCLUDE_QUERIES 에 해당하는 쿼리 파라미터 KEY 값의 VALUE 를 masking 값으로 치환

* refactor: 예외 처리 후에도 Response 로그 찍도록 수정

* refactor: CustomExceptionHandler 원상복구

- Response 로그를 통해 user를 추적할 수 있으므로 로그에 userId 를 추가하지 않습니다

* refactor: 리뷰 사항 반영

* refactor: RequestContext 빌더 제거

* refactor: RequestContextInterceptor import 수정

* refactor: logback yml 파일에서 timestamp 서버 시간과 동일한 규격으로 수정

* refactor: ApiPerformanceInterceptor 에서 동일 내용 로그 중복으로 찍는 문제 수정

* fix: decode를 두 번 하는 문제 수정

* test: 로깅 관련 filter, interceptor 테스트 추가

* refactor: 코드래빗 리뷰사항 반영

* test: contains 로 비교하던 검증 로직을 isEqualTo 로 수정

* test: preHandle 테스트 에서 result 값을 항상 검증

* refactor: 단위테스트에 TestContainer 어노테이션 제거

* fix: conflict 해결

* fix: docker-compose 충돌 해결 (#610)

* chore: release github action 임의 실행 추가

* refactor: 기본 추천 대학 후보 추가 (#161)

* fix: config.alloy 경로 수정

* hotfix: 모의지원 현황 어드민 권한 제거

* hotfix: import 제거

* chore: 서브모듈 해시 업데이트 (#611)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

버그 Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: 사용자 Hard Delete가 안 되는 문제를 해결한다.

4 participants