# 機能設計書 64-招待トークン検証

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける招待トークンの有効性検証機能の設計を記述する。招待リンクに含まれるJWTトークンを検証し、有効な招待情報を返却する。

### 本機能の処理概要

**業務上の目的・背景**：招待受諾フローにおいて、ユーザーがアクセスした招待リンクが正当なものであるか、また有効期限内であるかを確認することは、セキュリティ上不可欠である。招待トークン検証機能は、JWTトークンの署名検証、有効期限チェック、招待レコードの存在確認を行い、不正アクセスや期限切れリンクからのアクセスを防止する。

**機能の利用シーン**：
- 招待メール内のリンクをクリックしてアカウント設定画面にアクセスする際
- 招待受諾APIを呼び出す際の事前検証
- 招待リンクの有効性を確認するプレビュー機能

**主要な処理内容**：
1. JWTトークンのデコード
2. 署名検証（秘密鍵または公開鍵を使用）
3. トークンペイロードから招待IDを抽出
4. 招待レコードの存在確認（データベース検索）
5. 有効期限チェック（expires_atと現在時刻の比較）
6. 有効な招待情報の返却

**関連システム・外部連携**：
- UserModuleの招待サービスとの連携
- JWT検証ライブラリ（jsonwebtoken）の使用

**権限による制御**：招待トークン検証自体は認証不要（招待受諾前のため）。ただし、検証成功後の受諾処理には認証アイデンティティが必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | 招待画面 | 主画面 | 招待リンクの有効性確認 |

## 機能種別

検証処理 / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| token | string | Yes | JWTトークン（招待メールのリンクに含まれる） | 有効なJWT形式 |

### 入力データソース

- 招待メール内のリンクパラメータ
- 招待受諾APIのクエリパラメータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | 招待ID |
| email | string | 招待先メールアドレス |
| accepted | boolean | 受諾済みフラグ |
| expires_at | Date | 有効期限 |
| metadata | object | null | メタデータ |
| created_at | Date | 作成日時 |
| updated_at | Date | 更新日時 |

### 出力先

- ワークフローステップの戻り値
- 招待受諾処理への入力

## 処理フロー

### 処理シーケンス

```
1. JWTトークン受信
   └─ APIまたはワークフローステップから受信

2. JWT検証オプション設定
   ├─ jwt_verify_optionsまたはjwtOptionsを取得
   └─ algorithmsオプションの設定

3. JWT署名検証
   ├─ 秘密鍵または公開鍵を使用
   └─ jwt.verify()で検証

4. ペイロード抽出
   └─ decoded.payload.idから招待IDを取得

5. 招待レコード取得
   └─ inviteService_.retrieve()で招待情報取得

6. 有効期限チェック
   ├─ expires_at < 現在時刻の場合
   └─ MedusaError.INVALID_DATAをスロー

7. 招待情報返却
   └─ シリアライズして返却
```

### フローチャート

