# 機能設計書 53-住所追加

## 概要

本ドキュメントは、新規住所の登録機能の設計を記述する。

### 本機能の処理概要

本機能は、ログイン済みユーザーが新しい配送先・請求先住所を登録する機能を提供する。ユーザーは住所情報をフォームに入力し、バックエンドAPIを介してデータベースに新規住所を保存できる。また、位置情報機能を利用した住所入力のサポートも提供される。

**業務上の目的・背景**：ECサイトでの購入プロセスにおいて、ユーザーが複数の配送先を登録できることは重要である。自宅、職場、贈り先など、用途に応じた住所を事前に登録しておくことで、チェックアウト時の入力負荷を軽減し、購入完了率の向上に貢献する。

**機能の利用シーン**：住所一覧画面から「新規住所追加」ボタンをタップした時、チェックアウト時に新しい住所が必要な時、ダッシュボードの住所タブから追加ボタンをタップした時などにユーザーが利用する。

**主要な処理内容**：
1. 国・州リストのマスターデータ取得
2. 住所入力フォームの表示（名前、会社名、住所、国、州、市、郵便番号、電話番号、VAT ID）
3. 位置情報を利用した住所入力補助
4. 入力バリデーション
5. バックエンドAPIへの新規住所登録
6. 登録完了後の前画面への遷移

**関連システム・外部連携**：GraphQL APIを介してバックエンドサーバーに住所データを送信。Google Maps APIを利用した位置情報による住所入力補助。

**権限による制御**：ログイン済みユーザーのみがアクセス可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | 住所追加・編集画面 | 主画面 | 新規住所の登録処理 |
| 23 | 住所一覧画面 | 遷移元画面 | 住所追加ボタンから遷移 |
| 25 | 位置情報選択画面 | 補助画面 | 位置情報による住所入力 |

## 機能種別

データ登録（CRUD - Create）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| firstName | String | Yes | 名（ファーストネーム） | 空文字不可 |
| lastName | String | Yes | 姓（ラストネーム） | 空文字不可 |
| email | String | No | メールアドレス | メール形式 |
| companyName | String | No | 会社名 | - |
| address | String | Yes | 住所 | 空文字不可 |
| country | String | Yes | 国コード | 国リストに存在 |
| state | String | Yes | 州コード/名 | 州リストに存在または空文字不可 |
| city | String | Yes | 市区町村 | 空文字不可 |
| postCode | String | Yes | 郵便番号 | 空文字不可 |
| phone | String | Yes | 電話番号 | 空文字不可 |
| vatId | String | No | VAT ID | - |
| isDefault | bool | No | デフォルト住所フラグ | - |

### 入力データソース

- 画面入力フォーム
- SharedPreferences: ユーザー名、メールアドレス（デフォルト値として使用）
- Google Maps API: 位置情報による住所補完

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| status | bool | 処理成功/失敗 |
| message | String | 処理結果メッセージ |
| addressData | AddressData | 登録された住所データ |

### 出力先

- バックエンドデータベース（GraphQL API経由）
- 画面遷移（前画面に戻りつつ登録データを返却）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ AddEditAddressBlocの初期化とAddressCountryEventの発行
2. 国・州データ取得
   └─ AddEditAddressRepositoryImp.callCountriesData()で国・州リストを取得
3. フォーム表示
   └─ ユーザー情報のデフォルト値を設定してフォームを表示
4. ユーザー入力
   └─ 各フィールドへの入力を受付
5. 位置情報入力（オプション）
   └─ 位置情報画面から住所情報を取得して各フィールドに反映
6. バリデーション
   └─ フォームキーによる入力値検証
7. API呼び出し
   └─ FetchAddAddressEventを発行してAPIを呼び出し
8. レスポンス処理
   └─ 成功時は前画面に戻り、失敗時はエラーメッセージを表示
