# 機能設計書 62-お問い合わせ送信

## 概要

本ドキュメントは、お問い合わせ送信機能の設計仕様を定義する。ユーザーがお問い合わせフォームからショップ運営者へ連絡を送信する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトでは顧客からの問い合わせを受け付けることが顧客満足度向上と売上に直結する重要な機能である。商品に関する質問、注文に関する問い合わせ、返品・交換の相談など、様々な目的でユーザーがショップと連絡を取る手段を提供する。

**機能の利用シーン**：
- 商品について詳細を問い合わせたい場合
- 注文に関するトラブルや質問がある場合
- 返品・交換について相談したい場合
- ショップへの一般的なフィードバックを送りたい場合
- ナビゲーションドロワーのCMSページ一覧から「お問い合わせ」を選択した場合

**主要な処理内容**：
1. ユーザーがフォームに名前、メールアドレス、電話番号、メッセージを入力
2. クライアント側でバリデーション（必須項目チェック、メールフォーマット検証）
3. GraphQL APIを呼び出してお問い合わせ内容を送信
4. 送信結果に応じて成功/失敗通知を表示
5. 成功時はフォームをクリア

**関連システム・外部連携**：
- Bagisto GraphQL API（contactUs mutation）
- ショップ側のメール配信システム（バックエンドで処理）

**権限による制御**：認証状態に関わらず、すべてのユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 31 | お問い合わせ画面 | 主画面 | お問い合わせフォームからの連絡送信処理 |

## 機能種別

データ送信処理（CREATE操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | 問い合わせ者名 | 空でないこと |
| email | String | Yes | 連絡先メールアドレス | 空でないこと、有効なメールフォーマット |
| phone | String | Yes | 連絡先電話番号 | 空でないこと |
| message | String | Yes | 問い合わせ内容 | 空でないこと（trim後） |

### 入力データソース

- ContactUsPage画面のTextFormFieldウィジェットからのユーザー入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | bool | 送信成功/失敗 |
| message | String | 結果メッセージ |

### 出力先

- 画面上の通知（ShowMessage.showNotification）
- SnackBar表示

## 処理フロー

### 処理シーケンス

```
1. ユーザーがフォームに入力
   └─ 名前、メール、電話番号、メッセージを入力
2. 送信ボタンタップ
   └─ _submitFormメソッド呼び出し
3. クライアントサイドバリデーション
   └─ FormState.validate()で全項目を検証
4. バリデーション成功時
   └─ ContactUsEventをBlocに発行
5. ContactUsScreenBlocでイベント処理
   └─ ContactUsScreenRepository.contactUsRepoScreenを呼び出し
6. APIクライアント呼び出し
   └─ GraphQL mutation実行（contactUs）
7. レスポンス処理
   └─ BaseModelにデシリアライズ
8. 状態更新
   └─ ContactUsState.success または ContactUsState.fail を発行
9. UI更新
   └─ BlocConsumerのlistenerで通知を表示
10. 成功時のフォームクリア
    └─ 全TextEditingControllerをclear
```

### フローチャート

