[Django] 내가 생각한 비즈니스 모델에 카카오페이 API 적용해보기 | Part 1. 결제 흐름의 이해와 서비스에 필요한 DB 설계 (feat. 관광데이터 활용 공모전)

Chanjong Park
Chan’s Programming Diary
10 min readNov 1, 2021

약 3개월 전에 카카오한국관광공사에서 진행하는 관광데이터 활용 공모전에서 1차 서류 합격을 얼떨결에 해버렸다.

물론 이 과정에서 열심히 기획을 해주신 디자이너, 기획자 분들 덕분이 컸지만 산기요 면접준비외주개발을 하느라 정신이 없었던 나는 서류제출 후에는 완전히 까먹고 지내고 있었다.
(사실 서류제출 과정에 디자이너 분들이 워낙 이쁘게 디자인을 해주셔서, 개인적으로 붙었으면 하는 마음이 크긴 했다.)

각설하고 일단 붙었으니 개발을 해야겠지 하는 마음에 바로 작업을 시작하게 되었다.

나는 서버 배포와 백엔드 API 개발을 맡았고, 같이 협업할 백엔드 한분과 안드로이드 개발자 두분과 협업을 진행했다.

나름 디자이너, 기획자 분들과 협업하는 개발이기 때문에 생각보다 신경써야 할 부분들이 많았다. 이 부분에 대한 고찰은 시간이 나면 나중에 포스팅 하도록 하겠다.

내가 맡은 파트중에 제일 신경을 썼던 부분은 바로 글에서 소개할 결제 부분이다. 실제 출시를 목표로 개발하고 있고, 우리 서비스의 BM(Business Model)도 있기 때문에 결제 기능이 필수적이었다.

어차피 위 공모전의 심사 조건에서 API 활용 범위에 카카오페이 API도 포함되어 있고, 서류에서도 카카오페이를 사용한다고 적어서 우리는 카카오페이 API를 사용하여 결제 시스템을 적용하기로 했고, 내가 맡아서 개발을 하게 되었다.

이 글에서는 우리 서비스의 BM인 유료 포스트와 연동하여 카카오페이 API를 적용한 과정에 대해 설명할 것이기 때문에, 이해를 위해 간단한 서비스 로직과 관련된 테이블들을 같이 소개할 예정이다. 서론이 길어졌으니 바로 시작해 보도록 하자.

카카오페이 API 흐름

우선 카카오페이 결제의 흐름이 어떻게 진행되는지 파악해보자.
전체적으로 카카오 API에 대한 문서가 감동적으로 잘 되어있기 때문에 이해하는 데 크게 어려움은 없을 것이다. 하지만 필자는 살짝 어려움을 겪었기 때문에 핵심부분만 정리하고자 한다.

출처 : https://developers.kakao.com/docs/latest/ko/kakaopay/common

좀 더 자세하게 살펴보자면 Server Side와 Client Side 두 가지 입장에서 살펴볼 수 있다. (Sever Side를 중점적으로 보면 이해에 도움이 될 것이라고 생각한다)

Server Side

카카오페이 API는 크게 결제 준비결제 승인 API가 있다.

결제준비 단계에서는 주문번호(partner_order_id), 가격(total_amount) 등의 결제를 위해 필요로 하는 정보들을 다루고 있고, 성공하면 응답 값으로 결제 고유번호(TID),클라이언트에서 웹뷰로 제공할 Redirect URL을 받게 된다. 그리고 서버에 TID를 저장하되 Redirect URL(결제 대기화면)은 클라이언트에 전달한다.

실제 테스트로 응답받은 값들이다. TID를 포함한 제공하지 않은 플랫폼의 url이나 scheme은 안드로이드에 전달하기 전에 빼는게 좋다.

서버로부터 Redirect URL을 잘 전달받아 사용자가 결제수단을 선택하여 결제완료 버튼을 누르면 요청 결과값에 따라 요청 성공, 요청 취소, 요청 유효시간 경과 3가지의 경우로 서버에게 정의한 Callback URL로 응답을 전달한다.

