# 機能設計書 33-支払いプロバイダー管理

## 概要

本ドキュメントは、Medusaの支払いモジュールにおける支払いプロバイダー管理機能の設計を記載する。

### 本機能の処理概要

支払いプロバイダー管理機能は、Stripe、PayPal等の外部決済サービスとの連携を管理する機能である。プロバイダーの登録・取得・有効/無効化を行い、実際の決済処理を各プロバイダーに委譲するための仲介役を担う。

**業務上の目的・背景**：ECサイトでは複数の決済手段を提供することで顧客の利便性を向上させる必要がある。本機能により、Stripe、PayPal、その他の決済プロバイダーを統一的なインターフェースで管理し、プロバイダー固有の処理を抽象化する。

**機能の利用シーン**：
1. 新しい決済プロバイダーをシステムに追加する場面
2. 利用可能なプロバイダー一覧を取得する場面
3. プロバイダーを一時的に無効化/有効化する場面
4. 各決済操作（セッション作成、認可、キャプチャ、返金等）をプロバイダーに委譲する場面

**主要な処理内容**：
1. プロバイダーの一覧取得・検索
2. プロバイダーの有効/無効状態管理
3. 各決済操作のプロバイダーへの委譲（createSession、authorizePayment、capturePayment、refundPayment等）
4. アカウントホルダー操作のプロバイダーへの委譲
5. Webhookイベントの処理

**関連システム・外部連携**：Stripe、PayPal、その他サードパーティ決済サービスとAPIを通じて連携。

**権限による制御**：管理者（Admin）権限を持つユーザーのみがプロバイダー設定を変更可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 支払いプロバイダー設定画面 | 主機能 | プロバイダーの設定・管理（画面機能マッピングに該当なし） |

## 機能種別

データ連携 / CRUD操作 / 設定管理

## 入力仕様

### 入力パラメータ

#### プロバイダー一覧取得

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| is_enabled | boolean | No | 有効なプロバイダーのみ取得 | - |
| id | string[] | No | 指定IDのプロバイダーを取得 | - |

#### 決済操作委譲

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| providerId | string | Yes | プロバイダーID（例：pp_stripe） | 登録済みプロバイダーであること |
| input | 各種Input型 | Yes | 操作固有の入力データ | 操作種別による |

### 入力データソース

- 設定ファイル：medusa-config.js等でのプロバイダー設定
- DIコンテナ：プロバイダーインスタンスの登録
- DBテーブル：payment_provider

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| providers | PaymentProviderDTO[] | プロバイダー一覧 |
| providers[].id | string | プロバイダーID（例：pp_stripe） |
| providers[].is_enabled | boolean | 有効フラグ |

### 出力先

- 画面表示：管理画面のプロバイダー設定
- DBテーブル：payment_provider
- 外部API：各決済プロバイダーのAPI

## 処理フロー

### 処理シーケンス

