# 機能設計書 34-SEOプラグイン

## 概要

本ドキュメントは、Payload CMSのSEOプラグイン機能について記述する。このプラグインは、コレクションおよびグローバルにSEO関連フィールド（メタタイトル、メタディスクリプション、OG画像、プレビューURL）を自動的に追加し、検索エンジン最適化のためのメタデータ管理を実現する。

### 本機能の処理概要

**業務上の目的・背景**：Webサイトの検索エンジン最適化（SEO）は、コンテンツの発見可能性とオーガニックトラフィック獲得に不可欠である。各ページにメタタイトル、メタディスクリプション、OGP画像などのメタデータを適切に設定することで、検索結果での表示品質向上とSNSシェア時の見栄え改善を実現する。このプラグインにより、コンテンツ作成者がCMS上で直接SEOメタデータを管理できる。

**機能の利用シーン**：
- コンテンツ作成時のSEOメタデータ入力
- 検索結果プレビューの確認
- タイトル・説明文の文字数最適化
- OGP画像の設定と自動生成

**主要な処理内容**：
1. 設定されたコレクション/グローバルに`meta`グループフィールドを追加
2. メタタイトル、メタディスクリプション、メタ画像、プレビューURLフィールドの提供
3. generateTitle/generateDescription/generateImage/generateURL関数によるメタデータ自動生成
4. APIエンドポイント経由での動的生成処理
5. タブ型UIへのSEOフィールド統合（オプション）

**関連システム・外部連携**：
- Payload CMS管理画面（フィールド表示）
- アップロードコレクション（OGP画像保存）
- フロントエンドサイト（メタタグ出力）

**権限による制御**：
- コレクション/グローバルの編集権限に従う
- フィールドレベルのアクセス制御は通常のフィールドと同様

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | ドキュメント編集画面 | 主機能 | SEOフィールドの入力・編集 |

## 機能種別

プラグイン / フィールド拡張 / メタデータ管理

## 入力仕様

### 入力パラメータ（プラグイン設定）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| collections | CollectionSlug[] | No | SEOフィールドを追加するコレクション | 有効なコレクションスラッグ |
| globals | GlobalSlug[] | No | SEOフィールドを追加するグローバル | 有効なグローバルスラッグ |
| uploadsCollection | UploadCollectionSlug | No | OGP画像のアップロード先コレクション | - |
| tabbedUI | boolean | No | タブ型UIを使用するか | - |
| generateTitle | GenerateTitle | No | タイトル自動生成関数 | 関数型 |
| generateDescription | GenerateDescription | No | 説明文自動生成関数 | 関数型 |
| generateImage | GenerateImage | No | 画像自動生成関数 | 関数型 |
| generateURL | GenerateURL | No | URL自動生成関数 | 関数型 |
| fields | FieldsOverride | No | フィールドカスタマイズ関数 | 関数型 |
| interfaceName | string | No | TypeScript型のインターフェース名 | - |

### 入力データソース

- Payload設定ファイル（payload.config.ts）
- ドキュメントデータ（generate関数への入力）
- 管理画面からのフォーム入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| meta.title | string | メタタイトル |
| meta.description | string | メタディスクリプション |
| meta.image | Relationship | OGP画像（アップロードコレクションへの参照） |
| meta.url | string | ページURL（プレビュー用） |

### 出力先

- データベース（ドキュメントのmetaフィールド）
- 管理画面（フィールド表示）
- APIエンドポイントレスポンス

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化
   └─ seoPlugin(pluginConfig)でPayload設定を拡張

2. コレクション/グローバル拡張
   └─ 指定されたコレクションにmetaグループフィールドを追加
   └─ tabbedUI有効時はタブ構造に変換

3. APIエンドポイント登録
   └─ /plugin-seo/generate-title
   └─ /plugin-seo/generate-description
   └─ /plugin-seo/generate-url
   └─ /plugin-seo/generate-image

4. フィールドコンポーネント表示
   └─ Overview（検索結果プレビュー）
   └─ MetaTitle（文字数インジケータ付き）
   └─ MetaDescription（文字数インジケータ付き）
   └─ MetaImage（画像アップロード）
   └─ Preview（URLプレビュー）

5. 自動生成呼び出し（オプション）
   └─ ユーザーが生成ボタンクリック
   └─ APIエンドポイント呼び出し
   └─ generate関数実行
   └─ 結果をフィールドに反映
