Files
sodalive-backend-spring-boot/docs/prd/20260518_쿠폰충전회원락보강_prd.md

3.3 KiB

PRD: 쿠폰 충전 회원 락 보강

1. Overview

  • 쿠폰 사용으로 캔을 지급하는 흐름에서도 회원 잔액 변경 전에 회원 row lock을 확보하도록 보강한다.
  • 상세 구현 방향은 docs/plan-task/20260518_쿠폰충전회원락보강.md를 기준으로 한다.
  • 이번 문서는 구현 전 요구사항과 최소 작업 범위를 확정하기 위한 신규 작업 문서다.

2. Problem

  • 일반 결제 완료 흐름은 memberRepository.findByIdForUpdate(...)로 회원 row lock을 잡은 뒤 member.charge(...)를 호출한다.
  • 쿠폰 충전 흐름인 ChargeService.chargeByCoupon(...)은 컨트롤러/인증 계층에서 전달받은 member 인스턴스에 바로 member.charge(...)를 호출한다.
  • 같은 회원에게 쿠폰 충전과 다른 충전/보너스 지급이 동시에 발생하면 회원 잔액 갱신의 동시성 안전성이 일반 결제 흐름과 달라질 수 있다.

3. Goals

  • CouponType.CAN 쿠폰 사용 시 회원 row lock을 잡은 엔티티에 member.charge(...)를 호출한다.
  • 기존 쿠폰 사용 성공/실패 응답과 메시지는 변경하지 않는다.
  • 쿠폰 중복 사용 방지 로직은 기존 동작을 유지한다.
  • 일반 결제 완료 흐름의 락 패턴과 일관되게 동작하도록 최소 수정한다.
  • 회귀 테스트로 쿠폰 캔 지급 시 memberRepository.findByIdForUpdate(...)가 사용되는지 검증한다.

4. Non-Goals

  • 쿠폰 정책, 쿠폰 타입, 쿠폰 발급/조회 로직을 변경하지 않는다.
  • 포인트 쿠폰 지급 로직은 이번 범위에서 변경하지 않는다.
  • Member.charge(...) 구현 방식과 잔액 컬럼 구조를 변경하지 않는다.
  • 신규 API나 관리자 기능을 추가하지 않는다.

5. Core Features

Feature A. 쿠폰 캔 지급 회원 row lock 적용

Requirements

  • ChargeService.chargeByCoupon(...)CouponType.CAN 분기에서 회원 ID로 memberRepository.findByIdForUpdate(...)를 호출한다.
  • lock 조회에 실패하면 기존 인증 실패 계열 예외 메시지 패턴을 따른다.
  • Chargemember 연결과 member.charge(...) 호출은 lock 조회로 얻은 회원 엔티티를 기준으로 수행한다.
  • member.charge(...)는 기존처럼 += 기반 증가 로직을 그대로 사용한다.

Edge Cases

  • 이미 사용된 쿠폰이면 기존처럼 can.coupon.already_used 예외가 우선 발생해야 한다.
  • 유효하지 않은 쿠폰 번호이면 기존처럼 can.coupon.invalid_number_contact 예외가 발생해야 한다.
  • 회원 row lock 조회 결과가 없으면 쿠폰 사용과 캔 지급이 진행되지 않아야 한다.

6. Technical Constraints

  • Kotlin/Spring/JPA 기존 스타일을 따른다.
  • ChargeService의 기존 트랜잭션 경계를 유지한다.
  • 공개 API 스키마와 응답 DTO를 변경하지 않는다.
  • 불필요한 리팩터링 없이 쿠폰 캔 지급 경로만 최소 수정한다.

7. Metrics

  • 쿠폰 캔 지급 성공률
  • 쿠폰 중복 사용 차단 건수
  • 쿠폰 캔 지급 중 회원 lock 조회 실패 건수
  • 동시 충전 상황에서 회원 캔 잔액 유실 재발 여부

  • docs/plan-task/20260518_쿠폰충전회원락보강.md
  • docs/prd/20260518_충전이벤트보너스지급안정화_prd.md