```
1. プロバイダー取得
   └─ retrieveProvider()でDIコンテナからプロバイダーインスタンスを取得

2. 操作の委譲
   └─ 各操作メソッド（createSession、authorizePayment等）を呼び出し

3. プロバイダーAPIコール
   └─ 外部決済サービスへのリクエスト送信

4. レスポンス処理
   └─ プロバイダーからの応答を標準フォーマットに変換

5. 結果返却
   └─ 呼び出し元への結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始: プロバイダー操作] --> B[retrieveProvider]
    B --> C{プロバイダー存在?}
    C -->|No| D[AwilixResolutionError]
    D --> E[エラーログ出力]
    E --> F[エラースロー]
    C -->|Yes| G[プロバイダーインスタンス取得]
    G --> H[操作メソッド呼び出し]
    H --> I{プロバイダーAPI成功?}
    I -->|No| J[エラー処理]
    I -->|Yes| K[レスポンス処理]
    K --> L[結果返却]
    L --> M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-001 | プロバイダー登録必須 | 使用するプロバイダーはDIコンテナに登録されている必要がある | 全ての決済操作 |
| BR-33-002 | プロバイダーID形式 | プロバイダーIDは`pp_`プレフィックスで始まる | プロバイダー識別時 |
| BR-33-003 | オプショナルメソッド対応 | 一部のメソッド（createAccountHolder等）はプロバイダーがサポートしていない場合がある | 該当操作時 |
| BR-33-004 | 有効化状態管理 | is_enabled=falseのプロバイダーは決済処理で使用不可 | 決済操作時 |

### 計算ロジック

特に複雑な計算ロジックはなし。各操作はプロバイダーに委譲される。

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| プロバイダー一覧取得 | payment_provider | SELECT | 登録済みプロバイダーの取得 |
| プロバイダー有効化 | payment_provider | UPDATE | is_enabledの更新 |

### テーブル別操作詳細

#### payment_provider

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id | フィルタ条件 | pp_プレフィックス |
| SELECT | is_enabled | フィルタ条件 | デフォルトtrue |
| UPDATE | is_enabled | true/false | 有効/無効切り替え |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| AwilixResolutionError | ContainerError | プロバイダーがDIコンテナに登録されていない | 設定ファイルでプロバイダーを登録 |
| PROVIDER_NOT_SUPPORTED | Warning | プロバイダーがメソッドをサポートしていない | ログ出力して空レスポンスを返却 |
| PROVIDER_ERROR | ProviderError | 外部プロバイダーでのエラー | プロバイダー固有のエラー処理 |

### リトライ仕様

- プロバイダーAPI呼び出しのリトライは各プロバイダー実装に依存
- 冪等性キーの使用を推奨（context.idempotency_key）

## トランザクション仕様

- プロバイダー管理自体はトランザクション不要
- 外部API呼び出しはトランザクション外で実行
- 呼び出し元での補償処理が必要

## パフォーマンス要件

- プロバイダー取得：ミリ秒単位
- 外部API呼び出し：プロバイダー依存（通常1-5秒）

## セキュリティ考慮事項

- プロバイダーAPIキー等の機密情報は環境変数で管理
- 決済データの暗号化はプロバイダー側で実施
- Webhook署名検証によるリクエスト真正性確認

## 備考

- 新規プロバイダーの追加にはIPaymentProviderインターフェースの実装が必要
- プロバイダーモジュールは`packages/modules/providers/`配下に配置

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、プロバイダーに関するデータモデルを理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | payment-provider.ts | `packages/modules/payment/src/models/payment-provider.ts` | PaymentProviderエンティティの構造 |

**読解のコツ**: PaymentProviderモデルは非常にシンプルで、id（プロバイダー識別子）とis_enabled（有効フラグ）のみを持つ。実際のプロバイダー機能はDIコンテナから取得したインスタンスが担う。

#### Step 2: プロバイダーサービスを理解する

プロバイダーへの操作委譲を行うサービスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | payment-provider.ts | `packages/modules/payment/src/services/payment-provider.ts` | プロバイダーサービスの全体構造 |

**主要処理フロー**:
- **45-55行目**: クラス定義とコンストラクタ
- **57-77行目**: retrieveProvider（プロバイダーインスタンス取得）
- **79-86行目**: createSession（セッション作成）
- **88-95行目**: updateSession（セッション更新）
- **97-103行目**: deleteSession（セッション削除）
- **105-111行目**: authorizePayment（認可）
- **121-127行目**: capturePayment（キャプチャ）
- **129-135行目**: cancelPayment（キャンセル）
- **137-143行目**: refundPayment（返金）
- **160-173行目**: createAccountHolder（アカウントホルダー作成）

#### Step 3: プロバイダーインターフェースを理解する

各プロバイダーが実装すべきインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | IPaymentProvider | `packages/core/types/src/payment/provider.ts` | プロバイダーインターフェース定義 |

**読解のコツ**: IPaymentProviderインターフェースは必須メソッド（initiatePayment、authorizePayment等）とオプショナルメソッド（createAccountHolder等）を定義している。

#### Step 4: APIルートを理解する

プロバイダー一覧取得のAPIエンドポイントを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | route.ts | `packages/medusa/src/api/admin/payments/payment-providers/route.ts` | GET /admin/payments/payment-providers |

### プログラム呼び出し階層図

```
PaymentModuleService
    │
    └─ PaymentProviderService
           │
           ├─ retrieveProvider(providerId)
           │      │
           │      └─ DIContainer[`pp_${provider}`]
           │             │
           │             └─ IPaymentProvider実装
           │
           ├─ createSession()
           │      └─ provider.initiatePayment()
           │
           ├─ authorizePayment()
           │      └─ provider.authorizePayment()
           │
           ├─ capturePayment()
           │      └─ provider.capturePayment()
           │
           ├─ refundPayment()
           │      └─ provider.refundPayment()
           │
           ├─ cancelPayment()
           │      └─ provider.cancelPayment()
           │
           └─ getWebhookActionAndData()
                  └─ provider.getWebhookActionAndData()
```

### データフロー図

```
[入力]                    [処理]                          [出力]

providerId ────────────▶ PaymentProviderService
操作パラメータ                   │
                                │
                                ▼
                    ┌───────────────────────────┐
                    │ retrieveProvider()        │
                    │ DIコンテナからインスタンス取得│
                    └──────────┬────────────────┘
                               │
                               ▼
                    ┌───────────────────────────┐
                    │ IPaymentProvider実装       │
                    │ (Stripe, PayPal等)        │
                    └──────────┬────────────────┘
                               │
                               ▼
                    ┌───────────────────────────┐
                    │ 外部決済サービスAPI         │──────▶ 決済結果
                    └───────────────────────────┘        (DTO)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| payment-provider.ts | `packages/modules/payment/src/services/payment-provider.ts` | サービス | プロバイダー操作の委譲 |
| payment-provider.ts | `packages/modules/payment/src/models/payment-provider.ts` | モデル | プロバイダーエンティティ定義 |
| route.ts | `packages/medusa/src/api/admin/payments/payment-providers/route.ts` | APIルート | プロバイダー一覧取得エンドポイント |
| provider.ts | `packages/core/types/src/payment/provider.ts` | 型定義 | IPaymentProviderインターフェース |
| payment-module.ts | `packages/modules/payment/src/services/payment-module.ts` | サービス | プロバイダーサービスの呼び出し元 |
