개발 slecs

매출 KPI 요약에 PG 비용 컬럼 추가

목차

system-revenue-kpi 영역에 PG 비용 컬럼을 추가했다. live/yesterday/week 세 가지 summary 각각에 PG 비용을 붙이는 작업이고, 변경된 파일은 SQL 매퍼 하나다.

숫자 단위로 보면 작아 보이지만, 결제 도메인에서 집계 쿼리 하나를 추가하는 건 단순히 SELECT 컬럼 하나 더 붙이는 문제가 아니다. 어느 시점 기준으로 집계할 건지, NULL은 어떻게 처리할 건지, 기존 summary의 다른 숫자들과 단위/기준이 맞는지를 다 따져야 한다. 그래서 화면 레벨이 아니라 쿼리 레벨부터 설계를 시작했다.

쿼리를 어떻게 짰나

live/yesterday/week 각각 집계 방식이 조금씩 다르다. live는 오늘 실시간 누적이고, yesterday는 전일 확정치, week는 최근 7일 롤링이다. 기존 매출 집계 쿼리가 이미 각각 있었고, 거기에 PG 비용 컬럼을 추가하는 식으로 작업했다.

PG 비용은 보통 트랜잭션 단위로 테이블에 찍혀 있다. 집계할 때 실수하기 쉬운 부분이 몇 가지 있다.

  • NULL 처리: PG사에서 수수료 데이터가 아직 안 들어온 경우 NULL이 생긴다. SUM(pg_fee) 그대로 쓰면 NULL이 섞인 row에서 집계가 생각과 다르게 동작할 수 있다. COALESCE(pg_fee, 0)으로 감싸는 게 기본.
  • 취소 건 처리: 결제 취소가 발생하면 PG 비용도 환급되는 케이스가 있다. 취소 row가 음수로 들어오는 구조라면 SUM 자체가 맞지만, 별도 상태 컬럼으로 구분되는 구조면 WHERE 조건을 다시 봐야 한다.
  • 집계 기준 시간: live 집계에서 "오늘"의 기준이 서버 시간인지 사용자 타임존인지, yesterday가 자정에서 자정인지 확인. 기존 매출 집계와 기준을 맞추지 않으면 화면에서 두 숫자를 나란히 놓고 봤을 때 차이가 생긴다.

실제 SQL은 대략 이런 형태다. 기존 매출 집계 쿼리에 컬럼 하나 얹는 구조.

SELECT
    SUM(amount)                   AS revenue,
    COALESCE(SUM(pg_fee), 0)      AS pg_cost,
    COUNT(*)                      AS txn_count
FROM payments
WHERE
    status IN ('COMPLETED', 'PARTIAL_CANCEL')
    AND paid_at >= :startAt
    AND paid_at < :endAt

취소 케이스의 status 조건과 pg_fee 부호 처리는 프로젝트 스키마에 맞게 직접 기존 코드를 먼저 읽고 확인했다. 이 부분은 구조마다 다르기 때문에 기존 로직을 베이스로 맞추는 게 우선이다.

금융 도메인에서 숫자를 추가할 때의 원칙

결제 쪽 KPI를 다루다 보면 "숫자가 대충 맞는 것 같다"는 감으로 넘어가면 반드시 돌아온다는 걸 계속 경험하게 된다. 관리자가 KPI 화면에서 보는 값과 다른 경로로 확인한 값이 조금이라도 다르면 즉시 신뢰 문제가 된다.

이번에 새 컬럼을 추가하면서 확인한 것들을 정리하면 이렇다.

확인 항목 내용
기존 집계와 기준 일치 paid_at 기준, 타임존, status 필터 동일 여부
NULL/0 처리 pg_fee가 없는 row에서 집계 결과가 깨지지 않는지
취소 건 반영 취소 후 PG 비용이 어떻게 반영되는지 확인
다른 화면 cross-check 동일 기간 다른 화면의 PG 비용 합산과 일치 여부
쿼리 실행 계획 기존 쿼리에 컬럼 추가 후 실행 시간 변화 없는지

쿼리 실행 계획은 자주 빠뜨리게 된다. 집계 쿼리는 대용량 테이블에서 돌기 때문에 컬럼 하나 추가해도 인덱스가 안 타거나 full scan이 늘어나면 대시보드 로딩이 느려진다. EXPLAIN 한 번으로 확인할 수 있으니 건너뛰지 않는 게 낫다.

실시간 갱신 방식도 고려했다. live summary는 폴링으로 주기적으로 새로고침하는 구조였고, PG 비용 컬럼도 같은 주기를 그대로 탔다. 여기서 새로운 이벤트 구독 구조를 도입할 이유는 없었다. 기존 흐름에 얹는 게 맞았다.

검증 방식과 개발 습관

구현 후 화면에서 직접 확인하고, 기존 데이터가 깨지지 않았는지 cross-check했다. live/yesterday/week 각각에서 PG 비용이 제대로 렌더링되는지 보고, 같은 기간 다른 경로로 뽑은 숫자와 비교했다.

개발 흐름은 이런 식이다.

  • 변경 전 현재 화면 수치를 메모하거나 스크린샷
  • 수정 후 같은 케이스로 다시 확인
  • 관련 화면이 있으면 숫자 cross-check
  • 커밋은 논리적으로 독립된 단위로 쪼개기

마지막 항목이 습관으로 자리잡으면 디버깅이 훨씬 편해진다. 이번처럼 SQL 매퍼 변경, 내부 클래스 메서드 추가, 화면 렌더링 연동이 묶여 있는 작업도 각 단계를 별도 커밋으로 남기면, 나중에 어느 지점에서 문제가 생겼는지 찾는 시간이 줄어든다. 작은 커밋을 자주 하는 게 귀찮아 보여도 사후에는 훨씬 이득이다.

커밋 메시지도 "무엇을"보다 "왜"를 담으려고 한다. add pg_cost column to summary보다는 KPI summary에 PG 비용 추가 - 운영팀 비용 추적 요건 대응 쪽이 나중에 git log를 볼 때 맥락이 살아있다.

사내 서비스에서 기능 하나를 추가하는 일이 화면에 버튼 하나 붙이는 것으로 끝나지 않는다는 건, 이런 작업을 반복하면서 매번 다시 확인하게 된다. SQL 집계, 상태 처리, 예외 방어, 렌더링, 권한 확인이 모두 엮여 있고, 특히 금융/결제 쪽은 그 연결고리 하나가 어긋나면 숫자가 틀리거나 특정 케이스에서 이상한 화면이 나온다. 꼼꼼함이 기본값이어야 하는 도메인이라는 걸, 작업할 때마다 다시 새긴다.

댓글 0

첫 댓글 달아줘.