feat: 회원 탈퇴 API#127
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 16 minutes and 18 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
Walkthrough사용자 계정 삭제 기능을 구현합니다. Soft delete 패턴을 적용하여 User 엔티티에 deletedAt 타임스탬프를 추가하고, 서비스와 API 레이어에 withdraw 메서드를 구현했습니다. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/kr/co/webee/domain/user/entity/User.java (1)
21-43:⚠️ Potential issue | 🟠 Major개인정보 보존 및 연관 엔티티 처리 정책을 정의해 주세요.
현재 soft delete는
deleted_at만 기록하고username,name,phoneNumber,password등 개인정보를 그대로 보존합니다. 국내 개인정보보호법(PIPA)/GDPR 관점에서 탈퇴 회원의 개인정보 즉시 파기 또는 익명화가 일반적으로 요구됩니다. 또한Post,Business,PostComment,ProductReview등User를 참조하는 엔티티는 cascade 설정이 없어, soft delete 후 다음 두 가지 중 하나의 문제를 일으킵니다.
@SQLRestriction때문에 연관 User가 조회 결과에서 사라져, 해당 글/리뷰 조회 시EntityNotFoundException또는 N+1 시 NPE 발생.- 자원에 대한 책임 주체(작성자)가 사라진 “고아” 레코드가 남아 비즈니스 로직이 모호해짐.
탈퇴 흐름에서 다음 정책을 명문화/구현해 주세요.
- 개인정보 즉시 익명화(예:
username = "withdrawn_" + id,phoneNumber/name = null,password무효화)- 연관 엔티티에 대한 정책 결정: cascade soft delete / 작성자 표시 변경(“탈퇴한 사용자”) / 보존 기간 후 일괄 파기 등
- 탈퇴 후 해당 사용자 토큰/세션 무효화(refresh 토큰 폐기 등)
🧹 Nitpick comments (3)
src/main/java/kr/co/webee/domain/user/entity/User.java (1)
43-43:deletedAt필드에@Column명시 권장.
@SQLDeleteSQL은deleted_at컬럼명을 가정하고 있는데, 매핑이 네이밍 전략(SpringPhysicalNamingStrategy등)에 암묵적으로 의존합니다. 전략이 바뀌거나 다른 환경에서 다른 네이밍 전략이 활성화되면 SQL과 실제 컬럼명이 어긋나 soft delete가 실패할 수 있습니다.♻️ 제안 변경
- private LocalDateTime deletedAt; + `@Column`(name = "deleted_at") + private LocalDateTime deletedAt;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/kr/co/webee/domain/user/entity/User.java` at line 43, The User entity's deletedAt field relies on implicit naming and `@SQLDelete` assumes the column is named deleted_at; add an explicit `@Column` mapping on the deletedAt field (e.g., `@Column`(name = "deleted_at")) in the User class to ensure the field maps to the expected DB column regardless of naming strategy so soft-delete SQL in `@SQLDelete` will target the correct column.src/main/java/kr/co/webee/application/user/service/UserService.java (1)
45-45: 예외 처리는 정상 작동 중이나, 코드베이스의 예외 패턴 일관성 검토 권장.현재
EntityNotFoundException은 글로벌 예외 핸들러에서ErrorType.ENTITY_NOT_FOUND로 매핑되어 HTTP 404로 올바르게 응답하고 있습니다. 다만 코드베이스에서 예외 처리 패턴이 혼재되어 있습니다:
UserService,ProductService등:EntityNotFoundException사용PostLikeService,PostCommentService등:BusinessException(ErrorType.POST_NOT_FOUND)사용일관성을 위해 두 패턴 중 하나로 통일하면 좋습니다. 참고로
USER_NOT_FOUND는ErrorType열거형에 정의되지 않았으므로,ENTITY_NOT_FOUND사용을 유지하거나 새로운 사용자 관련 에러 타입을 추가하는 방식으로 진행할 수 있습니다.uploadProfileImage도 동일한 패턴을 사용 중이므로 함께 정리하면 좋습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/kr/co/webee/application/user/service/UserService.java` at line 45, The codebase mixes EntityNotFoundException and BusinessException(ErrorType.*) patterns; pick one and make services consistent: either convert services using BusinessException (e.g., PostLikeService, PostCommentService) to throw EntityNotFoundException like UserService/ProductService and uploadProfileImage, or add a new ErrorType.USER_NOT_FOUND and refactor places using EntityNotFoundException to throw BusinessException(ErrorType.USER_NOT_FOUND) (update global handler if needed). Locate usages by searching for class/method names UserService, ProductService, PostLikeService, PostCommentService, uploadProfileImage and update all throw sites and tests to use the chosen pattern consistently, ensuring ErrorType enum and global exception mapper are updated accordingly.src/main/java/kr/co/webee/presentation/user/api/UserApi.java (1)
45-55: 응답 타입을 공통 래퍼로 통일하는 것을 권장합니다.프로젝트에
ApiResponse<T>공통 응답 래퍼가 있으므로,withdraw메서드를 통일해야 합니다. 현재String을 반환하고 컨트롤러에서"OK"를 직접 반환하는 방식은ApiResponseHandler에서 특수 처리(line 49-60)되고 있지만,uploadProfileImage는UserProfileImageUploadResponseDTO를 반환하는 등 동일 컨트롤러 내에서 응답 모델이 비대칭적입니다. 다음 중 하나로 통일하세요.
- 본문이 의미 있는 데이터가 없다면
void로 선언하고 HTTP204 No Content반환(@ResponseStatus(HttpStatus.NO_CONTENT)).ApiResponse<Void>형태로 통일 (기존 래퍼 활용).또한
@SQLRestriction("deleted_at IS NULL")이 적용되어 있어 이미 탈퇴한 사용자가 재호출 시EntityNotFoundException으로 404가 발생합니다. 클라이언트가 멱등성을 처리할 수 있도록 API 문서에 이 시나리오를 명시하세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/kr/co/webee/presentation/user/api/UserApi.java` around lines 45 - 55, The withdraw endpoint currently returns a raw String ("OK"), which breaks the project's ApiResponse<T> convention and causes asymmetric responses in UserApi (see withdraw and uploadProfileImage); change withdraw to use the common wrapper or no-content semantics: either return ApiResponse<Void> or declare void and add `@ResponseStatus`(HttpStatus.NO_CONTENT) so all controllers are consistent with ApiResponseHandler behavior, and update the method signature and any callers accordingly; also update the API docs for withdraw to state that requests for already-soft-deleted users (SQLRestriction on deleted_at) result in 404 EntityNotFoundException so clients can handle idempotency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/kr/co/webee/application/user/service/UserService.java`:
- Around line 42-48: The withdraw method in UserService currently only calls
userRepository.delete (which relies on `@SQLDelete` soft-delete) and misses
required side-effects; update UserService.withdraw to (1) invalidate all auth
tokens for the user (call the auth/token service, e.g.,
tokenService.invalidateTokens(userId) or equivalent), (2) remove or archive
profile images via the S3 helper (e.g.,
s3Service.deleteProfileImage(user.getProfileImageKey()) or document preservation
policy), (3) trigger anonymization or mark PII for later processing (either call
a new anonymizeUser(user) helper on User.java or publish a domain event), and
(4) publish a domain event for downstream handlers
(eventPublisher.publishEvent(new UserWithdrawnEvent(userId))). Also decide and
implement idempotency: handle repeated withdraw calls by checking soft-deleted
state (consider user.isDeleted or `@SQLRestriction` behavior) and return success
if already withdrawn instead of throwing EntityNotFoundException. Ensure all
calls occur inside the `@Transactional` withdraw method and log failures for
compensating actions.
In `@src/main/java/kr/co/webee/domain/user/entity/User.java`:
- Line 21: The User entity currently relies on Hibernate's default table name
while `@SQLDelete` uses a hardcoded "user" table; add an explicit `@Table`(name =
"user") annotation to the User class to make the table mapping explicit and keep
`@SQLDelete`(sql = "UPDATE user SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?")
correct and maintainable (locate the User class and annotate it with `@Table`(name
= "user")).
- Line 22: The `@SQLRestriction`("deleted_at IS NULL") on User causes LAZY
`@ManyToOne` fetchers to throw EntityNotFoundException and makes
existsByUsername()/existsByPhoneNumber() ignore soft-deleted rows leading to DB
unique constraint errors; fix by removing or avoiding reliance on
`@SQLRestriction` and instead anonymize identifying fields on delete (implement in
User.delete()/UserService.deleteUser() to set username = username + "_deleted_"
+ id and phoneNumber = phoneNumber + "_deleted_" + id, and persist), and/or if
immediate fix needed change problematic relations (e.g., Post, PostComment,
PostLike, Business, UserCrop, ProductReview, InterestMarket,
InterestNewsKeyword, BeeDiagnosis, BeeRecommendation) from `@ManyToOne`(fetch =
FetchType.LAZY) to fetch = FetchType.EAGER to avoid lazy load failures; ensure
AuthService.signup() and repository methods
existsByUsername()/existsByPhoneNumber() will then behave consistently with DB
uniqueness.
---
Nitpick comments:
In `@src/main/java/kr/co/webee/application/user/service/UserService.java`:
- Line 45: The codebase mixes EntityNotFoundException and
BusinessException(ErrorType.*) patterns; pick one and make services consistent:
either convert services using BusinessException (e.g., PostLikeService,
PostCommentService) to throw EntityNotFoundException like
UserService/ProductService and uploadProfileImage, or add a new
ErrorType.USER_NOT_FOUND and refactor places using EntityNotFoundException to
throw BusinessException(ErrorType.USER_NOT_FOUND) (update global handler if
needed). Locate usages by searching for class/method names UserService,
ProductService, PostLikeService, PostCommentService, uploadProfileImage and
update all throw sites and tests to use the chosen pattern consistently,
ensuring ErrorType enum and global exception mapper are updated accordingly.
In `@src/main/java/kr/co/webee/domain/user/entity/User.java`:
- Line 43: The User entity's deletedAt field relies on implicit naming and
`@SQLDelete` assumes the column is named deleted_at; add an explicit `@Column`
mapping on the deletedAt field (e.g., `@Column`(name = "deleted_at")) in the User
class to ensure the field maps to the expected DB column regardless of naming
strategy so soft-delete SQL in `@SQLDelete` will target the correct column.
In `@src/main/java/kr/co/webee/presentation/user/api/UserApi.java`:
- Around line 45-55: The withdraw endpoint currently returns a raw String
("OK"), which breaks the project's ApiResponse<T> convention and causes
asymmetric responses in UserApi (see withdraw and uploadProfileImage); change
withdraw to use the common wrapper or no-content semantics: either return
ApiResponse<Void> or declare void and add `@ResponseStatus`(HttpStatus.NO_CONTENT)
so all controllers are consistent with ApiResponseHandler behavior, and update
the method signature and any callers accordingly; also update the API docs for
withdraw to state that requests for already-soft-deleted users (SQLRestriction
on deleted_at) result in 404 EntityNotFoundException so clients can handle
idempotency.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 39c029c4-2bf5-401a-bb38-40485200f7ab
📒 Files selected for processing (4)
src/main/java/kr/co/webee/application/user/service/UserService.javasrc/main/java/kr/co/webee/domain/user/entity/User.javasrc/main/java/kr/co/webee/presentation/user/api/UserApi.javasrc/main/java/kr/co/webee/presentation/user/controller/UserController.java
| @Transactional | ||
| public void withdraw(Long userId) { | ||
| User user = userRepository.findById(userId) | ||
| .orElseThrow(() -> new EntityNotFoundException("User not found: " + userId)); | ||
|
|
||
| userRepository.delete(user); | ||
| } |
There was a problem hiding this comment.
탈퇴 시 부수 작업 누락 점검.
withdraw는 단순히 userRepository.delete(user) 만 호출하여 @SQLDelete로 soft delete만 수행합니다. 다음 항목들은 탈퇴 API에서 통상적으로 함께 처리되어야 합니다.
- 인증/인가 토큰 무효화: 탈퇴 후에도 발급된 JWT/Refresh 토큰이 만료 시점까지 유효하면, 탈퇴 회원이 보호 리소스에 계속 접근 가능. 이때
@SQLRestriction으로findByUsername이 비어 다른 인증 흐름이 깨질 수도 있음. - S3 프로필 이미지 자원 정리(또는 보존 정책 정의)
- 개인정보 익명화(코멘트는
User.java측에 별도 작성) - 도메인 이벤트 발행으로 후속 처리(연관 엔티티 anonymize, 통계 차감 등) 트리거
또한 @SQLRestriction 적용 후에는 동일 사용자에 대한 두 번째 withdraw 호출이 findById 단계에서 EntityNotFoundException을 던지는데, 이 경로가 의도된 것인지(혹은 멱등하게 처리할지) 정의해 주세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/kr/co/webee/application/user/service/UserService.java` around
lines 42 - 48, The withdraw method in UserService currently only calls
userRepository.delete (which relies on `@SQLDelete` soft-delete) and misses
required side-effects; update UserService.withdraw to (1) invalidate all auth
tokens for the user (call the auth/token service, e.g.,
tokenService.invalidateTokens(userId) or equivalent), (2) remove or archive
profile images via the S3 helper (e.g.,
s3Service.deleteProfileImage(user.getProfileImageKey()) or document preservation
policy), (3) trigger anonymization or mark PII for later processing (either call
a new anonymizeUser(user) helper on User.java or publish a domain event), and
(4) publish a domain event for downstream handlers
(eventPublisher.publishEvent(new UserWithdrawnEvent(userId))). Also decide and
implement idempotency: handle repeated withdraw calls by checking soft-deleted
state (consider user.isDeleted or `@SQLRestriction` behavior) and return success
if already withdrawn instead of throwing EntityNotFoundException. Ensure all
calls occur inside the `@Transactional` withdraw method and log failures for
compensating actions.
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| @Entity | ||
| @SQLDelete(sql = "UPDATE user SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# DB 엔진 확인
fd -e yml -e yaml -e properties . src/main/resources | xargs rg -n -i 'datasource|jdbc|dialect|hibernate'
# User 테이블 명시 여부 확인
rg -nP -C2 '@Table\s*\(' src/main/java/kr/co/webee/domain/user
# 마이그레이션/DDL에서 user 테이블명 확인
fd -e sql . | xargs rg -n -i 'create\s+table.*user'Repository: BeeKeeprs/was
Length of output: 238
🏁 Script executed:
# User 엔티티 전체 확인
cat -n src/main/java/kr/co/webee/domain/user/entity/User.java
# 데이터베이스 마이그레이션 파일 찾기
fd -e sql .
# Flyway 마이그레이션 폴더 확인
find . -path "*/db/migration*" -o -path "*/flyway*" 2>/dev/null | head -20Repository: BeeKeeprs/was
Length of output: 2754
🏁 Script executed:
# 테이블 생성 DDL 찾기 (user 관련)
fd -e sql . -x grep -l -i "create.*table" {}
# application.yml/properties에서 JPA 설정 확인
cat -n src/main/resources/application.ymlRepository: BeeKeeprs/was
Length of output: 4029
🏁 Script executed:
# 마이그레이션 파일 찾기
find . -path "*/db/migration*" -o -path "*/flyway*" -o -name "*.sql" 2>/dev/null
# SQL 파일에서 user 테이블 정의 확인
fd -e sql . -x grep -i "create.*table.*user" {}Repository: BeeKeeprs/was
Length of output: 39
🏁 Script executed:
# Flyway 기본 경로 확인
ls -la src/main/resources/db/ 2>/dev/null || echo "No db migration folder"
# 모든 SQL 파일 나열
find src -name "*.sql" -type f 2>/dev/nullRepository: BeeKeeprs/was
Length of output: 80
명시적 테이블명 지정으로 @SQLDelete 유지보수성 개선 권장
User 엔티티에 @Table 어노테이션이 없어 Hibernate가 기본값으로 테이블명 user를 사용하고 있으며, 현재 @SQLDelete의 하드코딩된 SQL이 이와 일치하고 있습니다. 또한 현재 데이터베이스가 MySQL이므로 user가 예약어로 취급되지 않습니다.
다만 코드의 견고성과 유지보수성을 위해, 엔티티에 명시적으로 @Table(name = "user")를 추가하여 테이블명 매핑을 명확히 하는 것을 권장합니다. 이렇게 하면:
- 향후 누군가 테이블명을 변경할 때 두 곳을 동시에 수정하도록 강제
- 다른 데이터베이스로 마이그레이션할 경우 대비
- 코드의 의도가 명확해짐
현재는 기능상 문제가 없지만, 향후 스키마 변경 시 soft delete가 조용히 실패할 수 있는 위험을 사전에 방지하는 것이 좋습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/kr/co/webee/domain/user/entity/User.java` at line 21, The User
entity currently relies on Hibernate's default table name while `@SQLDelete` uses
a hardcoded "user" table; add an explicit `@Table`(name = "user") annotation to
the User class to make the table mapping explicit and keep `@SQLDelete`(sql =
"UPDATE user SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?") correct and
maintainable (locate the User class and annotate it with `@Table`(name = "user")).
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| @Entity | ||
| @SQLDelete(sql = "UPDATE user SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?") | ||
| @SQLRestriction("deleted_at IS NULL") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# username/phoneNumber 유니크 제약 확인
fd -e sql . | xargs rg -ni 'unique.*(username|phone_number)|user.*unique'
rg -nP -C2 '@Column\s*\([^)]*unique' src/main/java/kr/co/webee/domain/user
# User에 대한 ManyToOne 사용처
rg -nP -C3 '@ManyToOne[\s\S]{0,120}User\b'Repository: BeeKeeprs/was
Length of output: 39
🏁 Script executed:
cat -n src/main/java/kr/co/webee/domain/user/entity/User.java | head -100Repository: BeeKeeprs/was
Length of output: 2754
🏁 Script executed:
# 유니크 제약 찾기 - 다양한 패턴으로 검색
rg -n '@Column.*unique\s*=' src/main/java/
rg -n 'unique\s*=\s*true' src/main/java/
# 마이그레이션 파일이나 스키마 정의 찾기
fd -e sql . | head -20
fd -e yml . | head -20
fd -e yaml . | head -20Repository: BeeKeeprs/was
Length of output: 132
🏁 Script executed:
# User 엔티티에 대한 `@ManyToOne` 관계 찾기
rg -n '@ManyToOne' src/main/java/ -A 2Repository: BeeKeeprs/was
Length of output: 4968
🏁 Script executed:
# SQLRestriction 실제 사용 확인
rg -n '@SQLRestriction' src/main/java/Repository: BeeKeeprs/was
Length of output: 153
🏁 Script executed:
# UserRepository 찾기 및 검사
find src -name "*UserRepository*" -type fRepository: BeeKeeprs/was
Length of output: 126
🏁 Script executed:
# 마이그레이션 파일 찾기
fd -e sql . src/main/resources/
fd -e sql . src/Repository: BeeKeeprs/was
Length of output: 39
🏁 Script executed:
# findByUsername, existsByUsername 등의 메서드 검색
rg -n 'findByUsername|existsByUsername|existsByPhoneNumber|findByPhoneNumber' src/main/java/Repository: BeeKeeprs/was
Length of output: 975
🏁 Script executed:
# 데이터베이스 스키마 정의 확인
rg -n 'CREATE TABLE.*user' src/ -iRepository: BeeKeeprs/was
Length of output: 39
🏁 Script executed:
# 삭제 시 username/phoneNumber 처리 로직 확인
rg -n 'delete|soft.*delete' src/main/java/kr/co/webee/domain/user/ -i -A 3Repository: BeeKeeprs/was
Length of output: 1345
🏁 Script executed:
cat src/main/java/kr/co/webee/domain/user/repository/UserRepository.javaRepository: BeeKeeprs/was
Length of output: 522
🏁 Script executed:
# application.yml 에서 데이터베이스 스키마 설정 확인
cat src/main/resources/application.yml | head -50Repository: BeeKeeprs/was
Length of output: 1239
🏁 Script executed:
# 데이터베이스 제약 조건이 정의된 다른 엔티티 예 찾기
rg -n '@Column.*unique' src/main/java/ -C 1Repository: BeeKeeprs/was
Length of output: 39
🏁 Script executed:
# AuthService 의 회원가입 로직 확인
cat src/main/java/kr/co/webee/application/auth/service/AuthService.java | head -70Repository: BeeKeeprs/was
Length of output: 3168
@SQLRestriction의 부수 효과를 재검토하세요.
검증 결과, 다음 우려사항이 확인되었습니다:
-
@manytoone User 관계의 LAZY 로딩 위험: Post, PostComment, PostLike, Business, UserCrop, ProductReview, InterestMarket, InterestNewsKeyword, BeeDiagnosis, BeeRecommendation 등 10개 이상의 엔티티가
@ManyToOne(fetch = FetchType.LAZY)로 User를 참조합니다.@SQLRestriction("deleted_at IS NULL")으로 인해 삭제된 User를 LAZY 로딩할 때EntityNotFoundException이 발생할 수 있습니다. -
중복 검사와 유니크 제약의 불일치: AuthService의
signup()메서드는existsByUsername(),existsByPhoneNumber()를 통해 중복을 검사하며, 이 쿼리들은@SQLRestriction으로 인해 삭제된 유저를 제외합니다. 따라서 삭제된 유저의 username/phoneNumber는 "사용 가능"한 것으로 인식되지만, DB 수준에서 unique 제약이 있다면 INSERT 시점에DataIntegrityViolationException이 발생할 수 있습니다.
탈퇴 시 username과 phoneNumber를 익명화(예: username + "_deleted_" + id)하거나, @ManyToOne 관계에서 fetch = FetchType.EAGER로 변경하거나, 삭제 시 이러한 필드들의 관리 전략을 수립할 것을 권장합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/main/java/kr/co/webee/domain/user/entity/User.java` at line 22, The
`@SQLRestriction`("deleted_at IS NULL") on User causes LAZY `@ManyToOne` fetchers to
throw EntityNotFoundException and makes existsByUsername()/existsByPhoneNumber()
ignore soft-deleted rows leading to DB unique constraint errors; fix by removing
or avoiding reliance on `@SQLRestriction` and instead anonymize identifying fields
on delete (implement in User.delete()/UserService.deleteUser() to set username =
username + "_deleted_" + id and phoneNumber = phoneNumber + "_deleted_" + id,
and persist), and/or if immediate fix needed change problematic relations (e.g.,
Post, PostComment, PostLike, Business, UserCrop, ProductReview, InterestMarket,
InterestNewsKeyword, BeeDiagnosis, BeeRecommendation) from `@ManyToOne`(fetch =
FetchType.LAZY) to fetch = FetchType.EAGER to avoid lazy load failures; ensure
AuthService.signup() and repository methods
existsByUsername()/existsByPhoneNumber() will then behave consistently with DB
uniqueness.
23ecdf8 to
6f5abd5
Compare
🧷 이슈
🔨 작업 내용
👀 리뷰 요구사항
Summary by CodeRabbit
릴리스 노트