# 機能設計書 54-住所編集

## 概要

本ドキュメントは、既存住所の編集機能の設計を記述する。

### 本機能の処理概要

本機能は、ログイン済みユーザーが既に登録した配送先・請求先住所を編集する機能を提供する。ユーザーは住所情報をフォームで修正し、バックエンドAPIを介してデータベースの既存住所を更新できる。

**業務上の目的・背景**：ユーザーの住所情報は引っ越しや職場変更などにより変更が必要になることがある。既存住所を削除して新規登録するのではなく、直接編集できることで、ユーザーの利便性が向上する。また、住所の軽微な修正（番地の誤り等）にも迅速に対応できる。

**機能の利用シーン**：住所一覧画面で特定の住所カードの「編集」ボタンをタップした時、登録済み住所の情報を修正したい時などにユーザーが利用する。

**主要な処理内容**：
1. 既存住所データをフォームに初期表示
2. 国・州リストのマスターデータ取得
3. ユーザーによる住所情報の修正
4. 入力バリデーション
5. バックエンドAPIへの住所更新リクエスト
6. 更新完了後の前画面への遷移

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

**権限による制御**：ログイン済みユーザーのみがアクセス可能。自身の住所データのみ編集可能。

## 関連画面

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

## 機能種別

データ更新（CRUD - Update）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| addressId | int | Yes | 住所ID | 存在する住所ID |
| 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 | デフォルト住所フラグ | - |

### 入力データソース

- 画面遷移時パラメータ: AddressNavigationData（isEdit=true, addressModel=既存住所データ）
- 画面入力フォーム
- Google Maps API: 位置情報による住所補完

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ AddEditAddressBlocの初期化とAddressCountryEventの発行
2. 既存データ設定
   └─ addressModelから各フォームフィールドに値を設定
3. 国・州データ取得
   └─ AddEditAddressRepositoryImp.callCountriesData()で国・州リストを取得
4. フォーム表示
   └─ 既存データが設定されたフォームを表示
5. ユーザー修正
   └─ 各フィールドの値を修正
6. バリデーション
   └─ フォームキーによる入力値検証
7. API呼び出し
   └─ FetchEditAddressEventを発行してAPIを呼び出し
8. レスポンス処理
   └─ 成功時は前画面に戻り、失敗時はエラーメッセージを表示
```

### フローチャート

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

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-54-01 | 既存データ表示 | 編集モード時は既存住所データを各フィールドに初期表示 | isEdit=true |
| BR-54-02 | 国選択連動 | 国を選択すると、その国の州リストが更新される | 国選択時 |
| BR-54-03 | 州入力形式 | 州リストがある国は選択式、ない国はテキスト入力 | 国選択後 |
| BR-54-04 | 必須項目 | firstName, lastName, address, country, state, city, postCode, phoneは必須 | 保存時 |
| BR-54-05 | 住所ID必須 | 更新時は必ず住所IDが必要 | 更新API呼び出し時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 国・州取得 | countries, country_states | SELECT | 国・州マスターデータを取得 |
| 住所更新 | customer_addresses | UPDATE | 既存住所を更新 |

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

#### customer_addresses

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | first_name | フォーム入力値 | id = addressId |
| UPDATE | last_name | フォーム入力値 | id = addressId |
| UPDATE | email | フォーム入力値 | id = addressId |
| UPDATE | company_name | フォーム入力値 | id = addressId |
| UPDATE | address | フォーム入力値 | id = addressId |
| UPDATE | country | フォーム入力値（国コード） | id = addressId |
| UPDATE | state | フォーム入力値（州コード/名） | id = addressId |
| UPDATE | city | フォーム入力値 | id = addressId |
| UPDATE | postcode | フォーム入力値 | id = addressId |
| UPDATE | phone | フォーム入力値 | id = addressId |
| UPDATE | vat_id | フォーム入力値 | id = addressId |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

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

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

## パフォーマンス要件

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

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

- ログイン済みユーザーのみアクセス可能
- 認証トークン付きでAPIリクエスト送信
- 自身の住所データのみ更新可能（バックエンドで権限チェック）

## 備考

- 住所追加機能と同一の画面・コンポーネントを使用（isEditフラグで動作切替）
- 編集時は既存のbillingAddressId、shippingAddressIdを保持して返却
- 更新完了後、2秒のディレイを入れて前画面に遷移（ユーザビリティ考慮）

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | address_model.dart | `lib/screens/address_list/data_model/address_model.dart` | AddressDataクラスの構造 |
| 1-2 | update_address_model.dart | `lib/screens/address_list/data_model/update_address_model.dart` | 更新レスポンスモデル |

**読解のコツ**: UpdateAddressModelはBaseModelを継承し、更新成功/失敗の情報とメッセージを保持する。

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

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

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

**主要処理フロー**:
1. **63-95行目**: initStateで編集モード時に既存データを各フィールドに設定
2. **287-306行目**: buildUIで編集モード時の国・州データ設定
3. **176-221行目**: FetchEditAddressStateのリスナーで更新結果を処理

#### 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` | ステート定義 |

**主要処理フロー**:
- **29-64行目** (add_edit_address_bloc.dart): FetchEditAddressEventの処理
- **32-47行目** (add_edit_address_event.dart): FetchEditAddressEventの定義
- **38-51行目** (add_edit_address_state.dart): FetchEditAddressStateの定義

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

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

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

**主要処理フロー**:
- **48-86行目**: callEditAddressApiメソッドでApiClient().updateAddress()を呼び出し

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

```
AddNewAddress (add_edit_address_screen.dart) ※isEdit=true
    │
    ├─ AddEditAddressBloc (add_edit_address_bloc.dart)
    │      │
    │      └─ AddEditAddressRepositoryImp (add_edit_address_repository.dart)
    │             │
    │             ├─ ApiClient.updateAddress()
    │             └─ ApiClient.getCountryStateList()
    │
    ├─ GetAddressForm (get_address_form.dart)
    │      └─ TextFormFieldウィジェット群（既存データ初期表示）
    │
    ├─ CommonDropDownField
    │      └─ 国・州選択ドロップダウン（既存選択値設定）
    │
    ├─ SaveAddressButton (save_address_button.dart)
    │      └─ FetchEditAddressEvent発行
    │
    └─ LocationScreen (location_screen.dart) ※オプション
           └─ Google Maps API
```

### データフロー図

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

AddressNavigationData ───▶ initState ───▶ フォーム初期値設定
(isEdit=true, addressModel)

AddressCountryEvent ───▶ AddEditAddressBloc ───▶ AddressCountryState
                                │
                                ▼
                     AddEditAddressRepositoryImp
                                │
                                ▼
                     ApiClient.getCountryStateList()
                                │
                                ▼
                          CountriesData
                                │
                                ▼
フォーム修正 ───────────▶ FetchEditAddressEvent ───▶ AddEditAddressBloc
(addressId含む)                 │
                                ▼
                     AddEditAddressRepositoryImp
                                │
                                ▼
                     ApiClient.updateAddress()
                                │
                                ▼
                    UpdateAddressModel ───▶ 成功/失敗通知 ───▶ 前画面遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| 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` | ソース | ステート定義 |
| update_address_model.dart | `lib/screens/address_list/data_model/update_address_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` | ソース | 保存ボタン |
