# 機能設計書 35-フォームビルダー

## 概要

本ドキュメントは、Payload CMSのフォームビルダープラグイン機能について記述する。このプラグインは、管理画面上でドラッグ＆ドロップでフォームを作成し、フォーム送信データの収集、メール通知、決済処理を実現する動的フォーム管理システムを提供する。

### 本機能の処理概要

**業務上の目的・背景**：Webサイトには問い合わせフォーム、申し込みフォーム、アンケートなど様々なフォームが必要となる。開発者の介入なくコンテンツ管理者がフォームを作成・管理できることで、ビジネスニーズへの迅速な対応が可能になる。また、フォーム送信時の自動メール通知や決済連携により、業務プロセスの自動化を実現する。

**機能の利用シーン**：
- 問い合わせフォームの作成・管理
- イベント申し込みフォームの作成
- 商品購入・決済フォームの作成
- アンケートフォームの作成
- フォーム送信データの管理・閲覧
- 自動メール通知の設定

**主要な処理内容**：
1. Formsコレクション（フォーム定義）とFormSubmissionsコレクション（送信データ）の自動生成
2. テキスト、チェックボックス、セレクト、メール、決済など多様なフィールドタイプのサポート
3. 送信確認メッセージまたはリダイレクトの設定
4. カスタマイズ可能なメール通知（テンプレート変数対応）
5. 決済処理フック（handlePayment）

**関連システム・外部連携**：
- Payload CMS管理画面（フォーム設計）
- メール送信システム（通知メール）
- 決済システム（Stripe等）
- フロントエンドサイト（フォーム表示・送信）

**権限による制御**：
- Formsコレクション: 読み取りは全員可能、書き込みは認証ユーザー
- FormSubmissions: 作成は全員可能、読み取りは認証ユーザーのみ、更新は不可
- メール設定は認証ユーザーのみ閲覧可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | 一覧画面 | 主機能 | フォーム一覧の表示 |
| 10 | ドキュメント編集画面 | 主機能 | フォーム定義の編集 |

## 機能種別

プラグイン / コレクション生成 / フォーム処理 / メール送信 / 決済連携

## 入力仕様

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

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fields | FieldsConfig | No | 有効化するフィールドタイプの設定 | - |
| formOverrides | Partial<CollectionConfig> | No | Formsコレクションのオーバーライド | - |
| formSubmissionOverrides | Partial<CollectionConfig> | No | FormSubmissionsコレクションのオーバーライド | - |
| redirectRelationships | string[] | No | リダイレクト先として選択可能なコレクション | - |
| beforeEmail | BeforeEmail | No | メール送信前フック | - |
| handlePayment | HandlePayment | No | 決済処理フック | - |
| defaultToEmail | string | No | デフォルトの送信先メールアドレス | - |

### 入力データソース

- 管理画面からのフォーム定義入力
- フロントエンドからのフォーム送信データ
- Payload設定ファイル（payload.config.ts）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| forms | CollectionConfig | フォーム定義コレクション |
| form-submissions | CollectionConfig | フォーム送信データコレクション |

### 出力先

- データベース（フォーム定義、送信データ）
- メール送信（通知メール）
- 決済システム（課金処理）

## 処理フロー

### 処理シーケンス

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

2. コレクション生成
   └─ generateFormCollection: Formsコレクション
   └─ generateSubmissionCollection: FormSubmissionsコレクション

3. フォーム作成（管理画面）
   └─ ブロックフィールドでフォーム項目を追加
   └─ 確認メッセージ/リダイレクト設定
   └─ メール通知設定

4. フォーム送信（フロントエンド）
   └─ FormSubmissionsコレクションへのcreate

5. 送信後処理
   └─ beforeChange: createCharge（決済処理）
   └─ afterChange: sendEmail（メール送信）
