파트너 정산에 갭 안내·드롭다운·마감잔액 배지 추가
목차
partner-settlement 화면에 갭 안내 행, 드롭다운 상세, 기간 마감잔액 배지 세 가지를 한 번에 추가했다. 변경 파일은 뷰 1개, 스타일 1개, 내부 클래스 1개, SQL 매퍼 1개. 숫자만 보면 작은 작업처럼 들리는데, 실제로는 쿼리 집계 설계부터 상태 전환 로직, 예외 처리, 화면 렌더링까지 거의 전 레이어를 건드렸다.
출발점은 기존 화면이 제공하지 않던 데이터가 필요해진 것이었다. 정산 기간 사이에 빈 구간(갭)이 생기는 경우, 화면에 아무 표시가 없으면 운영팀 입장에서는 데이터가 없는 건지 집계가 아직 안 된 건지 확정 전 상태인 건지 구분할 방법이 없다. 드롭다운 상세도 마찬가지였다. 금액 합계만 보이는 상태에서 세부 내역을 확인하려면 별도 화면으로 이동해야 했고, 그게 운영 흐름을 끊었다. 마감잔액 배지는 기간 종료 시점의 잔액을 인라인으로 보여주는 용도인데, 기존 쿼리에서는 이 값이 아예 나오지 않아서 SQL 매퍼부터 다시 설계했다.
프론트에서 값을 계산해 억지로 끼워맞추는 방식을 쓰지 않은 게 이번 작업의 핵심이다. 필요한 집계가 없으면 백엔드 쿼리에서 뽑도록 하고, 프론트는 그 값을 어떻게 보여줄지만 결정한다. 집계를 프론트에서 하면 다른 화면 숫자와 반드시 틀어지는 시점이 생기고, 정산 도메인에서 그게 신뢰 문제로 직결된다.
구현하면서 챙긴 것들
정산 흐름에 신규 상태를 추가하면서 PENDING → CONFIRMED 전환 로직도 같이 다뤘다. 상태 머신이 들어가는 순간부터 멱등성 문제가 따라온다. 같은 이벤트가 두 번 들어왔을 때 두 번 처리되지 않도록 멱등성 키를 걸어뒀다. 정산 도메인에서 이게 빠지면 취소나 환불이 중복 반영되는 케이스가 나올 수 있다. 방어 처리는 선택이 아닌 기본값으로 봤다.
취소/환불 발생 시 정산 동기화도 함께 맞췄다. 원래는 취소가 발생해도 집계에 반영이 늦거나 아예 잡히지 않는 경우가 있었는데, 이번에 집계 쿼리와 동기화 타이밍을 명확히 정리했다. audit 이력 테이블 연동도 추가해서 언제 어떤 상태로 바뀌었는지 추적 가능하게 했다. 운영 이슈가 생겼을 때 "어느 시점에 뭔가 달라졌다"를 쿼리 한 번으로 확인할 수 있으면 디버깅 시간이 확연히 줄어든다.
실시간 갱신 방식은 폴링 vs 이벤트 기반을 검토했는데, 정산 데이터 특성상 갱신 빈도가 낮고 일관성이 우선이라 현재 방식을 유지했다. 이런 선택은 기록해두지 않으면 나중에 "왜 이렇게 했지?" 하고 다시 뒤지게 된다. 코드 주석이나 커밋 메시지에 근거를 남겨두는 게 장기적으로 훨씬 낫다.
예외 케이스를 정리하면 이렇다.
| 케이스 | 처리 방식 |
|---|---|
| 기간 내 정산 데이터 없음 (갭 구간) | 갭 안내 행 렌더링 |
| 마감잔액이 NULL인 기간 | 배지 미노출, 빈 문자열 대체 금지 |
| 드롭다운 열었을 때 내역 0건 | 빈 상태 메시지 표시 |
| 권한 없는 파트너가 타인 정산 접근 | 서버 레이어에서 차단 후 클라이언트 분기 |
NULL과 0을 구분하는 게 특히 중요했다. 잔액 0은 "계산 결과가 0원"이고, NULL은 "집계 자체가 없음"인데, 둘 다 공백으로 뿌리면 운영팀이 맥락을 잃는다. 타입 레벨에서 구분하고 렌더링 조건도 명확히 분기했다. "그냥 null 체크 하나면 되겠지" 생각하고 넘어가면 나중에 운영 문의로 돌아온다.
쿼리 성능도 미리 확인했다. 파트너 수 × 기간 수 조합으로 돌아가는 집계 쿼리는 인덱스 설계가 잘못되면 기간이 길어질수록 응답 시간이 선형 이상으로 늘어난다. 배포 전에 EXPLAIN으로 실행 계획을 확인하고, 필요한 컬럼에 인덱스가 제대로 타는지 검증했다.
커밋 단위와 검증 방식
구현 완료 후에는 직접 화면에서 동작을 확인했다. 갭 안내가 의도한 구간에만 나타나는지, 드롭다운이 자연스럽게 열리고 닫히는지, 배지 값이 다른 화면의 잔액 숫자와 일치하는지. cross-check는 "맞겠지"가 아니라 같은 기간을 두 화면에서 나란히 열어놓고 숫자를 눈으로 맞추는 식으로 했다.
금융 도메인에서 숫자 하나가 화면마다 다르게 보이면 버그를 넘어서 신뢰 문제가 된다. 운영팀이 한 번이라도 "이 숫자 왜 저기랑 달라요?"를 겪으면, 그 이후로는 모든 숫자를 의심하게 된다. 꼼꼼함이 기본값이어야 하는 이유가 여기 있다.
커밋은 논리적으로 독립된 단위로 쪼갰다.
feat: SQL 매퍼에 기간별 마감잔액 집계 쿼리 추가
feat: 내부 클래스에 갭 구간 판별 로직 추가
feat: 정산 뷰에 갭 안내 행 / 드롭다운 / 마감잔액 배지 렌더링
style: 정산 배지 및 드롭다운 스타일 추가
이렇게 쪼개두면 나중에 배지만 되돌려야 하는 상황이 생겨도 스타일 커밋 하나만 revert하면 되고, 갭 로직 버그를 찾을 때 쿼리 커밋과 뷰 커밋을 분리해서 볼 수 있다. 특히 SQL 변경과 로직 변경이 한 커밋에 섞여 있으면 rollback 범위가 애매해지는데, 그게 배포 직후 이슈가 생겼을 때 가장 골치 아픈 상황이다.
커밋 메시지는 "무엇을"보다 "왜"를 담으려고 노력한다. "배지 추가"보다 "기간 마감잔액을 인라인에서 확인할 수 없는 문제 해결을 위해 마감잔액 배지 추가"가 6개월 뒤에 훨씬 더 도움이 된다. 변경을 처음 보는 사람이 PR을 열었을 때 왜 이게 필요했는지 코드 밖에서도 읽을 수 있어야 한다.
사내 서비스를 오래 만들다 보면, 기능 하나가 화면 버튼 하나로 끝나는 경우가 없다는 걸 반복적으로 체감한다. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 모두 엮여 있고, 어느 하나가 빠지면 반드시 어딘가 구멍이 난다. "대충 맞는 것 같다"로 넘어가면 나중에 반드시 다시 돌아온다. 금융 도메인은 그게 더 빠르게, 더 눈에 띄게 돌아온다.
댓글 0
첫 댓글 달아줘.