Skip to content

Comments

[FEAT] 유저 즉시 삭제 API 구현 (#365)#367

Merged
lingard1234 merged 7 commits intodevfrom
feat/365-deleteUserImme
Feb 10, 2026
Merged

[FEAT] 유저 즉시 삭제 API 구현 (#365)#367
lingard1234 merged 7 commits intodevfrom
feat/365-deleteUserImme

Conversation

@lingard1234
Copy link
Contributor

Summary

유저 삭제 시 연관된 모든 데이터를 즉시 삭제하는 API를 구현했습니다.

Changes

  • DELETE /api//me/delete-immediately 엔드포인트 추가
  • 특이사항 : 유저 삭제 시 연관 데이터 cascade 삭제 로직 구현
    • CampaignProposal (sender/receiver 모두)
    • 기타 유저 연관 엔티티
  • CampaignProposalRepository.deleteByUserId() 메서드 관련
    • @Query 사용하여 senderUserId, receiverUserId 모두 처리
  • 유저 삭제 서비스 로직 구현

Type of Change

  • Bug fix (기존 기능에 영향을 주지 않는 버그 수정)
  • New feature (기존 기능에 영향을 주지 않는 새로운 기능 추가)
  • Breaking change (기존 기능에 영향을 주는 수정)
  • Refactoring (기능 변경 없는 코드 개선)
  • Documentation (문서 수정)
  • Chore (빌드, 설정 등 기타 변경)
  • Release (develop → main 배포)

Related Issues

Closes #365

참고 사항

@lingard1234 lingard1234 self-assigned this Feb 10, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @lingard1234, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 사용자가 자신의 계정을 즉시 삭제할 수 있는 기능을 도입합니다. 이 기능은 사용자 계정뿐만 아니라 해당 사용자와 관련된 모든 데이터를 데이터베이스에서 물리적으로 제거하여 데이터 무결성을 유지하고 개인 정보 보호 요구사항을 충족하도록 설계되었습니다. 이를 통해 시스템에서 더 이상 필요 없는 사용자 데이터를 효율적으로 관리할 수 있습니다.

Highlights

  • 새로운 API 엔드포인트 추가: 사용자 및 연관 데이터를 즉시 삭제하는 DELETE /api//me/delete-immediately 엔드포인트를 추가했습니다.
  • 연관 데이터 즉시 삭제 로직 구현: 사용자 삭제 시 BrandLike, Brand, CampaignApply, CampaignLike, CampaignProposal, MatchBrandHistory, MatchCampaignHistory, NotificationSetting, TagUser, UserContentCategory, UserSignupPurpose, UserTerm, AuthenticationMethod 등 모든 연관된 데이터를 물리적으로 즉시 삭제하는 로직을 구현했습니다.
  • CampaignProposalRepository 최적화: CampaignProposalRepository@Modifying@Transactional 어노테이션과 JPQL 쿼리를 사용하여 senderUserIdreceiverUserId 모두를 처리하는 deleteByUserId 메서드를 추가하여 쿼리 최적화를 진행했습니다.
  • UserDeleteService 도입: 사용자 삭제와 관련된 복잡한 연관 데이터 삭제 로직을 캡슐화하고 관리하기 위해 UserDeleteService를 새로 도입했습니다.
Changelog
  • src/main/java/com/example/RealMatch/brand/domain/repository/BrandLikeRepository.java
    • 사용자 ID를 기반으로 BrandLike 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/brand/domain/repository/BrandRepository.java
    • 사용자 ID를 기반으로 Brand 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/business/domain/repository/CampaignApplyRepository.java
    • 사용자 ID를 기반으로 CampaignApply 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/business/domain/repository/CampaignProposalRepository.java
    • @Modifying@Transactional 어노테이션을 임포트했습니다.
    • 사용자 ID를 기반으로 보낸/받은 CampaignProposal 데이터를 모두 삭제하는 커스텀 JPQL 쿼리 메서드 deleteByUserId를 추가했습니다.
  • src/main/java/com/example/RealMatch/campaign/domain/repository/CampaignLikeRepository.java
    • 사용자 ID를 기반으로 CampaignLike 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/match/domain/repository/MatchBrandHistoryRepository.java
    • 사용자 ID를 기반으로 MatchBrandHistory 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/match/domain/repository/MatchCampaignHistoryRepository.java
    • 사용자 ID를 기반으로 MatchCampaignHistory 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/user/application/service/UserDeleteService.java
    • 사용자 및 연관 데이터를 즉시 삭제하는 로직을 포함하는 UserDeleteService 클래스를 새로 추가했습니다.
    • deleteUserImmediatelydeleteRelatedData 메서드를 구현하여 다양한 리포지토리를 통해 연관 데이터를 삭제하도록 했습니다.
  • src/main/java/com/example/RealMatch/user/domain/repository/AuthenticationMethodRepository.java
    • 사용자 ID를 기반으로 AuthenticationMethod 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/user/domain/repository/NotificationSettingRepository.java
    • 사용자 ID를 기반으로 NotificationSetting 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/user/domain/repository/UserContentCategoryRepository.java
    • 사용자 ID를 기반으로 UserContentCategory 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/user/domain/repository/UserTermRepository.java
    • 사용자 ID를 기반으로 UserTerm 데이터를 삭제하는 deleteByUserId 메서드를 추가했습니다.
  • src/main/java/com/example/RealMatch/user/presentation/controller/UserController.java
    • UserDeleteService를 주입했습니다.
    • DELETE /me/delete-immediately 엔드포인트를 추가하여 사용자 즉시 삭제 기능을 제공했습니다.
  • src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java
    • @DeleteMapping 어노테이션을 임포트했습니다.
    • 사용자 즉시 삭제 API에 대한 Swagger 문서 (@Operation, @ApiResponses)를 추가했습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

유저 즉시 삭제 API를 구현하는 PR입니다. 삭제 로직을 별도 서비스와 트랜잭션 메서드로 분리하여 데이터 일관성을 보장하려는 시도는 좋습니다. 다만, 몇 가지 개선점이 보입니다.

첫째, 브랜드를 소유한 유저의 데이터를 삭제하는 로직이 불완전하여, 해당 브랜드에 연결된 캠페인 등이 있는 경우 서버 오류가 발생할 수 있습니다. 이 부분을 더 안정적으로 처리해야 합니다.

둘째, 리포지토리 메서드에 불필요한 @Transactional 어노테이션이 사용되었습니다. 트랜잭션 관리는 서비스 계층에서 일관되게 처리하는 것이 좋습니다.

전반적으로 좋은 방향의 변경이지만, 기능의 안정성을 위해 지적된 이슈들을 수정하는 것을 권장합니다.

Comment on lines +54 to +68
private void deleteRelatedData(Long userId) {
tagUserRepository.deleteByUserId(userId);
userContentCategoryRepository.deleteByUserId(userId);
userSignupPurposeRepository.deleteByUserId(userId);
userTermRepository.deleteByUserId(userId);
notificationSettingRepository.deleteByUserId(userId);
matchBrandHistoryRepository.deleteByUserId(userId);
matchCampaignHistoryRepository.deleteByUserId(userId);
brandLikeRepository.deleteByUserId(userId);
campaignLikeRepository.deleteByUserId(userId);
campaignApplyRepository.deleteByUserId(userId);
campaignProposalRepository.deleteByUserId(userId);
brandRepository.deleteByUserId(userId);
authenticationMethodRepository.deleteByUserId(userId);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

현재 유저 관련 데이터 삭제 구현이 불완전합니다. 특히, 유저가 'Brand'의 소유주일 경우, 해당 브랜드에 'Campaign'과 같은 다른 엔티티가 연결되어 있다면 66라인의 brandRepository.deleteByUserId(userId) 호출 시 데이터베이스 제약 조건 위반으로 실패하게 됩니다. 이는 처리되지 않은 500 에러로 이어져 사용자 경험을 해칩니다.

Swagger 문서에 이 가능성을 언급하셨지만, 애플리케이션 레벨에서 이 경우를 더 안정적으로 처리하는 것이 바람직합니다. 브랜드에 종속된 데이터를 먼저 삭제하거나, 삭제가 불가능한 경우 명확한 에러 메시지(예: 409 Conflict)를 반환하여 유저가 상황을 인지할 수 있도록 해야 합니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

"이 API는 개발/테스트용 헬퍼로 실제 프로덕션에서는 사용되지 않습니다. 실제 서비스에서는 soft delete를 사용합니다."

Comment on lines 66 to 69
@Modifying
@Transactional
@Query("DELETE FROM CampaignProposal cp WHERE cp.senderUserId = :userId OR cp.receiverUserId = :userId")
void deleteByUserId(@Param("userId") Long userId);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

리포지토리 메서드에 있는 @Transactional 어노테이션은 중복되므로 제거하는 것이 좋습니다. 이 메서드를 호출하는 UserDeleteService.deleteUserImmediately 서비스 메서드에 이미 @Transactional이 선언되어 있어, 해당 트랜잭션에 자동으로 참여하게 됩니다.

트랜잭션 경계는 서비스 계층에서 관리하는 것으로 일관성을 유지하면 코드의 트랜잭션 동작을 더 명확하게 파악하고 관리할 수 있습니다.

Suggested change
@Modifying
@Transactional
@Query("DELETE FROM CampaignProposal cp WHERE cp.senderUserId = :userId OR cp.receiverUserId = :userId")
void deleteByUserId(@Param("userId") Long userId);
@Modifying
@Query("DELETE FROM CampaignProposal cp WHERE cp.senderUserId = :userId OR cp.receiverUserId = :userId")
void deleteByUserId(@Param("userId") Long userId);

@lingard1234 lingard1234 merged commit 00270a0 into dev Feb 10, 2026
1 check passed
@lingard1234 lingard1234 deleted the feat/365-deleteUserImme branch February 10, 2026 19:16
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.

[FEAT] 회원 즉시 탈퇴 API 구현

1 participant