개발 slecs

파트너 포털 일별 판매 차트와 KPI 데이터 불일치 수정

목차

차트와 KPI 숫자가 미묘하게 다를 때, 처음엔 쉽게 지나친다. "쿼리 타이밍 차이겠지", "캐시 문제겠지" 하고 넘어가다가, 실제로는 소스 자체가 달랐던 경우가 있음. 이번 partner-portal 버그가 그랬다.

날짜별 판매 추이 차트와 상단 KPI 카드에 표시되는 todaySales가 가끔 안 맞는다는 제보가 들어왔다. 처음엔 렌더링 타이밍이나 캐싱 레이어 문제를 의심했는데, 쿼리를 직접 비교해보니 원인이 명확했음. 두 화면이 아예 다른 SQL을 쓰고 있었다.

왜 이런 불일치가 생기나

대시보드 하나를 만들 때 KPI 카드와 차트는 보통 다른 시점에, 다른 사람이, 다른 스프린트에서 붙인다. KPI는 "오늘 총 매출"이라는 단순한 숫자 하나만 필요하니까 간단한 SUM 쿼리로 먼저 만든다. 차트는 나중에 날짜별 추이를 보여줘야 하니까 GROUP BY date 형태로 따로 작성하게 됨. 여기서 두 쿼리의 WHERE 조건이나 집계 기준이 조금씩 달라지기 시작한다.

흔히 벌어지는 차이를 정리하면 이렇다.

차이 유형 KPI 쿼리 차트 쿼리
날짜 기준 컬럼 paid_at created_at
타임존 처리 CONVERT_TZ(..., '+09:00') UTC 그대로
상태 필터 status IN ('PAID', 'SETTLED') status != 'CANCELLED'
NULL 처리 COALESCE(amount, 0) NULL 그대로 SUM

이 중 하나만 달라도 숫자가 어긋난다. 특히 타임존 처리가 빠진 경우, 한국 시간 기준 자정 근처 거래가 전날 혹은 다음날로 넘어가서 일별 합계가 틀어진다. 하루치 전체가 바뀌는 게 아니라 경계값 몇 건만 이동하니까 언뜻 보면 비슷해 보여서 발견이 늦어지는 것도 이 케이스다.

이번엔 집계 조건 자체가 달랐다. SQL 매퍼 파일에서 차트용 쿼리의 WHERE 절과 SUM 대상 컬럼을 KPI 기준으로 통일하는 방식으로 수정했음.

-- 수정 전 (차트 쿼리)
SELECT
    DATE(created_at) AS sale_date,
    SUM(order_amount) AS total_sales
FROM orders
WHERE created_at BETWEEN #{startDate} AND #{endDate}
  AND status != 'CANCELLED'
GROUP BY DATE(created_at)

-- 수정 후 (KPI와 동일 기준)
SELECT
    DATE(CONVERT_TZ(paid_at, '+00:00', '+09:00')) AS sale_date,
    SUM(COALESCE(net_amount, 0)) AS total_sales
FROM orders
WHERE paid_at BETWEEN #{startDate} AND #{endDate}
  AND status IN ('PAID', 'SETTLED')
GROUP BY DATE(CONVERT_TZ(paid_at, '+00:00', '+09:00'))

실제 코드는 당연히 다르지만, 수정 방향은 이런 식이었다. 집계 컬럼, 날짜 기준 컬럼, 상태 필터 세 군데를 맞추고 나서야 두 숫자가 일치했음. 변경 파일은 SQL 매퍼 하나, 맞물린 설정/문서 파일 하나로 최소화했다.

한 가지 고민했던 지점은 "차트 쿼리를 고칠 것인가, 아니면 KPI 쿼리를 차트에서 재사용할 것인가"였다. 쿼리를 재사용하는 게 단기적으론 깔끔하지만, 차트는 날짜별 반복 조회고 KPI는 단일 집계라 파라미터 구조가 달라서 억지로 합치면 오히려 유지보수가 더 복잡해진다. 로직은 동일하게, 쿼리는 각자의 역할에 맞게 두되 집계 기준만 명시적으로 통일하는 쪽이 맞다고 판단했음.

