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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions