개발 slecs

가맹점 수수료 요율 검증으로 마진 역전 버그 차단

목차

문제: 요율 한 번 잘못 바꿨더니 마진이 음수가 됨

파트너 관리 화면에서 가맹점 충전 수수료를 0.5%로 내려달라는 요청 받음. 별생각 없이 업데이트했더니 운영팀에서 바로 핑이 옴. "이거 총판이 0.7% 받고 있는데, 가맹점이 0.5%면 총판이 -0.2% 손실 보는 거 아님?" 맞는 말이었음.

원래 구조 다시 정리해봄:

  • 가맹점이 가장 높은 요율 부담
  • 위로 올라갈수록 요율이 낮아짐
  • 차액 = 상위 계층의 수익

근데 화면에서는 상한값도, 상위 요율도 무시하고 그냥 저장돼버림. 정책이 머릿속에만 있었던 거임.

검증 두 단계로 분리

처음엔 한 메서드에 다 박아버렸다가 테스트 짜기 너무 빡세서 분리함.

검증 내용 실패 시
상한 검증 결제대행사 계약 상한 초과 금지 즉시 차단
상위 요율 비교 신규 요율이 상위보다 낮으면 차단 즉시 차단
validateFeeCap(newRate, contractCap);
validateAgainstParentRate(partnerId, newRate);

두 단계로 쪼개니까 실패 메시지도 정확하게 띄울 수 있고, 둘 중 하나만 다시 짤 때도 부담 없음. 화면에서 1차로 막아도 서비스 계층에서 한 번 더 막게 양쪽에 걸어둠.

삽질 포인트

  • 처음엔 하위 파트너까지 재귀로 다 검사하려 했는데, 한 건 수정에 N+1 쿼리 폭발. 상위만 비교하고 하위는 별도 배치로 정합성 체크하기로 결정
  • 상한값이 결제대행사별로 달라서 캐시 안 해두면 화면 뜰 때마다 조회 폭주. 파트너 화면 진입 시 한 번만 끌어오게 묶음
  • 파트너 본인이 자기 요율을 자기 상위보다 높게 못 올리게 하는 케이스를 처음에 빼먹어서 리뷰에서 잡힘. 같은 검증 함수에 추가

회고

수수료 정책은 코드보다 도메인 이해가 먼저였음. "상위가 더 적게 받고 차액이 수익"이라는 한 줄을 머리에 박고 보니 검증 로직이 자명해짐. 정책을 주석으로 한 줄 박아두는 게 다음 사람한테 가장 큰 선물이라는 것도 다시 확인함. 화면에서 막혀도 누군가 곧 API로 우회 호출할 거라는 가정도 잊지 말 것. 끝

댓글 0

첫 댓글 달아줘.