Debugging/2026.04.18/8 min read

찰떡 차감이 두 번 일어나지 않게 막기

AI 분석과 리포트 기능에 쓰는 찰떡 지갑에서 중복 차감, 부족 잔액, 환불 흐름을 방어한 기록입니다.

CubeWalletIdempotency

Code notes

코드에서 확인한 구현 포인트

배포 기준 2026.04.18

관련 파일

apps/web/lib/cubes.tsapps/web/app/api/cubes/spend/route.tsapps/web/app/api/cubes/refund/route.tsapps/mobile/lib/cube-api.ts

구현 메모

cube_transactions는 idempotency_key를 기준으로 이미 처리된 요청을 찾을 수 있게 했다.

모바일 cube-api는 잔액 부족 응답을 예외가 아니라 insufficient 상태로 받아 화면이 다음 행동을 안내하게 한다.

차감 실패 후 복구를 위해 refund API도 referenceId와 idempotencyKey를 기준으로 중복 환불을 막는다.

결제성 기능은 성공보다 중복 실패가 무섭다

찰떡은 사용자가 분석이나 리포트 기능을 사용할 때 차감되는 앱 내부 재화다. 이런 기능에서 가장 조심해야 할 것은 네트워크 재시도 때문에 같은 요청이 두 번 처리되는 일이다.

분석은 실패했는데 찰떡만 빠지거나, 버튼을 두 번 눌러 두 번 차감되면 사용자 신뢰가 바로 흔들린다.

idempotency key를 기준으로 거래를 찾다

큐브 거래에는 idempotency key를 붙인다. 같은 행동에서 온 요청이라면 이미 처리된 거래가 있는지 먼저 확인하고, 새 거래를 만들지 않는다.

모바일 쪽에서도 spend, grant, refund 요청에 같은 기준을 넘길 수 있게 했다. 서버와 클라이언트가 같은 중복 방지 언어를 쓰는 셈이다.

잔액 부족은 오류가 아니라 상태다

찰떡이 부족한 상황은 서버 오류가 아니다. 사용자가 다음 행동을 선택해야 하는 상태다. 그래서 spend API가 409 또는 부족 코드를 돌려주면 모바일은 insufficient 상태와 필요한 수량, 현재 잔액을 함께 받는다.

이렇게 하면 화면은 실패 알림만 띄우는 대신 충전이나 다른 행동으로 이어질 수 있다.

환불까지 같은 기준으로 본다

분석 흐름에서는 차감 후 실패가 생길 수 있다. 그래서 refund API도 referenceId와 idempotencyKey를 기준으로 중복 환불을 막을 수 있게 했다.

재화 시스템은 차감만 만들면 끝이 아니다. 적립, 차감, 부족, 환불, 거래 내역이 모두 같은 기준으로 이어져야 운영할 수 있다.

Keep reading

다른 글 이어서 보기

전체 글 보기