Files
sodalive-backend-spring-boot/docs/prd/20260518_충전이벤트보너스지급안정화_prd.md

108 lines
5.7 KiB
Markdown

# PRD: 충전 이벤트 보너스 지급 안정화
## 1. Overview
- 충전 완료 후 지급되는 충전 이벤트 보너스가 누락되거나 중복 지급되지 않도록 안정화한다.
- 상세 구현 방향은 `docs/plan-task/20260518_충전이벤트보너스지급안정화.md`를 기준으로 한다.
- 이 PRD는 충전 이벤트 보너스 지급 작업의 재시도, worker, 관리자 API 운영 정책을 확정한다.
---
## 2. Problem
- 현재 충전 이벤트 보너스 지급은 결제 완료 흐름과 분리된 비동기 이벤트에서 처리된다.
- 비동기 처리 실패가 발생하면 원 결제는 성공했지만 이벤트 보너스만 누락될 수 있다.
- 실패 작업을 DB에 남기고, 정해진 주기와 횟수 안에서 재시도하며, 최종 실패 건은 관리자 API로 확인/재시도할 수 있어야 한다.
---
## 3. Goals
- 이벤트 보너스 지급 실패가 DB에 남고 재시도 가능해야 한다.
- 중복 결제 검증 또는 worker 재시도에도 보너스가 중복 지급되지 않아야 한다.
- 원본 충전 완료 처리에서도 회원 잔액 변경은 회원 row lock을 잡은 뒤 수행해 동시 충전 시 잔액 유실을 방지해야 한다.
- 최대 재시도 후에도 실패한 작업은 운영자가 원인과 지급 대상, 지급할 캔 수를 확인할 수 있어야 한다.
- 충전 완료 검증 시 이벤트 작업을 기록하고 즉시 지급을 시도하되, 즉시 수행 중인 작업을 worker가 중복 처리하지 않아야 한다.
---
## 4. Non-Goals
- 결제 PG 검증 방식 자체를 교체하지 않는다.
- 충전 상품 가격, 이벤트 보너스율, 첫 충전 이벤트율을 변경하지 않는다.
- 관리자 화면 신규 개발은 포함하지 않는다. 단, 실패 작업 조회/재시도용 관리자 API는 포함한다.
---
## 5. Core Features
### Feature A. 충전 이벤트 보너스 지급 작업 추적
#### Requirements
- 충전 완료 후 이벤트 보너스 지급 대상이면 DB 작업으로 추적한다.
- 지급 대상, 원본 충전, 추가 지급 캔 수, 처리 상태, 실패 사유를 확인할 수 있어야 한다.
- 원본 충전 완료 처리(`verify`, `verifyHecto`, `appleVerify`, `payverseVerify`, `payverseWebhook`, `processGoogleIap`)는 회원 row lock 안에서 `PaymentStatus.REQUEST -> COMPLETE` 전이와 `member.charge(...)`를 수행한다.
- 충전 완료 처리(`verify`) 시 `charge_event_job`을 기록하고, 같은 흐름에서 이벤트 보너스 지급을 즉시 시도한다.
- 즉시 지급 중인 작업은 worker가 처리하지 않도록 `PROCESSING` 상태로 선점한다.
- 상세 테이블 구조와 구현 항목은 plan-task 문서를 따른다.
#### Edge Cases
- 같은 결제 검증 요청이 여러 번 들어와도 보너스 작업은 중복 생성되지 않아야 한다.
- worker가 같은 작업을 재시도해도 보너스는 1회만 지급되어야 한다.
- 이벤트 설정이 재시도 시점에 변경되어도 최초 작업 생성 시점의 추가 캔 수를 유지해야 한다.
- 즉시 지급 실패 후 worker가 재시도할 수 있도록 작업은 `PENDING``next_retry_at`으로 전환되어야 한다.
---
### Feature B. 이벤트 보너스 worker 재시도
#### Requirements
- worker 실행 주기는 5분으로 한다.
- worker batch size는 30건으로 한다.
- worker는 활성 충전 이벤트가 없으면 `charge_event_job` 조회를 수행하지 않고 종료한다.
- worker는 `PENDING` 상태이면서 `next_retry_at IS NULL OR next_retry_at <= now`인 작업만 처리한다.
- backoff 정책은 5분, 10분, 15분 순서로 적용한다.
- 최대 재시도 횟수는 3회로 한다.
- 3회 재시도 후에도 실패하면 `FAILED`로 전환하고 자동 재시도를 중단한다.
#### Edge Cases
- 같은 시간에 다른 scheduler/worker가 실행되어도 worker는 최대 30건만 처리한다.
- 이미 `PROCESSING`, `DONE`, `FAILED`인 작업은 자동 worker가 처리하지 않는다.
- `FAILED` 작업은 관리자 재시도 API를 통해서만 다시 재시도 대상으로 전환한다.
---
### Feature C. 이벤트 작업 관리자 API
#### Requirements
- `DONE`, `PROCESSING` 상태를 제외한 `charge_event_job` 목록을 조회할 수 있는 관리자 API를 추가한다.
- 조회 API는 재시도 대기 중인 `PENDING` 작업과 운영 확인이 필요한 `FAILED` 작업을 함께 보여준다.
- `FAILED` 상태의 단일 작업을 재시도 대상으로 되돌리는 관리자 API를 추가한다.
- 재시도 API는 대상 작업을 `PENDING`으로 변경하고 `next_retry_at`을 즉시 실행 가능하도록 갱신한다.
- 재시도 API는 이미 `DONE` 또는 `PROCESSING`인 작업을 변경하지 않아야 한다.
#### Edge Cases
- 관리자가 같은 실패 작업 재시도 API를 여러 번 호출해도 중복 지급되지 않아야 한다.
- 이미 성공 처리된 작업은 재시도 API에서 거부되어야 한다.
- 즉시 지급 중인 `PROCESSING` 작업과 지급 완료된 `DONE` 작업은 관리자 조회 목록에 노출하지 않는다.
---
## 7. Technical Constraints
- DB는 MySQL을 기준으로 한다.
- 날짜/시간 컬럼은 `TIMESTAMP`를 사용한다.
- boolean 컬럼이 필요해질 경우 `TINYINT(1)`을 사용한다.
- 각 DB 컬럼에는 `COMMENT`를 작성한다.
- 구현 계획과 DDL은 `docs/plan-task/20260518_충전이벤트보너스지급안정화.md`를 기준으로 관리한다.
---
## 8. Metrics
- 결제 완료 후 이벤트 보너스 지급 작업 생성 성공률
- 이벤트 보너스 지급 성공률
- 재시도 후 성공한 작업 수
- 최종 `FAILED` 상태로 남은 작업 수
- 중복 지급 방지 위반 건수
- 관리자 API로 재시도된 작업 수
---
## 9. Related Documents
- `docs/plan-task/20260518_충전이벤트보너스지급안정화.md`