공급사 포털 상품 목록·브랜드 자동 승인 버그 수정
목차
supplier-portal 쪽 버그 수정 작업이었다. 변경 파일 수만 보면 SQL 매퍼 1개, 뷰·스타일 1개로 단촐해 보이지만, 실제로 건드려야 했던 범위와 검증 과정은 그보다 훨씬 넓었다.
크게 두 군데가 문제였다. 하나는 my-products 데스크톱 테이블 - 공급사가 등록한 상품 목록을 집계해서 보여주는 화면. 다른 하나는 브랜드 자동 승인 흐름 - 조건이 충족되면 브랜드를 자동으로 승인 처리하는 로직. 증상은 달랐지만 공통점이 있었다. 둘 다 일반적인 정상 케이스에서는 멀쩡히 동작했고, 특정 데이터 조합에서만 재현됐다. 이런 버그는 발견하기도 어렵고, 증상만 보고 픽스하면 같은 자리에서 또 나온다.
원인: 집계 쿼리와 상태 분기의 엣지 케이스
my-products 테이블부터. 특정 조건에서 상품 수나 브랜드 수가 맞지 않았다. SQL 매퍼를 뒤져보니 LEFT JOIN + WHERE 조합에서 의도와 다른 결과가 나오는, 그리 낯설지 않은 패턴이었다.
-- 의도: 상품별로 승인된 브랜드 수 집계 (브랜드 없는 상품도 포함)
-- 문제가 있는 패턴
SELECT p.id, p.name, COUNT(b.id) AS approved_brand_count
FROM products p
LEFT JOIN brands b ON b.product_id = p.id
WHERE b.status = 'approved' -- LEFT JOIN이 사실상 INNER JOIN으로 동작
GROUP BY p.id, p.name;
-- 수정된 패턴
SELECT p.id, p.name, COUNT(b.id) AS approved_brand_count
FROM products p
LEFT JOIN brands b ON b.product_id = p.id
AND b.status = 'approved' -- ON 절에서 필터
GROUP BY p.id, p.name;
차이가 미묘해 보이지만 결과는 전혀 다르다. WHERE로 거르면 LEFT JOIN으로 연결된 행 중 b.status = 'approved'가 없는 경우가 모두 날아간다. 브랜드가 아직 없거나 심사 중인 상품이 목록에서 사라지는 것이다. 공급사 입장에선 "내가 등록한 상품이 왜 안 보이지"가 된다. 정상 케이스에서 안 잡히는 이유는 단순하다 - 테스트 데이터는 대부분 'approved' 상태의 브랜드가 붙은 상품이고, 브랜드가 없거나 pending 상태인 케이스는 실제 공급사 데이터에서나 자연스럽게 발생한다.
집계 외에도 WHERE와 HAVING 순서 문제가 섞여 있었다. GROUP BY + HAVING으로 걸러야 할 집계 후 조건이 WHERE에 있어서 집계 이전에 필터가 적용되는 케이스도 있었다. 결과적으로 어떤 상태 조합에서는 집계값이 의도와 달리 0이나 null로 내려왔다.
브랜드 자동 승인 흐름은 다른 결이었다. 자동 승인 트리거 조건을 체크하는 프론트 로직이 상태값 조합을 잘못 처리하고 있었다. 브랜드 상태가 여러 단계를 가지는데, 세 가지 이상 상태값이 조합될 때 분기가 예상과 다른 경로로 빠졌다. 그 결과 뷰에서 잘못된 상태 메시지와 스타일이 렌더링됐다.
수정 과정: 증상보다 패턴
픽스 자체는 빠르다. SQL 조건을 ON 절로 옮기고, 집계 후 필터를 HAVING으로 이동하고, 상태 분기 조건을 보정하고, 뷰 로직을 맞추면 된다. 오래 걸리는 건 "이 패턴이 다른 매퍼에도 쓰이고 있지 않나" 확인하는 작업이다.
이번에 챙긴 것들:
- LEFT JOIN + WHERE 패턴이 쓰인 다른 매퍼 전수 확인. 같은 구조가 다른 쿼리에 있어도 지금은 정상 케이스만 들어와서 안 터진 것일 수 있다.
- 브랜드 상태 분기 로직이 여러 곳에 흩어져 있었는데, 수정한 조건과 나머지가 일치하는지 대조. 중복된 조건 로직은 나중에 한 곳만 고치고 나머지를 빠뜨리는 사고의 씨앗이 된다.
- 수정 후 정상 케이스를 케이스별로 나눠서 확인. 브랜드 없음, 브랜드 하나 approved, 복수 브랜드 혼재 상태, 전체 rejected. 각각 숫자 직접 확인.
- my-products 화면 수치와 관리자 화면 수치 cross-check. 같은 데이터를 두 경로로 보여주는 구조라 한 쪽만 맞추면 다른 쪽이 틀릴 수 있다.
cross-check 단계가 이번에 특히 중요했다. 공급사가 보는 화면과 내부 관리자 화면이 같은 데이터를 각자 다른 쿼리로 집계하고 있었다. 한 쪽만 고치면 두 화면 숫자가 달라져 오히려 더 이상하게 보인다. 두 화면이 같은 숫자를 보여줘야 비로소 정상이라고 할 수 있다.
| 확인 항목 | 재현 케이스 | 체크 방법 |
|---|---|---|
| SQL 집계 정합성 | 브랜드 없음 / 혼재 / 전체 rejected | 수정 전후 COUNT 결과 직접 비교 |
| 자동 승인 흐름 | 상태값 조합 3가지 이상 | 각 분기 직접 재현 |
| 렌더링 정상 동작 | 각 상태별 화면 | 수정 전후 스크린샷 비교 |
| 관련 화면 cross-check | 공급사 화면 vs 관리자 화면 | 동일 데이터 기준 수치 대조 |
숫자 하나가 쌓는 것과 무너뜨리는 것
supplier-portal은 공급사가 비즈니스 의사결정에 직접 쓰는 화면이다. "내 상품 몇 개가 현재 승인 대기 중인가", "브랜드 자동 승인 조건은 언제 충족되나" 같은 정보를 여기서 본다. 이 숫자가 틀리면 공급사는 플랫폼 자체를 의심하게 된다. 한 번 심어진 의심은 설명으로 쉽게 사라지지 않는다.
사내 서비스라고 이 무게가 다르지 않다. 오히려 비즈니스 파트너가 실제 운영 결정을 내리는 데 쓰는 숫자라는 점에서, 불일치가 바로 운영 오류로 이어질 수 있다.
기능이 단순해 보여도 SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 전부 얽혀 있다. 어느 하나가 어긋나면 특정 데이터에서만 나타나는 버그가 된다. 개발 환경에서 정상 데이터로만 테스트하면 안 잡히고, 실제 공급사 데이터에서 처음 재현되는 케이스가 나오는 이유가 여기 있다. 상태값 조합은 실제 사용자 데이터만큼 다양하게 만들기가 쉽지 않다.
"대충 맞는 것 같다"로 넘기면 반드시 다시 온다. 그리고 두 번째로 올 때는 공급사가 이미 한 번 잘못된 숫자를 보고 판단을 내린 다음이다.
커밋은 SQL 매퍼 수정, 뷰·스크립트 수정을 따로 넣었다. 커밋 메시지에는 "LEFT JOIN 조건을 ON 절로 이동"보다 "왜 이 위치에서 집계가 의도와 달랐는지"를 담으려 했다. 나중에 비슷한 버그가 다른 쿼리에서 터질 때 git log가 힌트가 된다. 작은 커밋을 자주 쌓는 게 번거로워 보여도, 나중 디버깅 속도를 미리 당겨두는 것에 가깝다.
댓글 0
첫 댓글 달아줘.