결제 시스템 구현

"토스페이먼츠 연동은 생각보다 어렵다"

by 제임스

오늘은 제임스컴퍼니 프로젝트를 진행하면서 가장 긴장했던 부분 중 하나인 결제 시스템 구현에 대해 이야기해보려고 합니다. 특히 토스페이먼츠를 연동하면서 환경별로 겪었던 복잡성과 보안 이슈들을 공유하겠습니다.


결제 시스템, 왜 이렇게 어려운 거야?

처음엔 단순하게 생각했습니다. "API 문서 보고 따라하면 되겠지?" 하지만 실제로 구현해보니 고려해야 할 것들이 산더미였죠.

환경별로 다른 키 관리

보안 정책 준수

결제 실패 시나리오 처리

웹훅 검증

트랜잭션 정합성

무엇보다 실제 돈이 오가는 시스템이다 보니, 작은 실수 하나가 큰 문제로 이어질 수 있다는 부담감이 있었습니다.


토스페이먼츠 키 관리의 복잡성

1. 세 가지 환경, 세 가지 설정

처음부터 환경별로 키를 분리했지만, 그 과정이 생각보다 복잡했습니다.


"왜 개발 환경을 둘로 나눴냐고요?" 로컬과 Vercel 개발 환경에서 서로 다른 웹훅 URL을 사용해야 했거든요. 토스페이먼츠 대시보드에서는 테스트 키당 하나의 웹훅 URL만 설정할 수 있어서, 결국 개발용 테스트 키를 두 개 만들어야 했습니다.


2. Frontend와 Backend 키의 역할 분리

클라이언트 키와 시크릿 키를 적절히 분리하는 것도 중요했습니다.


3. Vercel 환경 변수 설정의 함정

Vercel Dashboard에서 환경 변수를 설정할 때 겪었던 이슈가 있었습니다.

"어? 분명히 환경 변수 설정했는데 왜 안 되지?"

알고 보니 Vercel은 환경별로 변수를 다르게 설정할 수 있는데, Production, Preview, Development 각각에 대해 별도로 설정해야 했습니다. 게다가 변수를 추가한 후에는 재배포를 해야 적용된다는 것도 뒤늦게 알았죠.


웹훅 검증 - 믿을 수 있는 요청인가?

1. 웹훅 URL 환경별 설정의 어려움

토스페이먼츠에서 결제 상태가 변경되면 웹훅을 통해 알려줍니다. 하지만 환경별로 다른 URL을 설정하는 게 생각보다 까다로웠습니다.

로컬 개발 시에는 ngrok을 사용했는데, URL이 계속 바뀌어서 매번 토스페이먼츠 대시보드에서 수정해야 하는 번거로움이 있었습니다.


2. 웹훅 시그니처 검증 구현

웹훅 요청이 정말 토스페이먼츠에서 온 것인지 검증하는 로직을 구현했습니다.


결제 실패 시나리오와 롤백 처리

1. 다양한 실패 케이스 처리

결제 과정에서 발생할 수 있는 다양한 실패 상황을 처리해야 했습니다.


2. 부분 취소와 전체 취소

토스페이먼츠는 부분 취소도 지원하는데, 이를 처리하는 로직도 구현해야 했습니다.


3. 동시성 문제 처리

같은 주문에 대해 동시에 여러 요청이 들어오는 경우를 처리해야 했습니다.


테스트 전략과 모니터링

1. 테스트 카드 번호 활용

토스페이먼츠는 다양한 테스트 시나리오를 위한 카드 번호를 제공합니다.


2. 결제 모니터링 대시보드

결제 상태를 실시간으로 모니터링할 수 있는 내부 대시보드를 만들었습니다.


토스페이먼츠를 선택한 이유

여러 PG사를 검토했는데, 토스페이먼츠를 선택한 결정적인 이유들이 있었습니다.

1. 개발자 경험 (DX)

명확한 API 문서: 각 상황별 예제 코드가 잘 정리되어 있음.

상세한 에러 메시지: 디버깅이 쉬움.

테스트 환경: 다양한 시나리오를 테스트할 수 있는 카드 번호 제공


2. 1인 개발자에게 적합

간단한 가입 절차: 사업자등록증만으로 즉시 테스트 가능

합리적인 수수료: 소규모 거래에도 부담 없는 수수료

빠른 정산: D+2 정산으로 현금 흐름 관리 용이


3. 기술적 장점

Webhook 재시도: 실패 시 자동 재시도

멱등성 키: 중복 결제 방지

상세한 거래 내역: 디버깅과 고객 지원에 유용

물론 아쉬운 점도 있었습니다. 예를 들어, 테스트 환경에서 웹훅 URL을 여러 개 등록할 수 없어서 환경별로 키를 분리해야 했고, 부분 취소 시 수수료 정책이 좀 복잡했죠. 하지만 전반적으로는 매우 만족스러웠습니다.


QA 관점에서 배운 것들

이번 결제 시스템 구현을 통해 QA 엔지니어로서 새로운 관점을 얻었습니다.


1. 환경별 테스트의 세분화

로컬: 모킹을 통한 단위 테스트

개발: 테스트 카드를 이용한 통합 테스트

스테이징: 실제와 동일한 플로우 테스트 (테스트 키 사용)

운영: 소액 실거래 테스트 후 즉시 취소


2. 엣지 케이스의 중요성

결제 도중 브라우저 종료

네트워크 불안정으로 인한 타임아웃

동시 결제 시도

결제 성공 후 웹훅 실패


3. 로그와 모니터링의 가치


결제 시스템 구현은 정말 어려웠지만, 그만큼 많은 것을 배울 수 있었습니다. 특히 "실제 돈이 오가는 시스템"이라는 무게감이 더 신중하고 체계적으로 접근하게 만들었죠.

QA 엔지니어로서 이런 경험은 정말 값진 것이었습니다. 이제 결제 관련 이슈가 발생했을 때,

어느 지점에서 실패했는지 빠르게 파악 가능

필요한 로그가 무엇인지 정확히 알 수 있음

재현 방법을 체계적으로 구성할 수 있음


다음 편에서는 JWT와 OAuth를 함께 사용하면서 겪었던 인증/인가 시스템의 복잡성에 대해 이야기해보겠습니다. 특히 환경별로 다른 OAuth 리다이렉트 URL 설정과 JWT 토큰 관리의 어려움을 공유할 예정입니다.

여러분도 결제 시스템을 구현하실 때는 충분한 테스트와 모니터링을 준비하시길 바랍니다.

그리고 무엇보다, "환경별 키 관리"에 각별히 신경 쓰세요.

keyword
이전 09화의존성 관리의 이중고