```

### フローチャート

```mermaid
flowchart TD
    A[画面初期化] --> B[AddressCountryEvent発行]
    B --> C[国・州データ取得]
    C --> D[フォーム表示]
    D --> E{位置情報使用?}
    E -->|Yes| F[位置情報画面へ]
    F --> G[住所情報取得]
    G --> D
    E -->|No| H[手動入力]
    H --> I{入力完了?}
    I -->|No| H
    I -->|Yes| J[保存ボタンタップ]
    J --> K{バリデーション}
    K -->|失敗| L[エラー表示]
    L --> H
    K -->|成功| M[FetchAddAddressEvent発行]
    M --> N[API呼び出し]
    N --> O{レスポンス}
    O -->|成功| P[成功通知]
    P --> Q[前画面へ遷移]
    O -->|失敗| R[エラー通知]
    R --> D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-53-01 | デフォルト値設定 | ユーザー名・メールアドレスは保存済みの値をデフォルト設定 | 新規追加時 |
| BR-53-02 | 国選択連動 | 国を選択すると、その国の州リストが更新される | 国選択時 |
| BR-53-03 | 州入力形式 | 州リストがある国は選択式、ない国はテキスト入力 | 国選択後 |
| BR-53-04 | 必須項目 | firstName, lastName, address, country, state, city, postCode, phoneは必須 | 保存時 |
| BR-53-05 | 位置情報連携 | 位置情報画面から戻った際、取得した住所情報を各フィールドに自動入力 | 位置情報使用時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 国・州取得 | countries, country_states | SELECT | 国・州マスターデータを取得 |
| 住所追加 | customer_addresses | INSERT | 新規住所を登録 |

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

#### customer_addresses

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | customer_id | ログインユーザーID | 自動設定 |
| INSERT | first_name | フォーム入力値 | - |
| INSERT | last_name | フォーム入力値 | - |
| INSERT | email | フォーム入力値 | - |
| INSERT | company_name | フォーム入力値 | - |
| INSERT | address | フォーム入力値 | - |
| INSERT | country | フォーム入力値（国コード） | - |
| INSERT | state | フォーム入力値（州コード/名） | - |
| INSERT | city | フォーム入力値 | - |
| INSERT | postcode | フォーム入力値 | - |
| INSERT | phone | フォーム入力値 | - |
| INSERT | vat_id | フォーム入力値 | - |
| INSERT | default_address | フォーム入力値 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | 必須項目未入力 | フィールドにエラーメッセージ表示 |
| - | API通信エラー | ネットワーク障害 | エラー通知を表示 |
| - | サーバーエラー | バックエンド処理失敗 | graphqlErrorsメッセージを表示 |

### リトライ仕様

エラー発生時は画面に留まり、ユーザーが再度保存ボタンを押すことで再試行可能。

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

API呼び出しはバックエンド側でトランザクション管理される。クライアント側では単一のAPI呼び出しのため、特別なトランザクション管理は不要。

## パフォーマンス要件

- 国・州データ取得: 2秒以内
- 住所登録API呼び出し: 3秒以内
- 位置情報からの住所取得: Google Maps APIの応答に依存

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

- ログイン済みユーザーのみアクセス可能
- 認証トークン付きでAPIリクエスト送信
- 位置情報の使用はユーザーの許可が必要

## 備考

- チェックアウト時の住所追加（isCheckout=true）と通常の住所追加で共通の画面を使用
- 位置情報機能はAppBarのアクションボタンからアクセス
- 登録完了後、2秒のディレイを入れて前画面に遷移（ユーザビリティ考慮）

---

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

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

### 推奨読解順序

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

住所追加で使用するデータモデルを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | address_model.dart | `lib/screens/address_list/data_model/address_model.dart` | AddressDataクラスの構造 |
| 1-2 | country_model.dart | `lib/screens/address_list/data_model/country_model.dart` | CountriesData, Data, Statesクラスの構造 |

**読解のコツ**: CountriesDataは国のリストを保持し、各Dataは国コード、名前、州リスト（States）を持つ。州がない国も存在するため、statesの有無をチェックする必要がある。

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

住所追加画面のメインウィジェットを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | add_edit_address_screen.dart | `lib/screens/add_edit_address/view/add_edit_address_screen.dart` | 画面構築とBloc連携ロジック |

