결제와 충전 승인 로직을 분리해 포인트 상품 연동 개선
목차
충전형 결제 플랫폼에서 새로운 포인트 상품 채널을 연동할 때, 기존 결제 승인 로직과 충전 승인 로직을 깔끔하게 분리하는 게 얼마나 중요한지 다시 한 번 느꼈다.
왜 mode 분기가 필요했나
이전까지 우리 결제 게이트웨이는 단순했다. 신용카드 / 계좌이체 / 간편결제 같은 결제 수단의 차이는 있었지만, 모두 "상품 구매 → 결제 승인" 이라는 단일 흐름으로 처리됐다.
하지만 이번에 새로 연동한 포인트 상품은 결제와 충전이 다르다. 결제는 실제 돈이 나가지만, 충전은 계좌에서 돈을 빼고 플랫폼 내 포인트로 변환하는 중간 단계가 있다. approve 단계에서도 결제(PAYMENT)와 충전(CHARGE)은:
- PAYMENT: 즉시 거래 완료, 거래명세서 발급, 취소 정책 적용
- CHARGE: 포인트 지급 대기, 충전 기록 별도 관리, 환불 정책이 다름
단순히 조건문으로 분기하는 게 아니라, 이 차이를 코드 구조 자체에 반영해야 했다.
변경의 범위
변경 파일들을 보면 단순 하드코딩 추가가 아니었다:
| 영역 | 파일 | 역할 |
|---|---|---|
| 결제 웹 컨트롤러 | payment/web 클래스 | approve 요청 수신 시 mode 파라미터 검증 |
| 비즈니스 로직 | slecs/utl 클래스들 (3개) | CHARGE/PAYMENT 분기별 처리, 포인트 지급 로직, 거래 기록 생성 |
| 프론트엔드 | paymentSheet.jsp | 결제 요청 시 mode=CHARGE 파라미터 자동 추가 |
가장 중요한 건 utl 레이어의 3개 클래스인데, 아마도 각각:
- ApprovalProcessor 류: mode에 따라 서로 다른 처리 경로로 라우팅
- PointChargeService 류: 포인트 충전 전용 로직 (거래소 연동, 포인트 지급)
- TransactionRecorder 류: 결제/충전을 분리된 테이블에 기록
였을 거다. 프론트에서는 단순히 파라미터 하나 추가지만, 백엔드에서는 여러 계층의 로직이 추가됐다는 뜻이다.
이런 분기를 설계할 때 배운 점
1. 초반부터 분리하지 않으면 나중에 더 복잡해진다
처음엔 "if (mode == CHARGE)" 정도로 생각하기 쉽다. 하지만 충전 중에:
- 포인트 지급 실패 시 롤백 로직
- 부분 충전 시나리오 (예: 100만원 요청 중 50만원만 가능)
- 중복 충전 방지 (멱등성)
- 충전 후 사용자에게 보낼 알림
등등이 하나씩 추가되면서, 결국 별도 클래스로 분리하게 된다. 차라리 처음부터 나눴으면 PR 리뷰도 단순했을 거다.
2. 파라미터 vs 전략 패턴
우리는 mode를 query parameter로 전달했는데, 다른 방식도 있다:
// 방식 1: mode 파라미터 (현재)
POST /approve?mode=CHARGE&transactionId=123
// 방식 2: 다른 endpoint
POST /charge/approve (결제용)
POST /point/approve (충전용)
// 방식 3: 헤더로 분기
X-Transaction-Type: CHARGE
우리가 선택한 방식 1은 기존 approve 엔드포인트를 재사용하면서도 간단했다. 다만 나중에 mode 옵션이 늘어나면(예: 정산, 환불 등) 엔드포인트가 너무 뚱뚱해질 수 있다. 그때쯤이면 전략 패턴이나 팩토리로 리팩토링할 후보가 될 거 같다.
3. 테스트 커버리지 증가
mode 분기는 테스트 매트릭스를 2배 이상 늘린다:
- 결제 승인 + PAYMENT mode
- 결제 승인 + CHARGE mode (예상 실패)
- 충전 승인 + CHARGE mode
- 충전 승인 + PAYMENT mode (예상 실패)
- 부분 충전, 중복 요청, 타임아웃 등
이번 작업 후 테스트 케이스를 정리할 때, 팀원에게 "CHARGE는 이 시나리오는 스킵해도 돼"라는 기준을 문서화하는 데 시간을 썼다. 분기가 있으면 그에 맞춘 테스트 전략도 함께 가야 한다.
다음 단계
현재는 CHARGE 로직이 포인트 충전에 특화되어 있지만, 향후 다른 충전형 상품이 늘어날 때를 대비해야 한다. 이번 작업에서 mode 분기의 뼈대를 제대로 세워놨으니, 다음 유사 요구가 들어올 때 기존 코드를 그대로 확장할 수 있을 거 같다. 물론 그때쯤이면 다시 한 번 리뷰해서 더 일반화할 부분이 있는지 체크하겠지만.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.