커리큘럼
home
React
home

장바구니 / 결제 / 환불

Created
2025/02/03 06:10
Tags

강의 장바구니, 결제와 환불 기능 구현

장바구니 기능

관심 있는 강의의 기수를 확인하여 해당 기수를 장바구니에 추가할 수 있습니다. 장바구니 추가 후 장바구니 목록을 확인할 수 있게 해당 페이지로 이동하게 됩니다.
웹 사이트 상단의 장바구니 아이콘을 통해서도 장바구니 목록에 접근 할 수 있습니다.
장바구니 페이지에서는 장바구니 삭제와 결제가 가능합니다.

결제 기능

결제 기능은 토스 페이먼트를 사용하여 진행됩니다.
장바구니에서 결제 요청을 하면 결제가 진행됩니다.
클라이언트의 결제 요청 - 카드사 인증 - 토스 페이먼트 결제 승인 요청 - 백엔드의 승인 결과 처리의 과정을 거쳐 결제 로직이 수행됩니다. 결제 승인의 결과를 토스 페이먼츠에서도 확인 할 수 있습니다.
정상적으로 결제 요청이 처리되면 결제 완료 메시지와 함께 구매한 강의의 목록으로 갈지, 결제 정보 목록으로 갈지 선택할 수 있습니다.
강의 목록에 결제한 강의가 추가 되었음을 알 수 있습니다.
결제 목록에서는 결제 정보 조회와 환불 기능을 제공하며 상세 정보를 통해 결제한 강의의 정보를 볼 수 있습니다.

환불 기능

위에서 볼 수 있듯 결제 목록에서는 각각의 결제 건에 대해 환불을 진행할 수 있습니다.
현재 기준 수업 시작 전 하루 전까지 환불이 가능합니다.
환불 성공 시 해당 결제는 목록에서 제거됩니다.
토스 페이먼츠에서도 정상적으로 환불 처리되었음을 확인할 수 있습니다.

Background Task

유효성 검사
장바구니 추가 시 추가할 강의의 유효성, 보유 여부, 모집 기간, 장바구니 추가 여부를 바탕으로 유효성 검사를 합니다.
결제 요청 시 한 번 더 유효성 검사를 거칩니다. 결제할 강의의 유효성, 보유 여부, 모집 기간, 해당 강의의 정원 초과 여부, 결제할 강의 간 or 수강 중인 강의 간의 요일과 시간의 동시성 여부를 바탕으로 유효성 검사와 에러 처리를 합니다.
결제 로직
결제는 클라이언트에서의 구매 요청 - 카드사 인증 - 결제 승인 요청 - 카드사 결제 승인 - 결제 결과 DB 반영의 흐름으로 이어집니다.
주문한 품목의 id들을 구매 요청 시 결제 로직에 포함해 결제 결과 처리 시 금액에 대한 유효성 검사를 한 번 더 거쳐 문제 시 결제 취소를 하고, 성공 시 DB에 반영합니다.
결제 승인이 성공적으로 이루어진 후 DB에 반영하는 트랜잭션 과정 도중 문제가 발생하면 결제 취소를 요청하는 로직을 포함했습니다. 이를 통해 서버 문제시 결제는 정상적으로 진행되고 강의는 구매되지 않는 문제를 해결하였습니다.
동시성 처리
강의 정원이 정해져 있어 동시에 결제 처리가 되면 DB에 반영될 경우 문제가 발생할 수 있어 결제 과정에서 동시성 처리를 고려해야 했습니다. 동시성 처리를 위해 Redis/BullMQ 라이브러리를 사용했습니다.
Redis/BullMQ 사용 이유
작업 큐 시스템
BullMQ는 작업 큐 시스템으로, 결제와 관련된 각 작업을 큐에 넣고 순차적으로 처리할 수 있습니다. 이를 통해 여러 결제 요청이 동시에 들어오더라도 작업이 중복되거나 누락되지 않도록 처리할 수 있습니다.
높은 처리 성능
BullMQ는 Redis 위에서 동작하기 때문에 빠른 읽기/쓰기 성능을 제공합니다. 이는 대량의 결제 요청이 동시에 발생하는 상황에서도 빠르고 효율적으로 작업을 처리할 수 있게 해줍니다.
확장성
BullMQ는 Redis의 분산 시스템을 기반으로 하여 쉽게 확장할 수 있습니다. 추후 서비스가 확장되어 더 많은 트래픽과 동시성을 처리해야 할 때 worker를 추가하여 부하를 분산시킬 수 있습니다.
간편성
다른 메시지 큐 시스템들과 비교하여 쉽게 설정하고 관리할 수 있습니다. Node.js 환경, 서비스의 크기를 생각했을 때 기본적인 기능들을 간편하게 구현할 수 있고, 서비스 확장 시에 추가적인 기능도 사용할 수 있어 BullMQ를 선택했습니다.

