재화(코인)에 대한 기술 가이드

개요

배경

  • 게임에서 유저는 결제 또는 인게임 컨텐츠 및 운영 지급 등을 통해서 재화(보석, 골드, 젬과 같은 코인류)를 습득 및 사용할 수 있습니다.

    • 예) 각 결제 스토어에서 현금 결제, 게임 미션 달성 보상지급, 운영에서 출석 보상으로 우편함에 코인 지급

  • 이러한 재화는 유저가 어떤 방식으로 획득했는지를 구분해서 저장 및 관리 되어야하며 정책에서 정한 데로 차감되어야합니다.

    • 유저 환불이 필요할 때 유료 코인의 잔액만 확인이 가능해야 환불 금액을 산정 가능합니다.

    • 일본 자금 결제법arrow-up-right에서는 일정 주기로 유료 잔액을 확인하고, 일정 금액 이상이라면 공탁금을 입금 해야 합니다.

    • 회계 규칙에 의해서 재화의 잔고 확인 및 증/차감 추적이 가능해야 합니다.

    • 일부 국가에서는 소비자 보호 등의 이유로 차감 순서가 틀릴 수 있습니다.

    • 정책 및 법은 변경될 수 있기에 개발은 가능하면 외부 변경에 유연하게 대응 할 수 있도록 설계 및 개발되면 좋습니다.

  • 게임 운영 과정에서 회수 기능이 필수입니다. 이때 유저의 코인 잔액은 음수가 될 수 있으니 꼭 감안하여 설계되어야 합니다.

    • 예) 게임 버그 등으로 재화 회수 → 이미 사용한 유저에게는 음수 값으로 차감(DB 음수 지원되는 sigined 타입 사용) → 유저가 결제 등으로 코인이 양수가 되면 정상 이용 가능(게임 내 UI에 음수 표시도 가능 해야함)

가이드의 한계

triangle-exclamation
circle-info

총 2가지의 코인 관리 DB 설계를 제공하니 게임 특성에 따라 알맞은 방법을 골라 참고하여 DB 설계 부탁 드립니다.

코인 충전 형태에 따른 코드 정의

코드 정의 표

  • 오타 등의 문제로 실수 가능성이 높은 상황에서는 가능하면 영문 코드를 사용

    • 예) API 통신에는 영문 코드로 통신하고 DB에 저장할 때는 맵핑 정의에 따른 숫자 포맷으로 저장해서 DB 인덱스 사이즈를 줄임

      • 정합성 보장 등을 위해서 PK나 유니크 인덱스에 숫자 포맷 값으로 인덱스를 생성해두시는게 좋습니다.

영문 코드
이름
숫자포맷
재무(회계) 유료 여부
일본 자금결제법상 유료 여부
설명

PAID

유료

1

유료

유료

유저가 실제 돈을 주고 구입한 재화로 보너스는 제외

PAID_BONUS

유료의 보너스

2

무료 (정책 변경될 수 있음)

무료

유저가 구입한 유료 코인에 덤으로 주는 보너스(자금결제법에서는 무료 처리해도 무방, 공탁금 줄일 수 있음)

PAID_INVEN

유료인데 상품 보관함 용

7

유료

무료

상품 보관함에서 임시로 지급되는 유료 재화

PAID_INVEN_BONUS

유료의 보너스인데 상품 보관함 용

8

유료

무료

상품 보관함에서 임시로 지급되는 덤 코인, 보너스 코인

FREE_BUY_PRODUCT

무료 상품 구매

14

무료

무료

회계 및 자금결제법상 무료로 관리되는 '권리' 형태의 상품을 구입 후 충전할 때 사용 ' - 예) 로그인하면 무료 코인을 주는 상품 구입 -> 게임에서는 내일 로그인하면 해당 타입으로 코인 충전(단, BM에 구매 즉시 지급되는 코인을 추가하고 해당 코인은 유료으로 처리)

FREE_AD

무료 광고

19

무료