만약 요청 성공으로 Callback이 들어왔다면, Query String으로 pg_token(결제승인에 필요한 토큰)이 함께 들어오고 결제 승인 API를 진행할 수 있다.

결제 승인 API에서 최종적으로 완료가 되면, 결제 수단(payment_method_type), 결제금액 정보(amount), 결제카드 정보(card_info) 등 결제 완료에 대한 정보들을 응답값으로 전달받고, 클라이언트 에서는 결제 완료 화면을 보여주게 된다. 여기서 자세하게 확인할 수 있다.

글이 좀 난잡할 수 있어 정리하자면

  1. 결제준비 API
  • 결제에 필요한 정보들(주문번호, 총 가격, 수량 등)을 담아 카카오 서버에 API 요청을 한다.
  • 응답값으로 TID(결제 고유번호), Redirect URL, App Scheme(결제수단을 확인하기 위한 카카오톡 Scheme)을 받고, TID는 데이터베이스에 저장하되 나머지 필요한 정보(redirect url, scheme)는 클라이언트에게 전달한다.

2. 결제승인 API

  • 앞서 전달받은 URL과 Scheme에서 결제수단을 선택하고 결제완료 버튼을 누를 시, 결과에 따라 3가지(성공, 실패, 유효시간 만료)의 상태로 각각 서버에서 설정한 Callback URL로 전달받게 된다.
  • 성공으로 Callback이 들어왔을 시, Query String으로 pg_token(결제 승인시에 필요한 토큰)이 함께 들어오고, pg_token과 함께 TID 및 결제 정보들을 담아 결제 승인 API에 요청한다.
  • 결제 승인까지 완료 시 결제 완료된 정보(사용자 결제 타입, 카드면 카드정보 등)를 받게 되고, 클라이언트 에서는 결제 완료 창을 띄워주게 된다.

Client Side

우리가 개발한 앱에서 제공하는 하단바의 결제하기 버튼이다.

먼저 사용자에 의해 위 사진처럼 결제하기 버튼 등의 이벤트가 발생하면, 준비하기 API와 연동되어 있는 서버로 콜을 한다. 성공 시에 전달받은 Redirect URL(결제 대기화면)을 웹뷰로 띄워주고, Android Scheme을 자동 호출하여 결제수단 선택 창으로 이동한다.

실제 앱에서 결제하기 버튼을 누른 후에 연결된 화면이다. 테스트이기 때문에 화면이 조금 다름을 유의하자.

결제하기 버튼을 눌러서 성공하게 되면, 서버에서 설정한 성공 Callback URL로 리다이렉트된다. 리다이렉트된 URL에서는 결제승인 API가 내부적으로 호출되며, 승인 후 대기 화면에서 결제완료 창을 누르면 결제가 완료된다.

결제완료 후의 카톡 알람이다. 테스트이기 때문에 실제 결제와는 문구가 다를 수 있다.

이 일련의 과정에서 우리가 해야 할 작업은 각 API 호출에 정확한 값들을 담는 것 뿐만 아니라 각 요청, 응답에 대해 필요한 정보를 데이터베이스에 매핑하는 것이다.

결제 흐름에 대해 어느정도 파악했다면, 필자가 설계한 테이블의 간단한 설명과 함께 결제DB 설계로 넘어가보자.

BM(Business Model) 부연설명

결제에 관한 DB를 설명하기에 앞서, 우리가 만든 서비스에서는 어떠한 목적으로 결제를 진행하는지, 그 목적에 대한 테이블은 어떻게 설계되어 있는지 간단하게 설명해보고자 한다. 이해를 돕기 위한 부연설명이기 때문에 간단하게 훑어보거나 스킵하자.

우리가 채택한 Business Model은 앞서 말했듯이 유료 포스트이다. 앱의 컨셉이 차박, 캠핑과 관련되었기 때문에 골수 차박러와 캠핑러들이 나만 알고 있는 꿀팁을 포스팅하여 필요한 유저가 구매를 하는 방식이다.