버그 수정 프로세스

단순히 증상만 픽스하는 건 의미가 반이다. 왜 발생했는지 원인을 파악하고, 비슷한 패턴이 다른 곳에도 있는지 확인하는 게 한 세트라고 생각함. 이번엔 파트너별 정산 화면과 월별 요약 리포트도 훑어봤는데, 거기는 이미 동일 소스를 쓰고 있어서 추가 수정은 없었다. 그래도 확인을 안 했으면 모르고 넘어갔을 거임.

버그 수정할 때 체크하는 순서:

  • 같은 로직이 다른 경로에도 있는지 - 중복 쿼리, 유사한 집계
  • 수정이 기존 정상 케이스를 망가뜨리지 않는지 - 다른 날짜 범위나 상태값으로 재확인
  • 해당 화면에서 실제 동작 확인
  • 관련 숫자를 다른 화면과 cross-check

엣지 케이스를 꼼꼼히 따지는 게 귀찮아 보여도, 나중에 같은 버그로 다시 오는 시간 비용이 훨씬 크다. 특히 금융/결제 도메인은 숫자 하나가 틀리면 신뢰가 흔들릴 수 있어서 "대충 맞는 것 같다"로 넘어가면 반드시 다시 돌아온다.

수정 후엔 버그를 직접 재현해서 정상 동작을 눈으로 확인했고, 차트와 KPI 숫자가 같은 날짜 범위에서 일치하는지 비교했음.

작업 습관으로 굳힌 것들

사내 서비스를 만들다 보면 기능 하나가 단순히 화면에 버튼 하나 추가하는 것으로 끝나지 않는다는 걸 계속 체감한다. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 모두 엮여 있어서 어느 하나만 빠뜨려도 숫자가 맞지 않거나 특정 사용자에게 이상한 화면이 나온다.

대시보드처럼 여러 숫자가 나란히 보이는 화면은 특히 데이터 소스를 단일화하거나, 적어도 집계 기준을 명시적으로 문서화해두는 게 낫다. 팀이 커지고 쿼리를 여러 사람이 건드리기 시작하면 "어디서 가져온 숫자인지"가 금방 불투명해진다. 이번처럼 화면이 늘어나면서 쿼리가 자연스럽게 분기된 경우, 설정/문서 파일에 "이 집계 기준은 todaySales와 동일하게 유지할 것"이라는 한 줄만 있어도 다음 사람이 실수할 가능성이 낮아진다.

개발 방식 측면에서는 이 작업에도 같은 루틴을 적용했다.

  • 변경 전 현재 수치 메모 - 차트값과 KPI값 양쪽 모두
  • 수정 후 같은 날짜 범위로 재확인
  • 관련 화면에서 숫자 cross-check
  • 커밋 메시지는 "무엇을"보다 "왜"를 담으려 노력

커밋 메시지에 "왜"를 쓰는 게 처음엔 어색한데, 익숙해지면 나중에 git blame할 때 맥락이 한눈에 들어와서 편하다. "차트 쿼리 수정"보다 "차트 집계 기준을 KPI todaySales와 통일 - 날짜 기준 컬럼 및 상태 필터 불일치"가 6개월 후에 훨씬 도움이 됨.

작은 커밋을 자주 하는 습관도 유지 중이다. 변경 범위가 좁고 의도가 명확하면, 문제가 생겼을 때 어느 커밋에서 깨졌는지 찾기가 훨씬 쉽다. 이번처럼 SQL 매퍼 수정과 문서 수정을 논리적으로 묶어서 한 커밋으로 가면, 리뷰할 때도 "이 두 파일이 왜 함께 바뀌었는지"가 자연스럽게 읽힌다.

댓글 0

첫 댓글 달아줘.