# 機能設計書 17-寄付機能

## 概要

本ドキュメントは、Ghostにおける寄付機能の設計仕様を記載する。本機能は、読者からの一回限りの寄付・チップを受け付ける機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：
サイト運営者がコンテンツの価値を直接収益化する方法として、定期購読以外に一回限りの寄付（チップ）を受け付けるニーズがある。寄付機能により、読者は特定の記事や運営者を支援するために任意の金額を寄付でき、運営者は追加の収益源を得ることができる。サブスクリプションに抵抗のある読者にも参加の機会を提供する。

**機能の利用シーン**：
- 読者が特定の記事に感謝を示して寄付する場合
- 運営者を直接支援したい読者が寄付する場合
- サブスクリプションを契約せずに一時的に支援したい場合

**主要な処理内容**：
1. 寄付設定の有効化/無効化
2. 推奨寄付金額の設定
3. Stripe経由の決済処理
4. 寄付イベントの記録
5. 寄付通知メールの送信

**関連システム・外部連携**：
- Stripe API（決済処理）
- メール通知サービス（スタッフへの通知）

**権限による制御**：
- 寄付設定の変更: Administrator以上
- 寄付の実行: 認証不要（公開機能）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 57 | 投げ銭・寄付設定 | 主画面 | 投げ銭・寄付機能の設定 |

## 機能種別

決済処理 / 設定管理

## 入力仕様

### 入力パラメータ（設定）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| donations_enabled | boolean | Yes | 寄付機能の有効/無効 | - |
| donations_currency | string | Yes | 寄付通貨 | 3文字ISO通貨コード |
| donations_suggested_amount | number | Yes | 推奨寄付金額 | 正の整数（セント単位） |

### 入力パラメータ（決済）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| amount | number | Yes | 寄付金額 | 正の整数（セント単位） |
| member_id | string | No | 寄付者のメンバーID | nullable |
| email | string | Yes | 寄付者のメールアドレス | メール形式 |
| name | string | No | 寄付者の名前 | - |

### 入力データソース

- 管理画面からの設定
- 公開サイトからの寄付リクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | 寄付イベントID |
| member_id | string | 寄付者メンバーID（nullable） |
| email | string | 寄付者メールアドレス |
| name | string | 寄付者名 |
| amount | number | 寄付金額（セント単位） |
| currency | string | 通貨コード |
| attribution_id | string | 属性ID（nullable） |
| attribution_type | string | 属性タイプ |
| attribution_url | string | 属性URL |
| referrer_source | string | リファラーソース |
| created_at | Date | 寄付日時 |

### 出力先

- DBテーブル（donation_payment_events）
- メール通知（スタッフ向け）

## 処理フロー

### 処理シーケンス

```
1. Stripeチェックアウトセッション作成
   └─ Donation用のセッション生成
2. 決済完了Webhook受信
   └─ checkout.session.completed イベント
3. 寄付イベント記録
   └─ DonationPaymentEvent をDBに保存
4. スタッフ通知
   └─ 新規寄付の通知メール送信
```

### フローチャート

```mermaid
flowchart TD
    A[寄付ボタンクリック] --> B[チェックアウトセッション作成]
    B --> C[Stripe決済ページへリダイレクト]
    C --> D{決済結果}
    D -->|成功| E[Webhook: checkout.session.completed]
    D -->|失敗/キャンセル| F[エラーページ/キャンセル]
    E --> G{mode = donation?}
    G -->|Yes| H[DonationPaymentEvent記録]
    G -->|No| I[他のセッション処理]
    H --> J[スタッフ通知メール]
    J --> K[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-17-01 | 最小金額 | 寄付金額は1セント以上 | 寄付時 |
| BR-17-02 | 通貨統一 | サイト設定の通貨で寄付を受付 | 寄付時 |
| BR-17-03 | 匿名寄付 | メンバー未登録でも寄付可能 | 寄付時 |
| BR-17-04 | 属性追跡 | 寄付元の記事・ページを追跡可能 | 寄付時 |
| BR-17-05 | 一回限り | 寄付はサブスクリプションではなく一回限り | 常に |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 寄付記録 | donation_payment_events | INSERT | 寄付イベント記録 |

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

#### donation_payment_events

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | ObjectID | 自動生成 |
| INSERT | member_id | 寄付者メンバーID | nullable |
| INSERT | email | メールアドレス | 必須 |
| INSERT | name | 名前 | nullable |
| INSERT | amount | 金額（セント） | 必須 |
| INSERT | currency | 通貨コード | 必須 |
| INSERT | attribution_id | 属性ID | nullable |
| INSERT | attribution_type | 属性タイプ | nullable |
| INSERT | attribution_url | 属性URL | nullable |
| INSERT | referrer_source | リファラーソース | nullable |
| INSERT | referrer_medium | リファラーメディア | nullable |
| INSERT | referrer_url | リファラーURL | nullable |
| INSERT | created_at | 作成日時 | 自動設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | BadRequest | 金額が0以下 | 正の金額を指定 |
| 400 | BadRequest | 寄付機能が無効 | 管理者が有効化 |
| 500 | InternalError | Stripe API エラー | リトライまたはサポート |

### リトライ仕様

- Stripe Webhookは自動リトライ

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

- 寄付イベント記録は単一INSERT

## パフォーマンス要件

- チェックアウトセッション作成: 即時応答

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

- Stripe決済による安全な処理
- カード情報はGhostには保存されない
- Webhook署名検証必須

## 備考

- 寄付機能はStripe連携が前提

---

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

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

### 推奨読解順序

#### Step 1: サービス構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | donation-service-wrapper.js | `ghost/core/core/server/services/donations/donation-service-wrapper.js` | サービス初期化 |

**読解のコツ**:
- DonationBookshelfRepositoryの初期化
- DonationPaymentEventModelの注入

**主要処理フロー**:
- **6-16行目**: init() - リポジトリ初期化

#### Step 2: Webhook処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | checkout-session-event-service.js | `ghost/core/core/server/services/stripe/services/webhook/checkout-session-event-service.js` | 寄付チェックアウト処理 |

**読解のコツ**:
- mode='donation' のセッション判定
- donationRepository.save() での記録

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

```
Stripe Webhook
    │
    └─ checkout.session.completed
           │
           └─ WebhookController
                  │
                  └─ CheckoutSessionEventService
                         │
                         ├─ isDonation() チェック
                         │
                         └─ donationRepository.save()
                                │
                                └─ DonationPaymentEvent INSERT
                                       │
                                       └─ staffServiceEmails (通知)
```

### データフロー図

```
[フロントエンド]          [Stripe]                [Ghost Backend]

寄付ボタン ──────▶ チェックアウト
クリック            セッション
                       │
                       ▼
                   決済ページ
                       │
                       ▼
                   決済完了
                       │
                       ▼
                   Webhook ─────────────▶ CheckoutSessionEventService
                                                    │
                                                    ▼
                                         donation_payment_events
                                                    │
                                                    ▼
                                              スタッフ通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| donation-service-wrapper.js | `ghost/core/core/server/services/donations/donation-service-wrapper.js` | ソース | サービスラッパー |
| index.js | `ghost/core/core/server/services/donations/index.js` | ソース | エントリーポイント |
| checkout-session-event-service.js | `ghost/core/core/server/services/stripe/services/webhook/checkout-session-event-service.js` | ソース | チェックアウト処理 |
| stripe-api.js | `ghost/core/core/server/services/stripe/stripe-api.js` | ソース | Stripe API（セッション作成） |
