개발 slecs

가상계좌 충전 정산에 결제수단 컬럼과 멱등 처리 추가

목차

결제수단 필드를 왜 이제야 추가했나

가상계좌 충전 로직을 손보다가 결제수단 구분 필드가 없어서 통계가 뒤죽박죽인 걸 발견함. 이커머스 정산 화면에서 "이게 카드인지 가상계좌인지" 구분이 안 되니까 운영팀이 매번 결제대행사 원장이랑 대조하고 있었음. 컬럼 하나 추가는 일이 아니고, 이미 쌓인 데이터를 어떻게 분류할지가 진짜 일이었음.

구분 기존 변경 후
결제수단 식별 메모로 추론 명시 컬럼
통계 집계 수기 대조 즉시
웹훅 분기 if 떡칠 enum 라우팅

가상계좌 충전이 왜 꼬였나

기존 흐름은 "충전 요청 → 즉시 잔액 반영" 한 줄이었음. 카드 결제는 그래도 동작했는데 가상계좌는 입금까지 시간차가 있어서, 그 사이에 취소/환불이 끼면 잔액이 마이너스로 박혔음.

  • 충전 요청 시점: PENDING 으로만 기록, 잔액 변동 0
  • 결제대행사 입금 통보: CONFIRMED 로 승격하면서 잔액 반영
  • 만료/취소 통보: CANCELLED 처리, 후속 변동 없음
-- 잔액 반영은 PENDING -> CONFIRMED 전이에서 단 한 번
UPDATE charge_history
   SET status     = 'CONFIRMED',
       pay_method = #{payMethod}
 WHERE order_id   = #{orderId}
   AND status     = 'PENDING';

status = 'PENDING' 조건이 WHERE 절에 박혀 있는 게 핵심. 동일 통보가 두 번 와도 두 번째는 0 row 되어서 잔액 이중 가산이 막힘.

웹훅 멱등성, "그럴 리가" 가 진짜로 일어남

처음엔 중복 통보가 들어올 리가 없다고 생각했는데, 로그 보니 분당 두세 건씩 같은 주문번호가 들어오고 있었음. 결제대행사 쪽 재시도 정책 + 우리 응답 지연이 겹친 결과.

  • 응답이 200 OK 로 나갈 때까지 같은 메시지가 N번 재시도
  • 첫 호출이 잔액을 가산하고, 두 번째 호출도 가산하면 사고
  • 결국 멱등성은 옵션이 아니라 기본 전제

추천 적립도 같이 미뤄야 했음

파트너 간 추천 보상이 충전 시점에 즉시 지급되는 구조였는데, 충전 자체가 PENDING 단계로 분리되면서 보상도 시점을 맞춰야 했음. 안 그러면 입금 안 된 충전에 대한 보상이 먼저 나가는 사고.

  • PENDING: 적립 후보로만 기록
  • CONFIRMED: 실제 적립 트랜잭션 트리거
  • CANCELLED: 후보 폐기, 적립 0

회고

  • 컬럼 하나 추가가 단순 작업처럼 보여도 "왜 빠져 있었나"부터 파야 함. 보통은 동기 결제만 가정한 흔적임
  • 비동기 입금이 끼는 순간 PENDING/CONFIRMED 분리는 선택이 아니라 필수
  • 웹훅은 무조건 멱등성. 중복 한 번에 정산 전체가 깨질 수 있음
  • 충전 상태 전이를 바꾸면 그 위에 얹힌 보상/적립 로직도 같이 봐야 함. 이걸 놓치면 잔액은 맞는데 보상은 틀어짐

다음

댓글 0

첫 댓글 달아줘.