---
# System prepended metadata

title: 결제 서버

---

# 결제 서버
### Dependency
- 기본적인 의존성은 build.gradle 참고
### 기능 종류
1. 충전 기능
  - 카카오페이 결제를 이용한 잔액 충전 기능
2. 게임 구매 기능
  - 게임을 구매하는 기능
### 충전 기능
카카오페이 API(테스트 버전)를 이용해 충전 구현
MySQL DB에 상품권 정보를 등록해놓고 카카오페이 결제를 통해 구매하는 방식
![](https://i.imgur.com/5eZOb2I.png)

- **프로세스**
  - 충전 준비 API
    - 카카오페이 결제 준비 API 요청
    - 결제 관련 데이터 Redis 캐싱
  - Web Response로 QR코드 전송
    - 유저가 브라우저에 띄어진 QR코드를 이용해 카카오페이로 상품권 결제
      - `결제 성공` , `실패` , `취소`
  - 결제 성공 시 결제 승인 API
    - 카카오페이 결제 승인 API 요청
    - 실제 DB의 유저 충전 트랜잭션
      - 트랜잭션 실패 시 카카오페이 결제 취소 API 요청


### 게임 구매 기능
장바구니에서 게임을 선택해서 게임 구매 API 호출
- **프로세스**
  - 요청한 게임의 가격, 할인 정보를 DB의 실제 게임 정보와 비교
    - 게임을 장바구니에 넣고 구매하는 사이에 배급사가 정보를 바꿀 경우, 할인율이 이벤트로 바뀔 경우를 대비
  - 요청한 게임의 총 가격과 유저가 소유한 잔액 비교
    - 유저가 소유한 돈에 따라 프론트에서 요청 불가 처리를 하지만 변조 가능성이 있어 이 경우를 대비
  - 이미 구매한 게임인지 구매 목록(라이브러리)을 조회하여 비교
  - 게임 구매 트랜잭션
    - 각 배급사에 게임 금액만큼 돈 입금
      - 배급사의 계좌는 여러 유저에게서 입금 트랜잭션이 일어날 수 있기 때문에, SELECT FOR UPDATE를 통해 갱신 분실 문제를 예방하고 정합성을 보장
    - 유저 잔액 차감
    - 라이브러리에 게임 추가
  - 구매한 게임을 위시리스트에서 삭제

### 로깅
결제와 관련된 부분은 신뢰성이 매우 중요하다고 생각해서 느려지더라도 로그를 꼼꼼히 남기려고 했습니다.

로깅이 실패했을 때, 비즈니스 로직까지 실패 처리를 해야할지 고민을 했는데, 로깅 자체도 중요하다고 생각해서 전체 실패로 처리하기로 했습니다. 이러한 이유 때문에 기존에 메세지 브로커나 Spring Stream을 이용해 로깅 시스템을 따로 분리시키려고 했지만, 하지 않게 됐습니다.

내부 트랜잭션의 경우 실패했다고 해서 로깅이 롤백되면 안되기 때문에, 트랜잭션 범위를 정확히 잡으려고 했습니다.

- **로깅 내용**
  - `결제 방법`
  - `요청 정보`
  - `잔액 변화`
  - `상태`
  - `시간`
- **충전**
  - `충전 요청`
  - `충전 승인`
    - 카카오페이 승인 요청
    - 카카오페이 승인 성공
    - 트랜잭션 성공
  - `충전 취소`
    - 카카오페이 승인 취소
- **게임 구매**
  - `게임 구매 준비`
  - `게임 구매 성공`

### 고민
- 내부적으로 긴 로직에 대한 처리
  - 기존에는 신경쓰지 않던 트랜잭션의 범위, 연결의 점유 시간을 고민하게됨
- 로깅 시점, 내용 고민
  - 기술적으로는 평범하지만 서비스적인 측면에서 어떤 부분을 보장해주고, 얼마나 신뢰성 높게 설정해야되는지 고민하게됨
- 외부 API와의 연동
  - 현재 외부 API를 사용하지 않는 서비스는 없다고 생각하는데, 외부 API와의 연동 프로세스를 이해하게 됨
- DB의 정합성 오류까지 고려한 로직 & 설정
  - 단순히 하나의 요청에 대해 기능적으로 잘 돌아가냐를 넘어서서 여러 요청이 동시에 들어왔을 때, 문제 없이 돌아가는지를 고려하여 개발하게 됨

### 발전 가능한 기능
- 구매할 게임들의 정보를 통해 충전과 구매를 동시에 진행하도록 수정
  - 서비스적으로 유저들에게 이 방식이 편함 