```

### フローチャート

```mermaid
flowchart TD
    A[formBuilderPlugin初期化] --> B[設定マージ]
    B --> C[Formsコレクション生成]
    C --> D[FormSubmissionsコレクション生成]
    D --> E[Config拡張完了]

    subgraph フォーム送信処理
        F[フォーム送信受信] --> G[バリデーション]
        G --> H{決済有効?}
        H -->|Yes| I[createCharge]
        H -->|No| J[スキップ]
        I --> K[データ保存]
        J --> K
        K --> L{メール設定?}
        L -->|Yes| M[sendEmail]
        L -->|No| N[完了]
        M --> N
    end

    subgraph フォーム定義
        O[タイトル設定] --> P[フィールド追加]
        P --> Q[送信ボタンラベル]
        Q --> R{確認タイプ}
        R -->|Message| S[確認メッセージ設定]
        R -->|Redirect| T[リダイレクト設定]
        S --> U[メール設定]
        T --> U
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | フィールド有効化 | fields設定でfalseのフィールドは使用不可 | プラグイン設定時 |
| BR-02 | デフォルトフィールド | checkbox, country, email, message, number, select, state, text, textareaがデフォルト有効 | fields未指定時 |
| BR-03 | 決済フィールド | paymentフィールドはデフォルト無効、明示的に有効化が必要 | fields.payment設定時 |
| BR-04 | 送信データ不変 | FormSubmissionsは更新不可（update: false） | 常時 |
| BR-05 | テンプレート変数 | メールテンプレートで{{fieldName}}形式で値を参照可能 | メール設定時 |
| BR-06 | ワイルドカード | {{*}}で全データ、{{*:table}}でHTML表形式 | メール設定時 |

### 計算ロジック

決済金額の計算（PriceConditions）：
```
basePrice + Σ(priceCondition)

priceCondition = {
  if (condition === 'equals' && fieldValue === valueForCondition) ||
     (condition === 'hasValue' && fieldValue) ||
     (condition === 'notEquals' && fieldValue !== valueForCondition)
  then:
    operator(currentPrice, valueForOperator)
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フォーム作成 | forms | INSERT | フォーム定義の保存 |
| フォーム更新 | forms | UPDATE | フォーム定義の更新 |
| 送信データ作成 | form-submissions | INSERT | フォーム送信データの保存 |
| フォーム参照検証 | forms | SELECT | 送信時のフォーム存在確認 |

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

#### forms

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | title | フォームタイトル | 必須 |
| INSERT/UPDATE | fields | ブロックフィールド配列 | フォーム項目 |
| INSERT/UPDATE | confirmationType | 'message' or 'redirect' | 確認タイプ |
| INSERT/UPDATE | emails | メール設定配列 | 通知メール |

#### form-submissions

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | form | フォームID（Relationship） | 必須 |
| INSERT | submissionData | 送信データ配列 | field/value |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | 送信時にフォームが存在しない | 'Cannot create this submission because this form does not exist.' |
| - | メール送信エラー | メール送信失敗 | エラーログ出力 |
| - | 決済エラー | 決済処理失敗 | handlePayment内で処理 |

### リトライ仕様

- メール送信: 自動リトライなし
- 決済処理: handlePayment実装依存

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

- フォーム送信とフック処理は同一トランザクション内で実行
- メール送信失敗時も送信データは保存される

## パフォーマンス要件

- ブロックフィールドによる動的フォーム生成
- リッチテキストフィールドのシリアライズ処理（Lexical/Slate）

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

- メール設定は認証ユーザーのみ閲覧可能（access.read条件）
- 送信データの更新は禁止（update: false）
- XSSエスケープ（escape-html使用）

## 備考

- Lexical/Slateリッチテキストのシリアライズ対応
- replaceDoubleCurlysによるテンプレート変数展開

---

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

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

### 推奨読解順序

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

まず、フォームとフィールドの型定義を理解することが重要。

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

**読解のコツ**: `FormFieldBlock`がフォーム項目の型（TextField、SelectField、PaymentField等）。`Form`がフォーム全体、`FormSubmission`が送信データの型。

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

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

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

**主要処理フロー**:
1. **11-13行目**: formBuilderPlugin関数の定義
2. **14-29行目**: デフォルトフィールド設定のマージ
3. **31-38行目**: collectionsへの追加

#### Step 3: Formsコレクション生成を理解する

フォーム定義コレクションの実装詳細。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Forms/index.ts | `packages/plugin-form-builder/src/collections/Forms/index.ts` | フォームコレクション生成 |
| 3-2 | Forms/fields.ts | `packages/plugin-form-builder/src/collections/Forms/fields.ts` | フィールドブロック定義 |

**主要処理フロー**:
- **10行目**: generateFormCollection関数
- **11-67行目**: redirectフィールド構築（条件付き）
- **69-225行目**: defaultFields定義
- **227-246行目**: CollectionConfig構築

#### Step 4: FormSubmissionsコレクション生成を理解する

送信データコレクションの実装詳細。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | FormSubmissions/index.ts | `packages/plugin-form-builder/src/collections/FormSubmissions/index.ts` | 送信コレクション生成 |

**主要処理フロー**:
- **10-12行目**: generateSubmissionCollection関数
- **17-81行目**: defaultFields定義（form、submissionData）
- **83-113行目**: CollectionConfig構築（hooks設定含む）
- **103-106行目**: afterChangeでsendEmail
- **107-109行目**: beforeChangeでcreateCharge

#### Step 5: フック処理を理解する

メール送信と決済処理のフック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | hooks/sendEmail.ts | `packages/plugin-form-builder/src/collections/FormSubmissions/hooks/sendEmail.ts` | メール送信処理 |
| 5-2 | hooks/createCharge.ts | `packages/plugin-form-builder/src/collections/FormSubmissions/hooks/createCharge.ts` | 決済処理 |

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

```
formBuilderPlugin (index.ts)
    │
    ├─ 設定マージ
    │      └─ fields設定デフォルト適用
    │
    ├─ generateFormCollection (Forms/index.ts)
    │      ├─ redirectフィールド構築
    │      ├─ フィールドブロック生成 (fields.ts)
    │      └─ CollectionConfig構築
    │
    └─ generateSubmissionCollection (FormSubmissions/index.ts)
           ├─ フォームリレーション定義
           ├─ submissionData配列定義
           └─ hooks設定
                  ├─ beforeChange: createCharge
                  └─ afterChange: sendEmail