```

### フローチャート

```mermaid
flowchart TD
    A[seoPlugin初期化] --> B[設定解析]
    B --> C{collections指定?}
    C -->|Yes| D[コレクションにSEOフィールド追加]
    C -->|No| E[スキップ]
    D --> F{globals指定?}
    E --> F
    F -->|Yes| G[グローバルにSEOフィールド追加]
    F -->|No| H[スキップ]
    G --> I[APIエンドポイント登録]
    H --> I
    I --> J[翻訳マージ]
    J --> K[設定返却]

    subgraph フィールド追加処理
        D --> D1{tabbedUI?}
        D1 -->|Yes| D2[タブ構造に変換]
        D1 -->|No| D3[フィールド末尾に追加]
    end

    subgraph 自動生成処理
        L[生成ボタンクリック] --> M[APIエンドポイント呼び出し]
        M --> N[generate関数実行]
        N --> O[結果をフィールドに反映]
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 対象コレクション指定 | collectionsに含まれるコレクションのみSEOフィールドを追加 | プラグイン適用時 |
| BR-02 | タブ型UI | tabbedUI=trueの場合、コンテンツとSEOを別タブに分離 | tabbedUI有効時 |
| BR-03 | 画像フィールド条件 | uploadsCollectionが指定された場合のみMetaImageフィールドを追加 | uploadsCollection設定時 |
| BR-04 | ローカライズ | メタフィールドはデフォルトでローカライズ有効 | 多言語設定時 |
| BR-05 | 認証コレクション例外 | authコレクションのemailフィールドはタブ移動しない | タブ変換時 |

### 計算ロジック

フィールド追加位置の決定：
```
if (tabbedUI) {
  if (collection.fields[0].type === 'tabs') {
    // 既存タブにSEOタブを追加
  } else {
    // Contentタブを作成し、SEOタブを追加
  }
} else {
  // フィールド末尾に追加
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 保存 | 対象コレクション | UPDATE | metaフィールドの保存 |
| 画像アップロード | uploadsCollection | INSERT | OGP画像の保存 |

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

#### 対象コレクション（pages等）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | meta.title | 入力値または生成値 | ローカライズ対応 |
| UPDATE | meta.description | 入力値または生成値 | ローカライズ対応 |
| UPDATE | meta.image | アップロード画像ID | Relationship |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 生成エラー | generate関数が例外をスロー | エラーをAPIレスポンスとして返却 |
| - | 設定エラー | 無効なコレクションスラッグ | プラグイン適用時に警告 |

### リトライ仕様

- 自動リトライなし
- ユーザーが再度生成ボタンをクリック

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

- ドキュメント保存時のトランザクションはPayload本体に委譲
- APIエンドポイントは読み取り専用（生成処理）

## パフォーマンス要件

- generate関数は非同期処理対応
- 大量のドキュメントがある場合、一括生成はバッチ処理を推奨

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

- APIエンドポイントは認証必須
- generate関数内での外部API呼び出しは注意が必要

## 備考

- 多言語対応（30以上の言語の翻訳を内包）
- Yoast SEOライクなUI/UXを提供

---

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

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

### 推奨読解順序

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

まず、プラグイン設定とgenerate関数の型定義を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/plugin-seo/src/types.ts` | SEOPluginConfig、GenerateTitle等の型定義 |

**読解のコツ**: `SEOPluginConfig`がプラグイン設定の型。`GenerateTitle`, `GenerateDescription`, `GenerateImage`, `GenerateURL`がメタデータ自動生成関数の型。

#### Step 2: エントリーポイントを理解する

seoPlugin関数がプラグインのメイン実装。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.tsx | `packages/plugin-seo/src/index.tsx` | プラグイン本体実装 |

**主要処理フロー**:
1. **20-22行目**: seoPlugin関数の定義
2. **23-42行目**: デフォルトフィールド構築
3. **44-56行目**: seoFieldsグループフィールド構築
4. **58-132行目**: collectionsのマッピングとフィールド追加
5. **133-231行目**: APIエンドポイント登録
6. **232-277行目**: globalsのマッピングとフィールド追加
7. **278-282行目**: 翻訳マージ

#### Step 3: フィールド定義を理解する