무료

광고로 발생한 무료 재화. ' - 예)유니티 또는 구글 광고 SDK를 붙여서 BM을 준비할때. 광고를 보면 코인을 지급

FREE_OP

무료 운영

21

무료

무료

푸시 및 쿠폰, 로그인 보상 등의 이유로 내부 운영 목적상에서 충전된 코인

FREE_SVC

무료 서비스

25

무료

무료

게임내의 컨텐츠 요소로 발생한 충전된 무료 재화. ' - 예) 게임 던전 클리어시 무료 코인 지급

AUCTION_BIDDING

경매장 입찰용

31

무료

무료

경매장 입찰에 사용되는 임시 코인(낙찰 시점에 유/무료 처리 등 고민해야할 부분이 있음)

코인 차감 순서

  • 유료 코인을 먼저 차감합니다. 이용약관 10조 5항 3호에도 관련 내용이 명시되어 있습니다.(2023-11-28 기준)

    • 유료 코인을 먼저 차감하지 않는다면 게임 종료, 환불 등의 이슈가 발생하면 개발사 및 회사는 큰 손해를 입을 수 있습니다.

      • 예) 운영 성격의 코인이 많이 지급되었는데 무료을 먼저 사용하게 된다면, 유저의 유료(유료) 코인 잔액은 차감이 안되고 계속 남아있어서 모두 환불 금액에 포함되어야하는 문제가 발생

circle-info

이용약관 유료 먼저 차감한다는 내용 발췌

③ 회원이 구매한 아이템은 획득 방식에 따라 유/무료 속성으로 구분됩니다. 회원이 유/무료 속성의 아이템을 모두 보유하고 있고 일부를 사용하였을 경우, 유료 속성이 우선 차감되고, 그 이후 무료 속성이 차감됩니다. 유료 속성만 보유 시에 차감 순서는 선입선출 방식(먼저 획득한 순서대로 차감되는 방식)에 따릅니다. 단, 사정에 따라 다르게 적용될 수 있으며 이 경우 서비스 내 또는 커뮤니티, 홈페이지 등을 통해 공지합니다.

코인 관리 DB 설계(참고용) - RDBMS

  • 아래 예제는 Mysql 기준으로 참고를 위해서 안내드리는 수준의 내용입니다.

  • 해당 row(또는 column)외 필요하신 추가 내용을 적용하셔도 무방합니다.

  • 다만, 꼭 관련 테이블들은 트랜잭션으로 묶어서 정합성에 문제가 생기지 않도록 해야합니다.

    • 이때 외부 API 호출 등 응답이 느린 로직이 있다면 트랜잭션 lock time이 길어지고, 다른 유저가 해당 데이터를 변경해야하는 로직이 있다면 데드락에 빠질 수 있으니 주의

(권장)확장성을 고려해서 충전 타입을 행 형태로 사용한 설계

  • 장점: 정책 또는 법규 등이 변경되어도 DB에 alter를 수행하지 않아도 되는 확장성의 장점

  • 단점: 유저의 코인 잔액을 조회하거나 변경할 때 여러 row를 읽어야하며 동시성에 대해서 더 잘 고민해야 함

    • 아래 샘플 내용은 참고를 위한 테이블 설계 및 쿼리입니다. 상황에 맞춰서 테이블명과 컬럼명 변경, 인덱스 조정 등이 진행되어도 괜찮습니다. 다만 증/차감 누락이나 중복 충전 등 크리티컬한 문제는 주의해주세요.

테이블 DDL 샘플

참고용 쿼리 샘플

단순화된 열 형태의 설계

  • 여러 코인 충전 형태 중 필수인 일부 충전 방식에 대해서 컬럼 기반으로 관리

  • 1개의 행(DB row)에 충전 타입에 따른 컬럼을 개별적으로 추가해서 잔액을 관리

    • 유료, 무료, 유료 보너스 3가지 구분은 필수

    • 아래 샘플 내용은 참고를 위한 테이블 설계 및 쿼리입니다. 상황에 맞춰서 테이블명과 컬럼명 변경, 인덱스 조정 등이 진행되어도 괜찮습니다. 다만 증/차감 누락이나 중복 충전 등 크리티컬한 문제는 주의해주세요.

