🐡

【インタビューAI】Stripe決済の実装:GCPとMongoDBを使ったテスト環境から月額課金導入まで

2024/10/09に公開

はじめに

1時間の音声を15秒で文字起こしし自然な会話形式に自動変換する「インタビューAI」を個人開発中。

https://www.interview-ai.site/

現在、開発環境での開発をほぼ終え、本番環境への移行中。

フロントエンドはReact、バックエンドはNode.js、データベースはMongoDBで開発。

今回は、Stripeのテスト環境を使用して、月額課金プランの変更の決済を実装し、動作確認する。

Stripeのテスト環境設定

テスト用APIキーの取得

Stripeのテスト環境を使用する場合、**公開可能キー(Publishable Key)秘密キー(Secret Key)**を使用する

Stripeにアカウント作成して、ダッシュボードに移動したら、ナビゲーションのテスト環境というスイッチ部分をONにして、テスト環境での動作確認にうつる。

すると、テスト環境モードになる。開発者のタブをクリックすると項目がプルダウンで表示されるので、APIキーをクリック。

公開可能キー(例: pk_test_XXXXXXXXXXXXXXXXXXXXXXXX)と秘密キー(例: sk_test_XXXXXXXXXXXXXXXXXXXXXXXX)をコピーする。

フロントエンドでの環境変数設定

環境変数ファイルの設定

フロントエンドプロジェクトのルートディレクトリに .env.production ファイルを作成(または既存のファイルを編集)し、以下のように環境変数を設定する

REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_test_XXXXXXXXXXXXXXXXXXXXXXXX
REACT_APP_BACKEND_URL=YOUR_BACKEND_URL
REACT_APP_FIREBASE_API_KEY=YOUR_FIREBASE_API_KEY

GitHub Actionsのシークレット設定

GitHubリポジトリに移動し、「Settings」 > 「Secrets and variables」 > 「Actions」 を選択。

「New repository secret」 をクリックし、以下のシークレットを追加する

  • 名前: REACT_APP_STRIPE_PUBLISHABLE_KEY
  • : 先ほどコピーしたStripeの公開可能キー(例: pk_test_XXXXXXXXXXXXXXXXXXXXXXXX

GitHub Actionsワークフローの修正

.github/workflows/firebase-hosting-merge.yml , .github/workflows/firebase-hosting-pull-request.yml でenvにREACT_APP_STRIPE_PUBLISHABLE_KEYを追加。

interview-ai/.github/workflows/firebase-hosting-merge.yml

- name: Build frontend
  run: npm run build
  working-directory: ./frontend
  env:
    REACT_APP_BACKEND_URL: ${{ secrets.REACT_APP_BACKEND_URL }}
    REACT_APP_FIREBASE_API_KEY: ${{ secrets.REACT_APP_FIREBASE_API_KEY }}
    REACT_APP_STRIPE_PUBLISHABLE_KEY: ${{ secrets.REACT_APP_STRIPE_PUBLISHABLE_KEY }}
    # 他の環境変数もここに追加

ワークフローファイルの作成に関しては、こちらの記事で記載。

https://kazulog.fun/business/github-actions-firebase-hosting/#toc4

フロントエンドコードでのStripeの初期化確認

フロントエンドコードでStripeを初期化する際に、環境変数から公開可能キーを取得する。

// 環境変数からStripeの公開可能キーを取得
const stripePromise = loadStripe(
  process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY || ""
);

バックエンドでのStripeの設定確認

バックエンドでもStripeを使用する場合、秘密キーを環境変数として設定し、セキュアに管理する。

環境変数の設定

バックエンドプロジェクトの環境変数ファイル(例: .env)に以下を追加する。

STRIPE_SECRET_KEY=sk_test_XXXXXXXXXXXXXXXXXXXXXXXX

バックエンドコードでのStripeの初期化

バックエンドコードでStripeを初期化する際に、環境変数から秘密キーを取得

// backend/controllers/subscriptionController.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

GCP Secrets ManagerにStripe秘密キーを登録

Google Cloud SDKを使って、Stripeの秘密キーをSecret Managerに追加する。下記コマンドを実行する。

echo -n "<your_stripe_secret_key>" | gcloud secrets create STRIPE_SECRET_KEY --data-file=-

ちなみに、既存のシークレットを更新するためには、gcloud secrets versions add コマンドを使用する。

Secret Managerに登録した秘密キーの確認

秘密キーが正しく登録されたか確認するには、次のコマンドを実行する。

gcloud secrets versions list STRIPE_SECRET_KEY

このコマンドを実行すると、シークレットのバージョンが表示される。最新のバージョンが表示されていれば、正しく追加されている。

Cloud Runの環境変数にシークレットを設定してデプロイ

gcloud run deploy コマンドを使用して、シークレットを環境変数として指定して、下記コマンドを実行してCloud Runにデプロイする

  • YOUR_SERVICE_NAME: Cloud Runのサービス名

  • YOUR_PROJECT_ID: Google CloudプロジェクトID

  • YOUR_PROJECT_NUMBER: Google Cloudプロジェクトの番号

  • YOUR_IMAGE_NAME: デプロイするDockerイメージの名前

  • YOUR_REGION: Cloud Runが稼働するリージョン

  • -update-secrets:既存のシークレットはそのままで、新しいシークレットを追加することができます。このコマンドでは、指定したシークレット(この場合はSTRIPE_SECRET_KEY)がCloud Runの環境変数として追加され、他の既存のシークレットや環境変数には影響を与えない。もし他のシークレットも含めてすべての環境変数を更新したい場合は、--set-secretsオプションを使う必要がある。

gcloud run deploy YOUR_SERVICE_NAME \
    --image gcr.io/YOUR_PROJECT_NUMBER/YOUR_IMAGE_NAME \
    --update-secrets STRIPE_SECRET_KEY=projects/YOUR_PROJECT_NUMBER/secrets/STRIPE_SECRET_KEY:latest \
    --platform managed \
    --region YOUR_REGION \
    --allow-unauthenticated

バックエンドのコード変更がある場合には、Cloud Runにデプロイする前に、まずコンテナイメージをビルドしてGoogle Container Registry(GCR)にアップロードする。

Secret Managerの設定や環境変数の変更適用だけの場合は、Cloud Rubへのデプロイだけで良い。

gcloud builds submit --tag gcr.io/interview-ai-20241006/backend .

無事デプロイが完了すると、ログイン後には下記の画面が表示される。

右上に現在のプランと、プラン変更のリンクを記載。プラン変更をクリックすると、プラン変更の選択とクレジットカード入力画面が表示される。

Stripeでのテスト決済を行うための設定手順
Stripe管理画面で商品作成、エンドポイント、イベントの許可の設定を進める。

商品の作成
左側のメニューから「商品カタログ」を選択し、「商品を追加」をクリックして、新しい商品を作成する。
商品名(例: “Standard Plan”)や、、、

続きはこちらで記載しています。
https://kazulog.fun/business/stripe-gcp-mongodb/

Discussion