# 機能設計書 10-顧客グループ登録

## 概要

本ドキュメントは、Shopware 6 Storefrontにおける顧客グループ登録機能の設計仕様を記述する。特定の顧客グループに登録する機能である。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトにおいて、B2B顧客や特別な会員グループなど、通常の顧客とは異なる価格体系や機能を提供する必要がある場合がある。本機能により、顧客は特定の顧客グループへの登録を申請できる。例えば、卸売業者向けグループや法人顧客グループなどへの登録が可能となる。

**機能の利用シーン**：法人顧客がB2B向けの特別価格での購入を希望する場合や、特定の会員グループに参加したい場合に使用される。グループによっては承認プロセスが必要な場合もある。

**主要な処理内容**：
1. 顧客グループ登録ページの表示
2. グループ固有の登録要件（法人のみなど）の適用
3. 顧客情報と住所の入力
4. requestedGroupIdとして顧客グループIDを設定
5. 通常の登録処理（承認待ち状態で登録）

**関連システム・外部連携**：特になし

**権限による制御**：未ログイン状態の顧客が使用可能。対象の顧客グループが登録を受け付けている必要がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 顧客グループ登録ページ | 主機能 | 特定顧客グループへの登録（RegisterController::customerGroupRegistration） |
| 56 | 顧客グループ設定 | 主機能 | 顧客グループの作成・管理 |

## 機能種別

画面表示 / データ登録

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| customerGroupId | string | Yes | 登録先の顧客グループID（パスパラメータ） | UUID、存在確認 |
| redirectTo | string | No | 登録後のリダイレクト先（デフォルト: frontend.account.home.page） | - |
| その他 | - | - | 通常のアカウント登録と同じパラメータ | - |

### 入力データソース

- パスパラメータ（customerGroupId）
- クエリパラメータ（redirectTo等）
- POSTリクエストボディ（登録データ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| page | CustomerGroupRegistrationPage | 顧客グループ登録ページデータ |
| redirectTo | string | リダイレクト先ルート名 |
| errorRoute | string | エラー時の戻り先ルート名 |
| errorParameters | string | エラー時のパラメータ（JSON） |
| data | RequestDataBag | フォームデータ |

### 出力先

- 画面表示（Twigテンプレート）
- データベース（customer.requested_group_id）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ RegisterController::customerGroupRegistration がGETリクエストを受け取る

2. ログイン状態チェック
   └─ ゲストログイン中はログアウトページへリダイレクト
   └─ 会員ログイン中はアカウントホームへリダイレクト

3. ページデータ読み込み
   └─ CustomerGroupRegistrationPageLoader::load でページデータを取得
   └─ 顧客グループの設定を取得

4. グループ設定適用
   └─ registrationOnlyCompanyRegistration=trueの場合、accountType=businessを強制

5. フック実行
   └─ CustomerGroupRegistrationPageLoadedHook を実行

6. レスポンス生成
   └─ customer-group-register/index.html.twigテンプレートをレンダリング

（登録処理は通常のRegisterController::registerが担当）
```

### フローチャート

```mermaid
flowchart TD
    A[顧客グループ登録開始] --> B{ログイン済み?}
    B -->|ゲスト| C[ログアウトページへ]
    B -->|会員| D[アカウントホームへ]
    B -->|未ログイン| E[CustomerGroupRegistrationPageLoader::load]
    E --> F{registrationOnlyCompanyRegistration?}
    F -->|Yes| G[accountType=business設定]
    F -->|No| H[CustomerGroupRegistrationPageLoadedHook]
    G --> H
    H --> I[customer-group-register/index.html.twig]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | ログイン済みリダイレクト | ログイン済みの場合はアカウントホームへリダイレクト | ページアクセス時 |
| BR-002 | ゲストログインリダイレクト | ゲストログイン中はログアウトページへリダイレクト | ページアクセス時 |
| BR-003 | 法人専用グループ | registrationOnlyCompanyRegistration=trueのグループは法人アカウントタイプを強制 | フォーム表示時 |
| BR-004 | 登録対象グループ確認 | registrationSalesChannels経由で現在のSales Channelで登録を受け付けているグループのみ対象 | グループ検証時 |
| BR-005 | 承認待ち登録 | requestedGroupIdが設定された顧客は承認待ち状態となる | 登録時 |

### 計算ロジック

- 特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| グループ取得 | customer_group | SELECT | 顧客グループ情報を取得 |
| ページデータ取得 | - | SELECT | PageLoader経由で必要なデータを取得 |
| 顧客作成（登録時） | customer | INSERT | requestedGroupIdを設定して顧客を作成 |

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

#### customer_group

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, registration_only_company_registration, registration_title, registration_introduction, registration_seo_meta_description | id = customerGroupId | グループ情報取得 |

#### customer（登録処理時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | requested_group_id | customerGroupId | 承認待ちグループとして設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | リダイレクト | ログイン済み | アカウントホームへリダイレクト |
| - | リダイレクト | ゲストログイン中 | ログアウトページへリダイレクト |
| - | 404エラー | 顧客グループが存在しない、または登録を受け付けていない | 404ページ表示 |

