콘텐츠로 이동

ZUKU Game Cloud

프로젝트 단위의 변수·세이브·지갑과 개발 중인 결제·함수 인터페이스를 제공합니다.

현재 지원 범위

변수·세이브 API와 별개로, Pay confirm은 외부 결제사나 영수증을 검증하지 않습니다. 실제 결제 완료 증빙으로 사용하지 마세요.

목차

  1. 개요
  2. 프로젝트
  3. Economy (지갑)
  4. Vars (클라우드 변수)
  5. Saves (클라우드 세이브)
  6. Pay (IAP)
  7. Functions (서버 함수)
  8. Cloud Billing
  9. 게임 전용 VM
  10. 대시보드

1. 개요

레거시 zuku v1 설명
ZCloud Economy /cloud/economy/balance POINT · CASH_KRW 지갑
ZVM /cloud/vars/* global/user 스코프 변수
ZASE /cloud/saves/* 버전드 세이브 슬롯
Pay /cloud/pay/* IAP 상품·세션·확인
WebFunc /cloud/functions/* 서버 함수 CRUD·invoke

인증: 모든 엔드포인트는 Authorization: Bearer <session_token> 필요.

Base URL: https://zuzunza.com/api/v1/cloud


2. 프로젝트

게임 클라우드는 프로젝트 단위로 격리됩니다.

프로젝트 생성

POST /api/v1/cloud/projects
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "내 RPG",
  "description": "온라인 멀티 RPG",
  "jump_content_id": "cnt_jump_abc123"
}

프로젝트 목록

GET /api/v1/cloud/projects
Authorization: Bearer <token>

3. Economy (지갑)

GET /api/v1/cloud/economy/balance?projectId=<uuid>
Authorization: Bearer <token>

응답:

{
  "success": true,
  "data": {
    "POINT": 1500,
    "CASH_KRW": 0
  }
}
  • POINT: 게임 내 재화
  • CASH_KRW: 지갑 잔액 필드. 실제 결제·환전·입금이 검증되었다는 뜻은 아닙니다.

4. Vars (클라우드 변수)

레거시 ZVM과 동일한 개념. currency scope는 클라이언트에서 변경 불가 (자기 mint 방지).

읽기

POST /api/v1/cloud/vars/get
Content-Type: application/json

{
  "projectId": "<uuid>",
  "scope": "user",
  "key": "high_score"
}

변경

POST /api/v1/cloud/vars/mutate
Content-Type: application/json

{
  "projectId": "<uuid>",
  "scope": "user",
  "key": "high_score",
  "op": "max",
  "num": 9999
}

op: set · incr · decr · max · min · cas

scope: global (전체 공유) · user (플레이어별)


5. Saves (클라우드 세이브)

레거시 ZASE. 인라인 JSON, 슬롯당 256KB 한도.

저장

POST /api/v1/cloud/saves/save

{
  "projectId": "<uuid>",
  "slot": "slot1",
  "data": { "level": 5, "inventory": ["sword", "potion"] }
}

로드

POST /api/v1/cloud/saves/load

{
  "projectId": "<uuid>",
  "slot": "slot1"
}

슬롯 목록

GET /api/v1/cloud/saves/list?projectId=<uuid>

6. Pay (IAP)

상품 목록

GET /api/v1/cloud/pay/products?projectId=<uuid>

구매 세션 생성

POST /api/v1/cloud/pay/session

{
  "projectId": "<uuid>",
  "productId": "<product-uuid>"
}

세션 TTL: 10분. status: pendingpaid (confirm 후).

결제 확인

POST /api/v1/cloud/pay/confirm

{
  "sessionId": "<session-uuid>"
}

7. Functions (서버 함수)

함수 소스를 등록하고 실제 Deno 런타임에서 실행합니다. 함수마다 네트워크가 분리되고 파일시스템은 최소 읽기 전용이며, 2초 실행 시간·128MiB cgroup 메모리·64 프로세스 상한을 적용합니다. Bubblewrap, Deno 또는 cgroup 위임이 없으면 실행을 거부합니다.

함수 등록/수정

POST /api/v1/cloud/functions

{
  "projectId": "<uuid>",
  "name": "grantReward",
  "sourceCode": "export default async function(input) { return { ok: true, input }; }"
}

함수 게시

POST /api/v1/cloud/functions/<id>/publish

{ "projectId": "<uuid>" }

함수 호출 (published 상태)

POST /api/v1/cloud/functions/<id>/invoke

{
  "projectId": "<uuid>",
  "input": { "amount": 100 }
}

8. Cloud Billing

GET /api/v1/cloud/billing/catalog
GET /api/v1/cloud/billing/account?projectId=<uuid>

API 요청, CPU-ms, RAM MB-ms, 디스크 GB-hours·읽기·쓰기, 동시 접속 분, KT/KR egress와 Global egress를 각각 계량합니다. 카탈로그의 rate_card_version, billing_unit, rate_krw로 비용을 계산하며 브라우저는 계량값을 제출할 수 없습니다.

유료 플랜에서 포함량을 넘기려면 프로젝트별 한도를 먼저 설정해야 합니다. 0은 초과 사용 차단입니다.

POST /api/v1/cloud/billing/limit

{ "projectId": "<uuid>", "spendLimitKrw": 50000 }

Cloud Free는 meter 하나라도 80%에 도달하면 완만한 QoS, 90%부터 강한 QoS가 적용되고, 100% 소진 후 다음 요청부터 차단됩니다.

9. 게임 전용 VM

Cloud Scale과 Game Dedicated는 고정 shape의 격리 KVM 서버를 요청할 수 있습니다. 요청은 먼저 dry-run 검토 큐에 들어갑니다.

POST /api/v1/cloud/vm

{ "projectId": "<uuid>", "idempotencyKey": "create-attempt-1" }
GET /api/v1/cloud/vm?projectId=<uuid>
POST /api/v1/cloud/vm/start
POST /api/v1/cloud/vm/stop
POST /api/v1/cloud/vm/delete

수명주기 POST 본문은 projectId와 고유한 idempotencyKey를 사용합니다. 만료된 VM 요금제로는 새 VM을 만들거나 중지된 VM을 다시 시작할 수 없습니다.

10. 대시보드

GET /api/v1/cloud/dashboard/summary?projectId=<uuid>&days=30

프로젝트 소유자만 조회. 이벤트별 사용량 breakdown 반환.


HTTP 연동 예시

ZUKU 세션을 관리하는 신뢰할 수 있는 앱에서 호출합니다. 게임 샌드박스에 계정 토큰을 넘기지 마세요. 아래는 실제 HTTP API 예시이며 별도 npm SDK 설치를 전제로 하지 않습니다.

await fetch("/api/v1/cloud/saves/save", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${accessToken}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ projectId, slot: "default", data: gameState })
});