**主要処理フロー**:
1. **61-101行目**: initStateでフォームのデフォルト値設定（編集時は既存データ、新規時はユーザー情報）
2. **115-170行目**: buildメソッドでScaffoldとAppBarを構築、位置情報ボタンを配置
3. **127-150行目**: 位置情報画面からの戻り値を各フィールドに設定
4. **173-277行目**: BlocConsumerでリスナーとビルダーを設定
5. **279-435行目**: buildUIメソッドでフォームを構築

#### Step 3: Bloc層を理解する

状態管理のロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | add_edit_address_bloc.dart | `lib/screens/add_edit_address/bloc/add_edit_address_bloc.dart` | イベント処理とステート発行 |
| 3-2 | add_edit_address_event.dart | `lib/screens/add_edit_address/bloc/add_edit_address_event.dart` | イベント定義 |
| 3-3 | add_edit_address_state.dart | `lib/screens/add_edit_address/bloc/add_edit_address_state.dart` | ステート定義 |

**主要処理フロー**:
- **65-87行目** (add_edit_address_bloc.dart): FetchAddAddressEventの処理
- **88-96行目** (add_edit_address_bloc.dart): AddressCountryEventの処理
- **15-30行目** (add_edit_address_event.dart): FetchAddAddressEventの定義

#### Step 4: Repository層を理解する

API呼び出しのロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | add_edit_address_repository.dart | `lib/screens/add_edit_address/bloc/add_edit_address_repository.dart` | API呼び出し実装 |

**主要処理フロー**:
- **88-122行目**: callCreateAddressメソッドでApiClient().createAddress()を呼び出し
- **123-133行目**: callCountriesDataメソッドで国・州リストを取得

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

```
AddNewAddress (add_edit_address_screen.dart)
    │
    ├─ AddEditAddressBloc (add_edit_address_bloc.dart)
    │      │
    │      └─ AddEditAddressRepositoryImp (add_edit_address_repository.dart)
    │             │
    │             ├─ ApiClient.createAddress()
    │             └─ ApiClient.getCountryStateList()
    │
    ├─ GetAddressForm (get_address_form.dart)
    │      └─ TextFormFieldウィジェット群
    │
    ├─ CommonDropDownField
    │      └─ 国・州選択ドロップダウン
    │
    ├─ SaveAddressButton (save_address_button.dart)
    │      └─ FetchAddAddressEvent発行
    │
    └─ LocationScreen (location_screen.dart) ※オプション
           └─ Google Maps API
```

### データフロー図

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

AddressCountryEvent ───▶ AddEditAddressBloc ───▶ AddressCountryState
                                │
                                ▼
                     AddEditAddressRepositoryImp
                                │
                                ▼
                     ApiClient.getCountryStateList()
                                │
                                ▼
                          CountriesData
                                │
                                ▼
フォーム入力 ───────────▶ FetchAddAddressEvent ───▶ AddEditAddressBloc
                                │
                                ▼
                     AddEditAddressRepositoryImp
                                │
                                ▼
                     ApiClient.createAddress()
                                │
                                ▼
                          BaseModel ───▶ 成功/失敗通知 ───▶ 前画面遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| add_edit_address_screen.dart | `lib/screens/add_edit_address/view/add_edit_address_screen.dart` | ソース | メイン画面 |
| add_edit_address_bloc.dart | `lib/screens/add_edit_address/bloc/add_edit_address_bloc.dart` | ソース | 状態管理 |
| add_edit_address_repository.dart | `lib/screens/add_edit_address/bloc/add_edit_address_repository.dart` | ソース | API呼び出し |
| add_edit_address_event.dart | `lib/screens/add_edit_address/bloc/add_edit_address_event.dart` | ソース | イベント定義 |
| add_edit_address_state.dart | `lib/screens/add_edit_address/bloc/add_edit_address_state.dart` | ソース | ステート定義 |
| country_model.dart | `lib/screens/address_list/data_model/country_model.dart` | ソース | 国・州データモデル |
| get_address_form.dart | `lib/screens/add_edit_address/view/widget/get_address_form.dart` | ソース | 住所入力フォーム |
| save_address_button.dart | `lib/screens/add_edit_address/view/widget/save_address_button.dart` | ソース | 保存ボタン |
| location_screen.dart | `lib/screens/location/view/location_screen.dart` | ソース | 位置情報画面 |