```mermaid
flowchart TD
    A[トークン受信] --> B[検証オプション設定]
    B --> C[JWT署名検証]
    C --> D{署名有効?}
    D -->|No| E[検証エラー]
    D -->|Yes| F[ペイロード抽出]
    F --> G[招待ID取得]
    G --> H[招待レコード検索]
    H --> I{招待存在?}
    I -->|No| J[NOT_FOUNDエラー]
    I -->|Yes| K[有効期限チェック]
    K --> L{有効期限内?}
    L -->|No| M[期限切れエラー]
    L -->|Yes| N[招待情報返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-64-01 | 署名必須 | JWTトークンは有効な署名を持つこと | 全トークン検証時 |
| BR-64-02 | 有効期限必須 | トークンの有効期限（expires_at）は現在時刻より未来であること | トークン検証時 |
| BR-64-03 | 招待存在必須 | トークンに含まれる招待IDは有効な招待レコードに対応すること | トークン検証時 |

### 計算ロジック

**有効期限判定**:
```typescript
if (invite.expires_at < new Date()) {
  throw new MedusaError(MedusaError.Types.INVALID_DATA, "The invite has expired")
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 招待取得 | invite | SELECT | IDを指定して招待レコード取得 |

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

#### invite

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id | WHERE id = ? | JWTペイロードから取得したID |
| SELECT | expires_at | 取得対象 | 有効期限チェック用 |
| SELECT | email, accepted, metadata, created_at, updated_at | 取得対象 | 招待情報返却用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| JsonWebTokenError | JWT Error | トークン形式不正、署名無効 | 検証エラーとして処理 |
| TokenExpiredError | JWT Error | JWTトークン自体の有効期限切れ | 検証エラーとして処理 |
| INVALID_DATA | MedusaError | 招待の有効期限（expires_at）切れ | 400レスポンス |
| NOT_FOUND | MedusaError | 招待IDに対応するレコードが存在しない | 404レスポンス |

### リトライ仕様

トークン検証失敗時のリトライは不要。新しい招待を再送信して新規トークンを発行する。

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

トークン検証はSELECT操作のみのため、トランザクション管理は不要。

## パフォーマンス要件

- 招待IDによる検索は主キーインデックスを使用
- JWT検証は同期処理で即座に完了

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

- JWT秘密鍵はConfigModuleで管理し、環境変数から取得
- 公開鍵方式（jwtPublicKey）にも対応
- アルゴリズム指定でダウングレード攻撃を防止
- 有効期限による時限的アクセス制御

## 備考

- JWT検証オプションはjwt_verify_optionsまたはjwtOptionsで設定可能
- completeオプションでヘッダーとペイロードの両方を取得

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | invite.ts | `packages/modules/user/src/models/invite.ts` | Inviteモデルの構造、特にexpires_atフィールド |

**読解のコツ**: トークン検証ではexpires_atフィールドが重要。これはDBレベルでの有効期限管理を示す。

#### Step 2: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | user-module.ts | `packages/modules/user/src/services/user-module.ts` | validateInviteToken関数の実装 |

**主要処理フロー**:
1. **98-102行目**: メソッドシグネチャとデコレータ
2. **103-111行目**: JWT検証オプションの設定、algorithmsの設定
3. **113-117行目**: jwt.verify()によるトークン検証
4. **119-123行目**: inviteService_.retrieve()による招待取得
5. **125-130行目**: 有効期限チェック、期限切れ時はMedusaError
6. **132行目**: 招待情報のシリアライズと返却

#### Step 3: ワークフローステップを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | validate-token.ts | `packages/core/core-flows/src/invite/steps/validate-token.ts` | ワークフローステップとしての実装 |

**主要処理フロー**:
- **15-26行目**: createStepでステップ定義、UserModuleのvalidateInviteToken呼び出し

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

```
validateTokenStep (workflow step)
    │
    └─ userModuleService.validateInviteToken
           │
           ├─ jwt.verify (署名検証)
           │      └─ jwtSecret / jwtPublicKey
           │
           └─ inviteService_.retrieve
                  │
                  └─ invite テーブル (SELECT)
```

### データフロー図

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

JWTトークン ──────▶ validateInviteToken ──────▶ InviteDTO
                         │
                         ├─ jwt.verify
                         │      │
                         │      ▼
                         │   署名検証結果
                         │      │
                         │      ▼
                         │   ペイロード抽出 (id, email)
                         │
                         └─ inviteService_.retrieve
                                │
                                ▼
                           invite レコード
                                │
                                ▼
                           有効期限チェック
                                │
                    ┌───────────┴───────────┐
                    ▼                       ▼
              有効期限OK              有効期限切れ
                    │                       │
                    ▼                       ▼
             InviteDTO返却            MedusaError
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| invite.ts | `packages/modules/user/src/models/invite.ts` | ソース | Inviteモデル定義 |
| user-module.ts | `packages/modules/user/src/services/user-module.ts` | ソース | validateInviteToken実装 |
| validate-token.ts | `packages/core/core-flows/src/invite/steps/validate-token.ts` | ソース | ワークフローステップ |
| accept-invite.ts | `packages/core/core-flows/src/invite/workflows/accept-invite.ts` | ソース | 招待受諾ワークフロー（呼び出し元） |
| jsonwebtoken | node_modules | 外部ライブラリ | JWT検証ライブラリ |
