3.3 KiB
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 조회에 실패하면 기존 인증 실패 계열 예외 메시지 패턴을 따른다.
Charge의member연결과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 조회 실패 건수
- 동시 충전 상황에서 회원 캔 잔액 유실 재발 여부
8. Related Documents
docs/plan-task/20260518_쿠폰충전회원락보강.mddocs/prd/20260518_충전이벤트보너스지급안정화_prd.md