From 823bdcafcfc137d02cd1f6c25bbe295122ebde7b Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Sun, 28 Jun 2026 15:12:59 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=97=85=EA=B7=B8=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20=ED=99=94=EB=A9=B4=20=EC=9D=B8=EC=95=B1=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=E2=80=94=20Android=20=EA=B5=AC=EB=A7=A4,=20PC?= =?UTF-8?q?=EB=8A=94=20=EC=95=B1=20=EC=9C=A0=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - billingApi(products/verifyGoogle), native/billing(테스트 구매 토큰 생성) - Android 앱: 상품(월간/연간) 구매 버튼 → 검증 → 프로필 갱신 - PC(웹/데스크톱): 구매 대신 앱 다운로드 안내 - 프리미엄 이용 중이면 만료일 표시 Co-Authored-By: Claude Opus 4.8 --- src/api/billingApi.js | 13 ++++ src/native/billing.js | 26 +++++++ src/views/UpgradeView.vue | 151 +++++++++++++++++++++++++++++++++++++- 3 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 src/api/billingApi.js create mode 100644 src/native/billing.js diff --git a/src/api/billingApi.js b/src/api/billingApi.js new file mode 100644 index 0000000..12eff03 --- /dev/null +++ b/src/api/billingApi.js @@ -0,0 +1,13 @@ +import http from './http' + +// 백엔드 /api/billing 엔드포인트와 매핑 +export const billingApi = { + // 구독 상품 목록 + products() { + return http.get('/billing/products') + }, + // Google Play 구매 검증 → 멤버십 부여 + verifyGoogle(payload) { + return http.post('/billing/google/verify', payload) + }, +} diff --git a/src/native/billing.js b/src/native/billing.js new file mode 100644 index 0000000..7c8436d --- /dev/null +++ b/src/native/billing.js @@ -0,0 +1,26 @@ +import { Capacitor } from '@capacitor/core' + +// 인앱 결제(Google Play) 헬퍼. +// 결제는 Android 앱에서만 가능 — 웹/데스크톱(PC)은 앱 다운로드로 유도한다. +export const billing = { + // Capacitor 네이티브(안드로이드) 여부 + isNative() { + return Capacitor.isNativePlatform() + }, + + /** + * 상품 구매 → 구매 토큰 반환. + * 스캐폴드(테스트): 실제 스토어 호출 없이 test- 토큰을 만들어 백엔드 검증 흐름을 태운다. + * + * TODO(실연동): Google Play Billing 플러그인(cordova-plugin-purchase 등)을 연결해 + * 실제 구매 후 purchaseToken/orderId 를 받아 반환하도록 교체. + */ + async purchase(productId) { + const rand = (globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.floor(Math.random() * 1e9)}`) + return { + productId, + purchaseToken: `test-${productId}-${rand}`, + orderId: `TEST-${rand}`, + } + }, +} diff --git a/src/views/UpgradeView.vue b/src/views/UpgradeView.vue index 2220a23..da6e63e 100644 --- a/src/views/UpgradeView.vue +++ b/src/views/UpgradeView.vue @@ -1,12 +1,59 @@