Skip to content

[BUG] 히든 이미지 제출 시 회원 상태가 DB에 반영되지 않는 문제 #375

@sgo722

Description

@sgo722

📋 Issue 번호

#375

🔍 문제 설명

구버전 앱(1.2.0 미만) 사용자가 히든 프로필 이미지를 제출할 때, completeHiddenProfile() 메서드를 통해 회원 상태를 HIDDEN_COMPLETED로 변경하려 했으나 DB에 반영되지 않는 문제가 발생했습니다.

문제 발생 위치

  • 파일: PreVerificationStrategy.kt
  • 메서드: handleHiddenImages()

현상

  1. 히든 이미지가 정상적으로 S3에 업로드됨
  2. member.completeHiddenProfile() 호출됨
  3. 하지만 회원 상태가 DB에 업데이트되지 않음
  4. 회원이 계속 PERSONALITY_COMPLETED 상태에 머물러 있음
  5. 관리자 심사 요청이 정상적으로 처리되지 않음

🔎 원인 분석

트랜잭션 경계 분리 문제

@Transactional
override fun handleHiddenImages(member: Member, images: List<MultipartFile>): ResponseEntity<Any> {
    // 1. 히든 이미지 등록 (SignupService의 @Transactional 메서드 호출)
    signupService.registerHiddenImages(member, images)

    // 2. 파라미터로 받은 member 객체를 그대로 사용
    member.completeHiddenProfile()  // ⚠️ 영속성 컨텍스트에서 분리된 준영속 상태!

    // 3. 변경사항이 DB에 반영되지 않음
}

문제점:

  • signupService.registerHiddenImages()는 별도의 @Transactional 메서드
  • 해당 메서드 실행 중 member 엔티티가 영속성 컨텍스트에서 관리되지만, 메서드 종료 후 준영속 상태로 전환
  • 이후 member.completeHiddenProfile() 호출 시 변경 감지(Dirty Checking)가 작동하지 않음
  • 결과적으로 memberStatus 필드 변경사항이 DB에 반영되지 않음

관련 개념

  • 영속성 컨텍스트: JPA에서 엔티티를 관리하는 환경
  • 변경 감지(Dirty Checking): 영속 상태의 엔티티가 변경되면 트랜잭션 커밋 시점에 자동으로 UPDATE 쿼리 실행
  • 준영속 상태: 영속성 컨텍스트에서 분리된 엔티티, 변경 감지가 작동하지 않음

✅ 해결 방법

변경 전

@Transactional
override fun handleHiddenImages(member: Member, images: List<MultipartFile>): ResponseEntity<Any> {
    signupService.registerHiddenImages(member, images)

    // ⚠️ 준영속 상태의 member 사용
    member.completeHiddenProfile()

    // Discord 알림 전송
    asyncNotificationService.sendAsync(...)

    return ResponseEntity.ok().build()
}

변경 후

@Transactional
override fun handleHiddenImages(member: Member, images: List<MultipartFile>): ResponseEntity<Any> {
    signupService.registerHiddenImages(member, images)

    // ✅ 영속 상태의 member 재조회
    val findMember = memberJpaRepository.findByMemberId(member.getIdOrThrow())
        ?: throw MemberException(HttpStatus.NOT_FOUND, "회원을 찾을 수 없습니다.")

    findMember.completeHiddenProfile()  // ✅ 변경 감지 작동

    // Discord 알림 전송
    asyncNotificationService.sendAsync(
        notification = Notification(
            type = NotificationType.DISCORD,
            targetId = findMember.getIdOrThrow().toString(),
            title = "${findMember.getProfileOrThrow().getCodeNameOrThrow()}님이 심사를 요청하였습니다.",
            body = "code:L 프로필 심사 요청이 왔습니다.",
        ),
    )

    return ResponseEntity.ok().build()
}

해결 원리

  1. memberJpaRepository.findByMemberId()영속성 컨텍스트에서 관리되는 member 재조회
  2. 영속 상태의 findMember에 대해 completeHiddenProfile() 호출
  3. 트랜잭션 커밋 시점에 변경 감지(Dirty Checking)가 정상 작동
  4. memberStatus 변경사항이 DB에 반영됨

🧪 테스트 시나리오

재현 방법

  1. 앱 버전 1.2.0 미만 사용자로 회원가입 진행
  2. 필수 프로필, 성격 프로필 작성 완료 (PERSONALITY_COMPLETED 상태)
  3. 히든 프로필 이미지 제출 (POST /v1/signup/hidden-images)
  4. DB에서 해당 회원의 member_status 확인

기대 결과 (수정 후)

  • ✅ 히든 이미지가 S3에 정상 업로드
  • ✅ 회원 상태가 HIDDEN_COMPLETED로 변경
  • hidden_completed_at 타임스탬프 기록
  • ✅ Discord 알림 정상 발송

📊 영향 범위

영향받는 사용자

  • 앱 버전 1.2.0 미만 사용자
  • 히든 프로필 이미지를 제출하는 신규 가입자

영향받는 기능

  • 회원가입 플로우 (히든 프로필 완료)
  • 관리자 프로필 심사 대기 목록

심각도

  • Priority: High
  • Severity: Critical (회원가입 완료 불가)

🔗 관련 커밋

  • 5fff556 [bug] 히든이미지 저장 시 필드값 저장이 DB반영이 안되던 문제 수정

📝 참고 사항

JPA 트랜잭션 경계와 영속성 컨텍스트

  • Spring에서 @Transactional 메서드가 중첩 호출될 때, 기본적으로 같은 트랜잭션을 공유
  • 하지만 내부 메서드 실행 중 엔티티 상태 변경이 있을 경우, 호출 후 엔티티가 준영속 상태로 전환될 수 있음
  • 해결책: 엔티티를 재조회하거나 EntityManager.merge() 사용

유사한 문제 예방

향후 유사한 문제를 방지하기 위해:

  1. 서비스 간 호출 시 엔티티 재조회 고려
  2. 엔티티 변경 후 변경사항이 반영되는지 로그 확인
  3. 통합 테스트로 DB 반영 여부 검증

📌 체크리스트

  • 문제 원인 분석 완료
  • 코드 수정 완료
  • 로그 추가 (상태 변경 확인용)
  • 통합 테스트 작성
  • 코드 리뷰 요청
  • QA 테스트 완료

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug버그 수정입니다.

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions