계층별 수수료 분배 로직과 정산 검증 기능 추가
목차
계층별 수수료 분배 로직을 짜는 건 처음엔 단순해 보인다. 요율 곱하기, 고정비 더하기. 근데 막상 구현하다 보면 계층 수, 요율 입력 순서, 부동소수점 처리, 배치 집계 타이밍 같은 게 하나씩 발목을 잡는다. 이번 작업도 딱 그 범위였다.
수수료 구조 자체부터 얘기하면, 유통 채널이 계층 구조로 되어 있을 때 각 계층이 부담하는 수수료율이 다르게 설정된다. 하위 계층이 높은 요율을 내고, 상위 계층은 낮은 요율만 실제 집행 기관에 넘기면서 그 차액을 마진으로 가져가는 방식이다. 대리점망이나 리셀러 구조가 있는 서비스에서는 흔히 쓰이는 모델이다.
이번에 작업한 예시 기준으로 보면 이렇다.
| 계층 | 요율 | 비고 |
|---|---|---|
| 최하위 | 1.0% | 최대 부담 |
| 중간 | 0.8% | 차액 0.2% 수익 |
| 최상위 | 0.6% | 차액 0.2% 수익 |
비율 수수료만 있으면 계산이 단순하지만, 건당 고정 수수료가 붙으면 얘기가 달라진다. 소액 거래가 많은 구조에서는 비율 수수료보다 건당 고정 수수료 비중이 오히려 커지는 경우도 있어서, 둘을 합산할 때 어느 쪽이 지배적인지 사전에 파악해두는 게 좋다. 계산 자체는 간단하다.
// 비율 수수료 + 건당 고정 수수료 합산
long feeAmount = (long)(txAmount * feeRate) + perTxFee;
여기서 (long) 캐스팅이 중요한데, txAmount * feeRate를 double로 계산한 뒤 버림 처리하는 것과 반올림 처리하는 것 사이에 건당 1원 차이가 생긴다. 건수가 수백만 건 쌓이면 무시할 수 없는 오차가 된다. 현재는 버림 기준으로 처리하고 있는데, 이 정책은 운영팀 쪽과 맞춰서 문서화해두는 게 낫다. 나중에 감사 받을 때 "왜 이렇게 계산됐냐"는 질문이 꼭 나온다.
validation을 어디에 두느냐
이번 작업에서 실질적으로 공들인 부분은 계층별 요율 순서 검증이었다. 하위 계층 요율이 상위 계층 요율보다 낮거나 같으면 마진이 음수가 된다. 회계상으로는 상위 계층이 하위 계층에게 돈을 거꾸로 줘야 하는 상황인데, 시스템이 이걸 자동으로 막지 않으면 운영 중에 조용히 흘러가다가 정산 때 터진다.
validation을 어디에 둘지는 항상 고민이 있다. 선택지를 정리하면 이렇다.
- 입력 시점 (UI/API 레이어): 사용자 피드백이 빠르고 잘못된 데이터가 DB에 아예 안 들어온다. 단, 클라이언트 우회 가능성이 있어서 서버 사이드를 믿어야 한다.
- 저장 시점 (서비스 레이어): 실제 비즈니스 룰이 적용되는 곳이라 가장 신뢰할 수 있는 지점이다. 이번에 추가한 것도 여기다.
- 정산 배치 실행 시점: 마지막 방어선. 여기서 잡히면 이미 운영 데이터에 문제가 생긴 상태라 롤백 비용이 크다.
세 군데 모두 막는 게 이상적이지만, 현실적으로는 서비스 레이어 한 곳에서 일관되게 관리하고 배치 쪽에는 이상 탐지 알림 정도만 두는 방식이 유지보수하기 편하다. 같은 룰이 세 군데 흩어지면 하나 바꿀 때 나머지를 빠뜨리는 사고가 생긴다.
정산 배치와 UI 사이의 간극
정산 배치는 주기적으로 실행되면서 해당 기간 거래 내역을 집계하고 수수료를 확정한다. 배치가 돌기 전과 후의 상태를 UI에서 어떻게 구분해서 보여주느냐도 사소하지 않은 문제다. "집계 중", "확정됨", "오류" 같은 상태값이 명확하게 관리되지 않으면 사용자가 정산이 안 됐는데 됐다고 오해하거나 반대로 이미 됐는데 재처리 요청을 넣는 상황이 생긴다.
정산 화면에서 사용자가 가장 많이 보는 건 결국 숫자다. 총 거래액, 수수료, 실수령액 세 가지를 명확하게 보여주는 게 핵심이고, 표기 방식은 단순하지만 통일이 안 되면 혼란이 크다. 천 단위 구분자와 '원' 단위를 일관되게 쓰고, 마이너스 금액은 색으로 구분해주는 정도만 해도 CS 문의가 줄어드는 걸 체감할 수 있다.
작업 규모 자체는 크지 않았다. 하지만 수수료 계산이나 정산 쪽은 틀렸을 때 영향이 직접적으로 금액으로 나타나기 때문에, 작더라도 꼼꼼하게 짜야 하는 영역이다. validation 추가나 계산 정책 명문화처럼 눈에 안 띄는 작업들이 나중에 시스템 신뢰도를 결정한다.
댓글 0
첫 댓글 달아줘.