# 通知設計書 3-有料会員登録完了メール

## 概要

本ドキュメントは、Ghost CMSにおける有料会員登録完了メール（Paid Signup確認メール）の設計仕様を記載する。有料サブスクリプションの支払い完了後に送信されるサインインリンク付きメールの送信ロジック、テンプレート構造、およびデータフローを定義する。

### 本通知の処理概要

本通知は、ユーザーがStripe決済を通じて有料サブスクリプションを完了した際に、アカウントへのサインインリンクを含む確認メールを送信する機能である。

**業務上の目的・背景**：有料会員として登録が完了したことをユーザーに通知し、サイトへの即座なアクセス手段を提供する。Stripeチェックアウト完了後、会員アカウントが自動作成されるため、初回サインインのためのマジックリンクを提供する必要がある。

**通知の送信タイミング**：Stripeのチェックアウトセッションが成功し、会員レコードが作成された後にトリガーされる。具体的にはStripe Webhookの`checkout.session.completed`イベント処理の一環として送信される場合と、チェックアウト完了後のリダイレクト時に送信される場合がある。

**通知の受信者**：有料サブスクリプションを完了した新規会員のメールアドレスに送信される。チェックアウト時に入力されたメールアドレス、または既存会員として認証済みのメールアドレスが使用される。

**通知内容の概要**：メールには登録完了の感謝メッセージと、サイトへ自動サインインするためのマジックリンクが含まれる。リンクは24時間で有効期限が切れる。

**期待されるアクション**：受信者はメール内の「Sign in」ボタンをクリックしてサイトにサインインし、有料会員向けコンテンツへアクセスする。

## 通知種別

メール通知（トランザクションメール）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無 |

### 送信先決定ロジック

1. Stripeチェックアウト完了時のメールアドレスを取得
2. 会員レコードが正常に作成されていることを確認
3. 該当会員のメールアドレスに送信

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | サイト設定の`members_support_address`または`noreply@[サイトドメイン]` |
| 送信元名称 | サイトタイトル |
| 件名 | `Thank you for signing up to {siteTitle}!` |
| 形式 | HTML + テキスト（マルチパート） |

### 本文テンプレート

```html
件名: Thank you for signing up to {siteTitle}!

本文:
Hey there!

Thank you for subscribing to {siteTitle}. Tap the link below to be automatically signed in:

[Sign in ボタン]

For your security, the link will expire in 24 hours time.

See you soon!

---
You can also copy & paste this URL into your browser:
{magicLinkUrl}

This message was sent from {siteDomain} to {email}.
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 本通知には添付ファイルはない |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| siteTitle | サイト名 | settingsCache.get('title') | Yes |
| email | 送信先メールアドレス | Stripe checkout / 会員レコード | Yes |
| url | マジックリンクURL | tokenProvider.create() + getSigninURL() | Yes |
| accentColor | サイトのアクセントカラー | settingsCache.get('accent_color') | No（デフォルト: #15212A） |
| siteDomain | サイトドメイン | urlUtils.getSiteUrl()から抽出 | Yes |
| siteUrl | サイトURL | urlUtils.getSiteUrl() | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Stripe Webhook | checkout.session.completed | mode='subscription'かつ新規会員 | 有料サブスクリプション完了 |
| チェックアウト完了 | 決済成功後のリダイレクト処理 | 会員作成成功時 | フロントエンドからのコールバック |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 既存会員の追加サブスク | 既にサインイン済みの会員には送信不要 |
| 会員作成失敗 | 会員レコードの作成が失敗した場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Stripe checkout.session.completed] --> B[会員存在確認]
    B --> C{新規会員?}
    C -->|Yes| D[会員レコード作成]
    C -->|No| E[既存会員更新]
    D --> F[マジックリンク生成]
    E --> G[サブスク情報更新のみ]
    F --> H[signup-paidテンプレート展開]
    H --> I[メール送信]
    I --> J[完了]
    G --> J
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| members | 会員存在確認・作成 | email列で検索 |
| stripe_customers | Stripe顧客情報 | customer_id列で検索 |
| settings | サイト設定取得 | settingsCacheから取得 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| members | INSERT | 新規会員レコード作成 |
| members_stripe_customers | INSERT | Stripe顧客関連付け |
| stripe_customer_subscriptions | INSERT | サブスクリプション情報 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 会員作成失敗 | DBエラー等 | エラーログ出力、メール送信スキップ |
| 送信失敗 | SMTPエラー | エラーログ出力 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 設定なし |
| 1日あたり上限 | 設定なし |

### 配信時間帯

特定の配信時間帯制限はない。

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

- マジックリンクトークンは24時間で有効期限切れ
- Stripe Webhookの署名検証を実施
- 会員のメールアドレスとStripeの顧客メールアドレスの一致を確認

## 備考

- 有料会員登録完了メールと無料会員サインアップメールは異なるテンプレートを使用
- 「Thank you for subscribing」というメッセージで有料登録を明示
- Welcome Emailとは別の通知（Welcome Emailは管理者が任意設定するもの）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | signup-paid.js | `ghost/core/core/server/services/members/emails/signup-paid.js` | signup.jsとの違いを確認。「Thank you for subscribing」のメッセージ |

**読解のコツ**: signup.jsと比較して、preheaderとメイン文言の違いに注目。有料会員向けのウェルカムメッセージになっている。

#### Step 2: Stripe連携フローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stripe-api-service | `ghost/core/core/server/services/stripe/` | Stripe Webhook処理、checkout.session.completed |
| 2-2 | member-repository.js | `ghost/core/core/server/services/members/members-api/repositories/member-repository.js` | 会員作成時のメール送信トリガー |

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

```
Stripe checkout.session.completed Webhook
    │
    ├─ StripeWebhookHandler
    │      │
    │      └─ handleCheckoutSessionCompleted()
    │             │
    │             ├─ 会員存在確認
    │             │
    │             ├─ 新規会員作成 or 既存会員更新
    │             │
    │             └─ sendEmailWithMagicLink()
    │                    │
    │                    └─ signup-paid.js テンプレート
```

### データフロー図

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

Stripe Webhook ─────────▶ StripeWebhookHandler
  - customer_email              │
  - subscription_id             ▼
                          会員作成/更新
                               │
membersテーブル ◀─────────────┘
                               │
                               ▼
                         マジックリンク生成
                               │
                               ▼
                         メール送信 ─────────▶ 新規有料会員のメールボックス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| signup-paid.js | `ghost/core/core/server/services/members/emails/signup-paid.js` | テンプレート | 有料会員登録完了メールのHTMLテンプレート |
| stripe-api-service | `ghost/core/core/server/services/stripe/` | サービス | Stripe API連携 |
| member-repository.js | `ghost/core/core/server/services/members/members-api/repositories/member-repository.js` | リポジトリ | 会員CRUD |