各SEOフィールドの実装詳細。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | MetaTitle/index.ts | `packages/plugin-seo/src/fields/MetaTitle/index.ts` | メタタイトルフィールド定義 |
| 3-2 | MetaDescription/index.ts | `packages/plugin-seo/src/fields/MetaDescription/index.ts` | メタディスクリプションフィールド定義 |
| 3-3 | MetaImage/index.ts | `packages/plugin-seo/src/fields/MetaImage/index.ts` | メタ画像フィールド定義 |
| 3-4 | Overview/index.tsx | `packages/plugin-seo/src/fields/Overview/index.tsx` | 概要プレビューフィールド |
| 3-5 | Preview/index.tsx | `packages/plugin-seo/src/fields/Preview/index.tsx` | URLプレビューフィールド |

**主要処理フロー**:
- **MetaTitle**: localized: true、カスタムコンポーネント指定
- **MetaDescription**: localized: true、カスタムコンポーネント指定
- **MetaImage**: relationTo指定、uploadsCollectionへの参照

#### Step 4: UIコンポーネントを理解する

管理画面で表示されるコンポーネント。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | MetaTitleComponent.tsx | `packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx` | タイトル入力UI |
| 4-2 | MetaDescriptionComponent.tsx | `packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx` | 説明文入力UI |
| 4-3 | OverviewComponent.tsx | `packages/plugin-seo/src/fields/Overview/OverviewComponent.tsx` | 検索結果プレビューUI |
| 4-4 | LengthIndicator.tsx | `packages/plugin-seo/src/ui/LengthIndicator.tsx` | 文字数インジケータ |

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

```
seoPlugin (index.tsx)
    │
    ├─ フィールド構築
    │      ├─ OverviewField
    │      ├─ MetaTitleField
    │      ├─ MetaDescriptionField
    │      ├─ MetaImageField (条件付き)
    │      └─ PreviewField
    │
    ├─ コレクションマッピング
    │      └─ map((collection) => ...)
    │             ├─ tabbedUI処理
    │             └─ フィールド追加
    │
    ├─ APIエンドポイント登録
    │      ├─ /plugin-seo/generate-title
    │      ├─ /plugin-seo/generate-description
    │      ├─ /plugin-seo/generate-url
    │      └─ /plugin-seo/generate-image
    │
    ├─ グローバルマッピング
    │      └─ map((global) => ...)
    │
    └─ 翻訳マージ
           └─ deepMergeSimple(translations, ...)
```

### データフロー図

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

pluginConfig             seoPlugin
    │                          │
    │                          ▼
    │                     collectionsマッピング
    │                          │
    │                          ▼
    │                     フィールド追加 ────▶ 拡張されたConfig
    │                          │
    │                          ▼
    │                     APIエンドポイント登録
    │                          │
    │                          ▼
    │                     翻訳マージ

docData                  generateTitle/Description/etc
    │                          │
    │                          ▼
    └─────────────────▶  generate関数実行
                               │
                               ▼
                          メタデータ生成 ────▶ APIレスポンス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.tsx | `packages/plugin-seo/src/index.tsx` | ソース | プラグインエントリーポイント |
| types.ts | `packages/plugin-seo/src/types.ts` | ソース | 型定義 |
| MetaTitle/index.ts | `packages/plugin-seo/src/fields/MetaTitle/index.ts` | ソース | タイトルフィールド定義 |
| MetaTitleComponent.tsx | `packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx` | ソース | タイトル入力UI |
| MetaDescription/index.ts | `packages/plugin-seo/src/fields/MetaDescription/index.ts` | ソース | 説明文フィールド定義 |
| MetaDescriptionComponent.tsx | `packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx` | ソース | 説明文入力UI |
| MetaImage/index.ts | `packages/plugin-seo/src/fields/MetaImage/index.ts` | ソース | 画像フィールド定義 |
| Overview/index.tsx | `packages/plugin-seo/src/fields/Overview/index.tsx` | ソース | 概要フィールド定義 |
| OverviewComponent.tsx | `packages/plugin-seo/src/fields/Overview/OverviewComponent.tsx` | ソース | 検索結果プレビューUI |
| Preview/index.tsx | `packages/plugin-seo/src/fields/Preview/index.tsx` | ソース | URLプレビューフィールド |
| LengthIndicator.tsx | `packages/plugin-seo/src/ui/LengthIndicator.tsx` | ソース | 文字数インジケータUI |
| translations/index.ts | `packages/plugin-seo/src/translations/index.ts` | ソース | 翻訳定義 |
| package.json | `packages/plugin-seo/package.json` | 設定 | パッケージ定義 |