```mermaid
flowchart TD
    A[フォーム入力] --> B[送信ボタンタップ]
    B --> C{クライアント側バリデーション}
    C -->|失敗| D[エラーメッセージ表示]
    C -->|成功| E[ContactUsEvent発行]
    E --> F[ContactUsScreenBloc処理]
    F --> G[Repository呼び出し]
    G --> H[ApiClient.contactUsApiClient]
    H --> I[GraphQL mutation実行]
    I --> J{API成功?}
    J -->|Yes| K[ContactUsState.success]
    J -->|No| L[ContactUsState.fail]
    K --> M[成功通知表示]
    M --> N[フォームクリア]
    L --> O[エラー通知表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-62-01 | 必須項目 | 名前、メール、電話番号、メッセージはすべて必須 | 常時 |
| BR-62-02 | メールフォーマット | メールアドレスは有効な形式である必要がある | 常時 |
| BR-62-03 | メッセージトリム | メッセージの前後空白を除去して空でないこと | 常時 |
| BR-62-04 | 成功時クリア | 送信成功時は全入力フィールドをクリア | API成功時 |

### 計算ロジック

該当なし

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

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

本機能はGraphQL APIを通じてバックエンドにデータを送信する。クライアント側でのデータベース操作は行わない。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| お問い合わせ送信 | contacts（バックエンド） | INSERT | 問い合わせ内容を保存 |

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

#### contacts（バックエンド想定）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | ユーザー入力値 | 問い合わせ者名 |
| INSERT | email | ユーザー入力値 | 連絡先メール |
| INSERT | phone | ユーザー入力値 | 連絡先電話番号 |
| INSERT | message | ユーザー入力値 | 問い合わせ内容 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | 必須項目が未入力 | フィールド下にエラーメッセージ表示 |
| - | メールフォーマットエラー | 無効なメールアドレス | 「有効なメールアドレスを入力してください」表示 |
| - | API通信エラー | ネットワーク接続失敗 | ContactUsState.fail発行、赤い通知表示 |
| - | サーバーエラー | バックエンド処理失敗 | graphqlErrorsメッセージを表示 |

### リトライ仕様

自動リトライは実装されていない。ユーザーは再度送信ボタンを押す必要がある。

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

バックエンド側で管理。クライアント側ではAPIリクエストを1回発行するのみ。

## パフォーマンス要件

- お問い合わせ送信: 5秒以内にレスポンス

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

- 認証不要で利用可能（ゲストユーザー対応）
- 入力データはGraphQL経由でバックエンドに送信
- メールアドレスのフォーマット検証をクライアント側で実施
- バックエンド側でのスパム対策・レート制限は別途対応

## 備考

- お問い合わせ内容はバックエンドのメール配信システムでショップ運営者に通知される
- EmailValidatorミックスインでメール検証を実装

---

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

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

### 推奨読解順序

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

お問い合わせ機能ではBaseModelを使用してレスポンスを処理する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | graphql_base_model.dart | `lib/data_model/graphql_base_model.dart` | BaseModelクラスのsuccess、message、graphqlErrorsフィールド |

**読解のコツ**:
- BaseModelは汎用的なAPIレスポンスモデル
- successがtrueなら成功、falseならerrorを参照

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

処理の起点となる画面ファイルを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | contact_us_view.dart | `lib/screens/contact_us/contact_us_view.dart` | ContactUsPageウィジェット、フォーム構成、バリデーション |

**主要処理フロー**:
1. **14-25行目**: 状態変数とTextEditingControllerの定義
2. **27-30行目**: initStateでContactUsScreenBlocを取得
3. **46-71行目**: BlocConsumerでContactUsBaseStateを監視し、成功/失敗時の通知処理
4. **73-228行目**: _reviewFormでフォームUIを構築
5. **86-199行目**: 各TextFormFieldの定義とバリデーション
6. **230-244行目**: _submitFormでバリデーション後にContactUsEventを発行

#### Step 3: イベント・状態管理を理解する

BLoCパターンによる状態管理の仕組みを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | contact_us_event.dart | `lib/screens/contact_us/bloc/contact_us_event.dart` | ContactUsEventの定義（name, email, phone, describe） |
| 3-2 | contact_us_state.dart | `lib/screens/contact_us/bloc/contact_us_state.dart` | ContactUsStatus列挙型、ContactUsStateの定義 |
| 3-3 | contact_us_bloc.dart | `lib/screens/contact_us/bloc/contact_us_bloc.dart` | イベントからAPIを呼び出し、状態を発行する処理 |

**主要処理フロー**:
- **contact_us_event.dart 24-31行目**: ContactUsEventでname, email, phone, describeを保持
- **contact_us_state.dart 18行目**: ContactUsStatus列挙型でsuccess/failを定義
- **contact_us_state.dart 20-27行目**: ContactUsStateでresponse/successMsg/errorを保持
- **contact_us_bloc.dart 31-48行目**: mapEventToStateでContactUsEventを処理

#### Step 4: リポジトリ層を理解する

API呼び出しの抽象化層を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | contact_us_repository.dart | `lib/screens/contact_us/bloc/contact_us_repository.dart` | ContactUsScreenRepositoryインターフェースと実装 |

**主要処理フロー**:
- **15-19行目**: ContactUsScreenRepository抽象クラスでcontactUsRepoScreenメソッドを定義
- **23-33行目**: ContactUsScreenRepositoryImpでApiClient().contactUsApiClientを呼び出し

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

```
ContactUsPage (contact_us_view.dart)
    │
    ├─ _submitForm
    │      ├─ FormState.validate()
    │      └─ ContactUsScreenBloc.add(ContactUsEvent)
    │
    └─ BlocConsumer<ContactUsScreenBloc, ContactUsBaseState>
           │
           ContactUsScreenBloc (contact_us_bloc.dart)
               │
               └─ mapEventToState
                      │
                      ContactUsScreenRepository.contactUsRepoScreen
                          │
                          ApiClient.contactUsApiClient
                              │
                              GraphQL Mutation: contactUs
```

### データフロー図

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

名前 ─────────────┐
                 │
メール ───────────┼────▶ FormState.validate() ────▶ ContactUsEvent
                 │                                        │
電話番号 ─────────┤                                        ▼
                 │                           ContactUsScreenBloc
メッセージ ───────┘                                        │
                                                          ▼
                                              ContactUsScreenRepository
                                                          │
                                                          ▼
                                              ApiClient.contactUsApiClient
                                                          │
                                                          ▼
                                              GraphQL API (contactUs)
                                                          │
                                                          ▼
                                              BaseModel ───▶ ContactUsState
                                                                   │
                                                                   ▼
                                                          通知表示 & フォームクリア
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| contact_us_view.dart | `lib/screens/contact_us/contact_us_view.dart` | ソース | お問い合わせフォーム画面 |
| contact_us_bloc.dart | `lib/screens/contact_us/bloc/contact_us_bloc.dart` | ソース | 状態管理BLoC |
| contact_us_event.dart | `lib/screens/contact_us/bloc/contact_us_event.dart` | ソース | イベント定義 |
| contact_us_state.dart | `lib/screens/contact_us/bloc/contact_us_state.dart` | ソース | 状態定義 |
| contact_us_repository.dart | `lib/screens/contact_us/bloc/contact_us_repository.dart` | ソース | API呼び出しリポジトリ |
| api_client.dart | `lib/services/api_client.dart` | ソース | GraphQL APIクライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | ソース | GraphQLクエリ定義 |
| graphql_base_model.dart | `lib/data_model/graphql_base_model.dart` | ソース | 汎用レスポンスモデル |