### リトライ仕様

- バリデーションエラー時はフォームを再表示して修正可能

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

- ページ表示時はトランザクションを使用しない
- 登録処理は通常のアカウント登録と同じトランザクション仕様

## パフォーマンス要件

- ページ表示は500ms以内のレスポンスを目標

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

- 顧客グループIDはURLに含まれるが、登録を受け付けているグループのみ有効
- requestedGroupIdは承認待ち状態を示すのみで、即座にグループに参加するわけではない

## 備考

- requestedGroupIdが設定された顧客は、管理画面で承認されるまで通常の顧客グループに所属
- 顧客グループごとにカスタムの登録タイトルや説明文を設定可能
- registrationSalesChannelsで登録を受け付けるSales Channelを限定可能

---

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

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

### 推奨読解順序

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

顧客グループ登録ページのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CustomerGroupRegistrationPage.php | `src/Storefront/Page/Account/CustomerGroupRegistration/CustomerGroupRegistrationPage.php` | group, seoMetaInformationプロパティ |
| 1-2 | CustomerGroupEntity.php | `src/Core/Checkout/Customer/Aggregate/CustomerGroup/CustomerGroupEntity.php` | registrationOnlyCompanyRegistration等のプロパティ |

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

Storefrontのリクエストはregistercontrollerで受け付けられる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RegisterController.php | `src/Storefront/Controller/RegisterController.php` | customerGroupRegistration()メソッド（114-154行目） |

**主要処理フロー**:
1. **122-128行目**: ゲスト・ログイン済みチェック
2. **130-134行目**: HTTPキャッシュ設定
3. **136-138行目**: ページデータ読み込み
4. **140-142行目**: 法人専用グループの場合はaccountType設定
5. **144行目**: フック実行
6. **146-153行目**: テンプレートをレンダリング

#### Step 3: ページローダーを理解する

ページデータの読み込みはCustomerGroupRegistrationPageLoaderが担当する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractCustomerGroupRegistrationPageLoader.php | `src/Storefront/Page/Account/CustomerGroupRegistration/AbstractCustomerGroupRegistrationPageLoader.php` | 抽象定義 |

**読解のコツ**: ページローダーは顧客グループの翻訳情報やSEOメタ情報も取得する。

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

```
RegisterController::customerGroupRegistration (Storefront)
    │
    ├─ context.getCustomer() チェック
    │      ├─ [ゲスト] redirectToRoute('frontend.account.logout.page')
    │      └─ [会員] redirectToRoute('frontend.account.home.page')
    │
    ├─ CustomerGroupRegistrationPageLoader::load
    │      ├─ CustomerGroupEntity取得
    │      │      └─ registrationSalesChannels確認
    │      ├─ 翻訳情報取得
    │      └─ SEOメタ情報設定
    │
    ├─ registrationOnlyCompanyRegistration確認
    │      └─ [true] data.set('accountType', 'business')
    │
    ├─ CustomerGroupRegistrationPageLoadedHook (dispatch)
    │
    └─ renderStorefront('customer-group-register/index.html.twig')
```

### データフロー図

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

customerGroupId ───▶ RegisterController::customerGroupRegistration
                            │
                            ▼
                      ログイン状態確認
                            │
                      ┌─────┴─────┐
                      ▼           ▼
                   [ゲスト]     [会員]
                      │           │
                      ▼           ▼
               ログアウトへ   アカウントホームへ

                      [未ログイン]
                            │
                            ▼
                CustomerGroupRegistrationPageLoader::load
                            │
                            ▼
                      グループ設定確認
                            │
                      ┌─────┴─────┐
                      ▼           ▼
              法人専用?        通常
                      │           │
                      ▼           ▼
            accountType=business  │
                      │           │
                      └─────┬─────┘
                            ▼
                      フック実行
                            │
                            ▼
             customer-group-register/index.html.twig ───▶ [画面表示]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RegisterController.php | `src/Storefront/Controller/RegisterController.php` | コントローラ | 顧客グループ登録エンドポイント |
| AbstractCustomerGroupRegistrationPageLoader.php | `src/Storefront/Page/Account/CustomerGroupRegistration/AbstractCustomerGroupRegistrationPageLoader.php` | ローダー | ページデータの読み込み（抽象） |
| CustomerGroupRegistrationPage.php | `src/Storefront/Page/Account/CustomerGroupRegistration/CustomerGroupRegistrationPage.php` | ページ | ページのデータモデル |
| CustomerGroupRegistrationPageLoadedHook.php | `src/Storefront/Page/Account/CustomerGroupRegistration/CustomerGroupRegistrationPageLoadedHook.php` | フック | ページロード後のフック |
| CustomerGroupEntity.php | `src/Core/Checkout/Customer/Aggregate/CustomerGroup/CustomerGroupEntity.php` | エンティティ | 顧客グループデータモデル |
| CustomerEntity.php | `src/Core/Checkout/Customer/CustomerEntity.php` | エンティティ | 顧客データモデル（requestedGroupId） |