관련 트러블 슈팅

문제 1:
결제 요청 - 카드사 인증 - 결제 승인 요청 - 카드사 결제 승인 - 백엔드의 승인 결과 처리로 이어지는 로직에서 결제는 처리되지만, DB의 결과 처리 과정이 제대로 이루어지지 않는 경우가 발생했습니다.
원인 분석 :
결제 승인이 성공한 후 트랜잭션 처리 중 에러가 발생하는 경우, 결제는 정상 처리되지만, DB에는 해당 결제 데이터가 적절하게 반영되지 않는 것이 원인이었고 이로 인해 토스 결제 부분과 DB의 결제 정보 간의 불일치가 발생했습니다.
해결 :
결제 승인 이후 트랜잭션이 실패하면, 승인된 결제를 자동으로 환불하는 로직을 추가했습니다. 이를 통해 결제 승인과 데이터베이스 업데이트 사이에 문제가 발생할 경우, 결제를 취소하여 시스템 상태를 일관성 있게 유지할 수 있었습니다. 이를 위해 트랜잭션 내에서 승인 요청을 처리하고, 승인 성공 후 발생하는 모든 에러에 대해 일관된 롤백 또는 보정 작업을 수행할 수 있도록 구조를 개선했습니다
문제 2 :
프로젝트의 결제 처리 로직에서 초기에는 결제 요청 전에 직접 orderId를 생성하고, 이 orderId를 기준으로 결제 정보를 미리 DB에 저장하고 결제 요청 시 비교하여 유효성 검사를 수행한 후, 결제 승인 요청을 진행했습니다.
그러나 버블로 프론트엔드를 작업하면서 토스(Toss)에서 제공하는 버블 결제 플러그인을 사용하는 것으로 결정했는데 플러그인을 사용하면 기존의 결제 로직을 그대로 사용할 수 없는 문제가 발생했습니다.
원인 분석
토스에서 제공하는 버블 플러그인은 결제 요청 시에 orderId를 자동으로 생성하도록 설계되어 있어, 개발자가 요청 전에 직접 orderId를 생성할 수 없는 문제가 있었습니다. 이는 기존 로직에서 필수적으로 사용하던 orderId 기반의 유효성 검사 방식, DB에서의 결제 처리 로직과 충돌을 일으켰습니다.
해결 과정 :
문제 분석 및 해결 방안 탐색: 처음에는 공식 문서와 다양한 온라인 자료를 통해 문제 해결 방법을 찾으려고 했습니다. 하지만, 버블 플러그인에 대한 정보는 많지 않았고, 문제를 해결할 만한 정보를 얻지는 못했습니다.
커뮤니티 및 개발자 소통: 문제 해결에 필요한 정보를 찾는 데 한계가 있었기에, 결국 토스 개발자 커뮤니티에 이슈를 제기하기로 했습니다. 문의한 결과, 토스 개발자로부터 플러그인의 편의성을 위해 orderId는 자동으로 생성되며, 직접 설정할 수 있는 옵션이 따로 제공되지 않는다는 답변을 받았습니다.
대체 방안 모색 및 구현: 기존 로직을 그대로 유지할 수 없었기에, 대체 방안을 모색했습니다. 토스 플러그인이 제공하는 기능과 제한 사항을 감안하여, orderId 대신 orderName 필드를 활용하기로 했습니다. 구체적으로는, 요청 전에 클라이언트 측에서 컨트롤할 수 있는 orderName에 결제 품목의 ID를 포함해, 이 값을 기준으로 결제 요청 정보의 유효성을 검사하고, 결제한 품목들을 추적하여 토스 결제 승인 이후에 DB 처리를 할 수 있도록 로직을 변경했습니다.
이를 통해 결제 프로세스의 유효성 검사를 유지하면서도, 토스 플러그인의 구조적인 제한 사항에 맞춘 새로운 로직을 구현할 수 있었습니다.