Show GN: buttonmasher – 중복 결제와 재시도 버그를 찾아보는 Claude Code 스킬
요약
본 글은 결제 중복 및 재시도 버그를 찾아내는 'buttonmasher'라는 Claude Code 스킬을 소개합니다. 이 스킬은 단순 코드 리뷰를 넘어, 버튼 연타나 웹훅 재전송 등 다양한 실행 시점과 순서에 따른 문제를 집중적으로 점검하여 실제 서비스의 취약점을 발견하는 데 초점을 맞춥니다.
핵심 포인트
- 단순한 unique 제약으로는 중복 결제를 막기 어려움
- 실제 버그는 요청의 '시점'과 '순서'에서 발생함
- buttonmasher는 실행 시나리오 기반으로 코드를 분석함
- 멱등성 키(Idempotency Key) 적용이 필수적임
결제 API에서 orders(cart_id)
에 unique 제약을 걸어두면 이중 결제가 막힐까요?
결제 API를 먼저 호출하고 주문을 저장하는 구조라면 막히지 않습니다. 결제 버튼을 두 번 눌렀을 때 두 요청 모두 주문이 저장되기 전에 결제 API를 호출할 수 있기 때문입니다. unique 제약은 이후의 INSERT만 막습니다. 결과적으로 주문은 1건인데 결제는 2번 발생할 수 있습니다.
백엔드 개발을 하다 보면 이런 문제를 반복해서 만나게 됩니다. 웹훅이 재전송되면서 주문이 중복 생성되거나, 이미 취소된 예약에 다시 처리가 들어가는 경우도 있습니다.
일반적인 코드 리뷰에서는 이런 버그를 놓치기 쉽습니다. 코드 한 줄이 잘못됐다기보다 요청이 들어오는 순서와 시점에 따라 문제가 발생하기 때문입니다.
코드를 함수 단위로 읽는 것보다, 같은 요청을 두 번 보내거나 처리 중에 다시 요청이 들어오는 상황을 확인하고 싶었습니다. 그래서 이런 실행 순서를 집중적으로 점검하는 buttonmasher라는 Claude Code 스킬을 만들었습니다.
제출 버튼 연타, 타임아웃 후 재시도, 뒤로가기 후 재진입, 여러 탭에서의 동시 요청, 웹훅 재전송 등을 가정하고 코드를 분석합니다. 실행 환경이 준비되어 있으면 실제 요청으로 확인하고, 그렇지 않으면 코드 추적 결과라는 점을 구분합니다.
별도의 실행 프로그램은 아니고, 에이전트가 참고하는 마크다운 프롬프트 모음입니다.
주로 확인하는 문제는 두 가지입니다.
- 한 번만 실행돼야 하는 작업이 중복 실행되는 경우
- 이미 완료된 작업이 다시 실행되는 경우
직접 확인해 보기
앞서 설명한 unique 제약 사례는 저장소의 demo/
에 넣어뒀습니다. 외부 패키지 설치 없이 Node.js로 실행할 수 있고, 터미널 하나에서 서버를 띄운 뒤 다른 터미널에서 스크립트로 동시 요청 두 개를 보내 재현할 수 있습니다.
- 수정 없음: 주문 2건, 결제 2건
- unique 제약만 적용: 주문 1건, 결제 2건
- unique 제약 + 결제 API 멱등성 키 적용: 주문 1건, 결제 1건
마지막 결과는 데모의 구현과 요청 조건에서 확인한 것입니다. 실제 서비스에서는 멱등성 키를 생성하고 보관하는 방식, 결제 API의 멱등성 지원 여부까지 고려해야 합니다.
일반 프롬프트와 비교
실제로 얼마나 도움이 되는지 확인하려고 일반적인 버그 탐색 프롬프트와 비교해 봤습니다.
Claude Fable 5를 Claude Code에서 사용했고, 동일한 도구와 환경에서 조건별로 2회씩 테스트했습니다.
cal.com 예약 생성 경로에서는 buttonmasher가 6건, 일반 프롬프트가 0건을 발견했습니다.
대표적으로 멱등성 키가 예약 상태 ACCEPTED
일 때만 기록되는 문제가 있었습니다. 결제 대기 등으로 PENDING
상태인 예약에는 키가 null
로 남을 수 있는데, PostgreSQL의 일반적인 unique 제약은 여러 null
값을 허용합니다.
따라서 이 제약만으로는 중복 예약을 막을 수 없습니다. 같은 원인을 지적한 이슈도 별도로 등록되어 있습니다. (cal.com #29968)
일반 프롬프트는 해당 경로를 확인했지만 문제를 발견하지 못했습니다. 반대로 일반 프롬프트가 찾아낸 시간대 관련 버그와 보안 우회 문제는 buttonmasher가 놓쳤습니다.
FastAPI 템플릿에서는 오히려 일반 프롬프트의 결과가 더 좋았습니다.
일반 프롬프트가 10건, buttonmasher가 5건을 발견했고, 해당 저장소에서 가장 심각한 문제도 buttonmasher는 찾아내지 못했습니다.
cal.com은 테스트 환경을 끝내 실행하지 못했습니다. 따라서 발견한 6건은 모두 정적 코드 분석 결과이며, 실제 실행 환경에서 중복 예약이나 결제가 발생하는지 재현한 것은 아닙니다.
또한 조건당 2회씩만 테스트했기 때문에 이 결과만으로 어느 쪽이 더 우수하다고 일반화하기는 어렵습니다. 비교에 사용한 프롬프트와 출력 원문, 놓친 문제까지 저장소의 bench/
에 올려뒀습니다.
설치 방법
Claude Code에서 다음 두 명령어를 실행하면 됩니다.
/plugin marketplace add Nova-47/buttonmasher
/plugin install buttonmasher@buttonmasher
특정 파일을 검사하려면 다음처럼 실행합니다.
/buttonmasher src/api/checkout.ts
인자 없이 /buttonmasher
를 실행하면 현재 diff를 대상으로 검사합니다. "이 엔드포인트 재시도해도 안전해?"처럼 한국어로 요청해도 됩니다.
직접 사용해 보시고 발견한 버그나 놓친 버그를 알려주시면 감사하겠습니다. 특히 어떤 문제를 놓쳤는지가 궁금합니다. 실제 서비스에서 중복 결제나 중복 주문을 경험하셨다면 어떤 상황에서 발생했는지도 듣고 싶습니다.
그리고 또 한 가지 의견을 더 구하고 싶습니다. 이런 검사는 매 PR마다 CI에서 자동으로 실행하는 편이 좋을까요?
아니면 결제나 예약처럼 중복 실행이 문제가 되는 코드를 수정할 때만 직접 실행하는 방식이 더 실용적일까요?
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기