아래는 실제 작성했던 ERD를 참고하여 포스트 부분만 보기쉽게 재구성해 보았다. 잘 안보일 수 있지만, 서비스의 각 테이블에 대한 관계의 이해를 돕기 위한 사진이니 양해 바란다.

작성 툴 : draw.io

UserPost를 부모 테이블로 두고 실제 포스트의 내용만 담았으며, 부가적인 정보 부분은 UserPostInfo 테이블에 담아서 개발했다.

실제로 사용자(User)가 결제를 완료하면, User와 UserPost가 ManyToMany로 연결된 테이블에 저장되어 접근 권한을 가질 수 있게 된다.

정리하자면

  • UserPost는 실제 글의 내용이 담긴 테이블
  • UserPostInfo는 부가적인 정보(가격, 유/무료 여부, 작가소개 등)가 담긴 테이블
  • 결제 완료 시, User와 UserPost는 ManyToMany에 저장(저장된 사람만 포스트 접근가능)

결제내역 테이블 생성

어떠한 서비스를 위해 결제 시스템을 개발 하는지 파악이 되었다면, 결제 시 필요한 정보들을 담는 테이블을 만들어 보자.

카카오페이 API의 흐름이 전체적으로 결제 요청, 승인 두 개로 나뉘어져 있기 때문에, 두 개의 테이블을 설계하였다. 아래 표를 참고해보자.

UserPostPaymentRequest(결제준비 내역 테이블)은 UserPost를 참조하고 있다.

각각의 단계(준비, 승인)에서 결제내용에 필요한 정보들만 선별하였다. 특정 유저가 결제를 했다는 기록을 꼭 남길 필요가 있기 때문에, 신중히 설계하자.

(사실 주문 결제 고유번호로 카카오페이 서버에서 주문조회가 가능하긴 하지만, 신중해서 나쁠건 없다.)

UserPostPaymentRequest

  • user_id : 구입하려고 하는 유저
  • total_amount : 구매 물품 총액(비과세 포함)
  • tax_free_amount : 상품 비과세 금액
  • vat_amount : 상품 부가세 금액
  • tid : 결제 고유번호(결제 준비 완료 시 서버에 저장)
  • status : 결제요청 상태(대기중, 성공, 실패, 취소)

UserPostPaymentApprovalResult

  • payment_request_id : 위의 요청 테이블을 참조
  • aid : 요청 고유번호(결제 고유번호와 다르니 주의하자)
  • payment_type : 결제수단(카드 or 현금)
  • total_amount : 결제 금액 정보(amount)에서 가져온 전체 결재금액(total)
  • card_info : Django Model의 TextField로 따로 구분없이 JSON을 String으로 저장함
  • item_name : UserPost의 title(제목)
  • ready_requested_at : 결제 준비요청 시간
  • approved_at : 결제 승인완료 시간

앞서 장황하게 설명한 내용과는 달리 테이블 생성 자체는 큰 어려움이 없었다.

사실 카카오페이 결제흐름의 부연설명부터 BM 소개까지 투머치 하게 글을 작성할 필요가 있었나 싶었지만,

이후에 필자가 작성한 코드를 하나하나 설명할 때, 무엇 때문에 코드를 작성했는지 미리 설명할 필요가 있다고 생각했다. (서비스의 홍보도 사실 있다)

앞서 말했듯이 공식 문서가 매우 잘 나와있기 때문에, 문서를 읽고 어느정도 이해가 된다면 실제 코드를 살펴보는 다음 포스트로 넘어가도 좋다.

다음 포스트에서는 준비부터 승인까지의 과정을 코드로 살펴보고, Callback URL에서 어떻게 결제내역 테이블을 매핑하는지까지 살펴보겠다.

코드

참고

카카오페이 이해하기 | Kakao Developers 문서

[게르만 민족 프로젝트]Django로 카카오페이 API 사용하기

Django와 Vue를 이용한 카카오페이 API

--

--