```

### データフロー図

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

pluginConfig             formBuilderPlugin
    │                          │
    │                          ▼
    │                     コレクション生成 ────▶ 拡張されたConfig
    │                          │
    │                          ▼
    │                     forms, form-submissions

フォーム送信データ ─────▶ FormSubmissions.create
    │                          │
    │                          ▼
    │                     beforeChange
    │                          │
    │                          ├─▶ createCharge ────▶ 決済システム
    │                          │
    │                          ▼
    │                     データベース保存
    │                          │
    │                          ▼
    │                     afterChange
    │                          │
    │                          └─▶ sendEmail ────▶ メール送信
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/plugin-form-builder/src/index.ts` | ソース | プラグインエントリーポイント |
| types.ts | `packages/plugin-form-builder/src/types.ts` | ソース | 型定義 |
| Forms/index.ts | `packages/plugin-form-builder/src/collections/Forms/index.ts` | ソース | フォームコレクション生成 |
| Forms/fields.ts | `packages/plugin-form-builder/src/collections/Forms/fields.ts` | ソース | フィールドブロック定義 |
| FormSubmissions/index.ts | `packages/plugin-form-builder/src/collections/FormSubmissions/index.ts` | ソース | 送信コレクション生成 |
| hooks/sendEmail.ts | `packages/plugin-form-builder/src/collections/FormSubmissions/hooks/sendEmail.ts` | ソース | メール送信フック |
| hooks/createCharge.ts | `packages/plugin-form-builder/src/collections/FormSubmissions/hooks/createCharge.ts` | ソース | 決済処理フック |
| replaceDoubleCurlys.ts | `packages/plugin-form-builder/src/utilities/replaceDoubleCurlys.ts` | ソース | テンプレート変数展開 |
| getPaymentTotal.ts | `packages/plugin-form-builder/src/utilities/getPaymentTotal.ts` | ソース | 決済金額計算 |
| package.json | `packages/plugin-form-builder/package.json` | 設定 | パッケージ定義 |