circle-info

개발은 쉽지만 확장성이 부족한 열(컬럼) 잔액을 관리하는 DB 설계

테이블 DDL 샘플

참고용 쿼리 샘플

  • row 방식 쿼리를 참고하되 charge_type에 대해서 행을 열로 변경한 부분을 고려해서 수정해서 사용

코인 관리 DB 설계(참고용) - NoSQL

단순화된 열 형태의 설계

  • 여러 코인 충전 형태 중 필수인 일부 충전 방식에 대해서 필드 기반으로 관리

  • 1개의 행(Document)에 충전 타입에 따른 필드를 개별적으로 추가해서 잔액을 관리

    • 유료, 무료, 유료 보너스 3가지 구분은 필수

    • 샘플 내의 내용은 참고를 위한 내용입니다. 상황에 맞춰서 컬렉션(필드 및 인덱스 등)은 변경되어도 괜찮습니다. 다만 증/차감 누락이나 중복 충전 등 크리티컬한 문제는 주의해주세요.

샘플 컬렉션 정의 - coin_balance

  • 유저의 현재 코인(재화)의 잔액을 관리하는 마스터 컬렉션

  • 재화의 증/차감 변경이 발생할 때마다 데이터가 insert 또는 update되어 저장되는 컬렉션

  • 코인 코드에 따라서 유저는 N개의 Document를 보유할 수 있음

<필드 정의>

필드
데이터 타입
설명

_id

object

자동 생성되는 objectIdarrow-up-right 필드로 개발자가 생성할 수도 있지만 일반적으로 드라이버에서 생성됨

6698b68bd8cd923a387c3572

player_id

string

플레이어ID(유저ID)

test_user

coin_cd

string

코인 종류(GEM 등)

GEM

balance_paid

number

유료 코인의 현재 잔액

5

balance_paid_bonus

number

유료 보너스 코인의 현재 잔액

3

balance_free

number

무료 코인의 현재 잔액

0

created_at

object

최초 저장 일시

ISODate("2024-07-18T06:43:44.099Z")

updated_at

object

변경일시(최초에는 저장될때와 같은 일시로 저장)

ISODate("2024-07-18T06:43:44.099Z")

상세 참고사항

컬렉션 정의 - coin_balance_hist

  • 유저의 재화 잔액 변경 이력을 저장하는 컬렉션

  • 재화의 증/차감 변경이 발생할 때마다 데이터가 insert되어 저장되는 컬렉션(Update가 발생하면 안됨)

<필드 정의>

필드
데이터 타입
설명

_id

object

자동 생성되는 objectIdarrow-up-right 필드로 개발자가 생성할 수도 있지만 일반적으로 드라이버에서 생성됨

6698b68bd8cd923a387c3572

req_id

string

요청ID(중복 요청 방어 목적 및 추적용)

uuid-player_id-balance-plus-01

player_id

string

플레이어ID(유저ID)

test_user

coin_cd

string

코인 종류(GEM 등)

GEM

player_country

string

유저의 국가정보(국가별 법률 준수 목적으로 필요시 저장)

KR

amount

number

증감되는 변경 양

5

balance_paid

number

유료 코인의 현재 잔액

5

balance_paid_bonus

number

유료 보너스 코인의 현재 잔액

3

balance_free

number

무료 코인의 현재 잔액

0

balance_change_type

string

잔액 변경 종류(증/차감)

  • PLUS 또는 MINUS

PLUS

reason

string

증감되는 사유

plus_test

memo

string

메모(필요시 저장)

memo_test

hist_created_at

object

이력저장일시

ISODate("2024-07-18T07:54:53.388Z")

<상세 참고 사항>

Last updated