# 機能設計書 73-位置情報取得

## 概要

本ドキュメントは、ECモバイルアプリケーションにおけるユーザーの位置情報取得および住所選択機能の設計を記述する。

### 本機能の処理概要

本機能はGoogle Maps APIとデバイスのGPS機能を活用し、ユーザーが配送先住所を地図上から視覚的に選択できるようにする。現在地の自動取得、地図上でのピン移動による位置選択、場所検索によるジオコーディングを通じて、正確な住所情報を取得する。

**業務上の目的・背景**：ECサイトにおいて、正確な配送先住所の入力は非常に重要である。手動入力では入力ミスや不完全な住所が発生しやすいが、地図ベースの住所選択により、位置座標から自動的に住所コンポーネント（番地、市区町村、都道府県、郵便番号等）を取得でき、入力ミスを軽減し、配送精度を向上させることができる。

**機能の利用シーン**：
- 新規住所登録時の住所入力補助
- 既存住所の編集時の位置確認・修正
- 現在地を配送先として設定する場合

**主要な処理内容**：
1. デバイスの現在位置取得（GPS）
2. Google Mapsでの地図表示と操作
3. 地図上のカメラ移動による位置選択
4. 逆ジオコーディングによる住所コンポーネント取得
5. 場所検索（テキスト検索）によるジオコーディング
6. 選択した住所情報の呼び出し元画面への返却

**関連システム・外部連携**：
- Google Maps SDK for Flutter
- Google Places API（場所検索）
- Flutter locationパッケージ（GPS位置取得）
- geocodingパッケージ（逆ジオコーディング）

**権限による制御**：位置情報の取得にはデバイスの位置情報アクセス許可が必要。許可されていない場合やエラー発生時は画面を閉じる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 位置情報選択画面 | 主画面 | Googleマップ表示、住所選択操作 |
| 24 | 住所追加・編集画面 | 呼び出し元 | 地図アイコンタップで本画面を呼び出し |

## 機能種別

位置情報取得 / ジオコーディング / 外部API連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| address | String? | No | 初期表示時の住所文字列（ジオコーディング用） | - |

### 入力データソース

- デバイスGPS（現在位置）
- Google Places API（場所検索）
- Google Maps（カメラ位置）
- geocodingパッケージ（住所→座標変換）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| street1 | String | 番地（street） |
| street2 | String | 通り名（thoroughfare） |
| street3 | String | 地区（subLocality） |
| city | String | 市区町村（locality） |
| state | String | 都道府県（administrativeArea） |
| zip | String | 郵便番号（postalCode） |
| country | String | 国名（country） |
| countryCode | String | 国コード（isoCountryCode） |

### 出力先

- Navigator.pop()により呼び出し元画面へMap<String, dynamic>形式で返却

## 処理フロー

### 処理シーケンス

```
1. LocationScreen初期化
   └─ addressパラメータがあれば保持
   └─ getCurrentLocation()呼び出し

2. 現在位置取得処理（getCurrentLocation）
   └─ addressパラメータからジオコーディング試行
   └─ 失敗時はデバイスGPSから現在位置取得
   └─ latitude/longitude設定
   └─ カメラ位置をアニメーション移動

3. 地図操作
   └─ onCameraMove: position更新
   └─ onCameraIdle: getLocation()呼び出し

4. 逆ジオコーディング（getLocation）
   └─ placemarkFromCoordinates()で座標→住所変換
   └─ address文字列とaddressMap生成

5. 場所検索（PlaceSearch）
   └─ テキスト入力でSearchPlaceEvent発行
   └─ LocationRepositoryで Google Places API呼び出し
   └─ 結果選択でLatLngを返却
   └─ placeSearch()でカメラ移動

6. 住所選択完了
   └─ 下部エリアタップでNavigator.pop(addressMap)
```

### フローチャート

```mermaid
flowchart TD
    A[LocationScreen開始] --> B{addressパラメータあり?}
    B -->|Yes| C[addressからジオコーディング]
    B -->|No| D[デバイスGPS取得]
    C --> E{ジオコーディング成功?}
    E -->|Yes| F[座標設定]
    E -->|No| D
    D --> G{GPS取得成功?}
    G -->|Yes| F
    G -->|No| H[画面を閉じる]
    F --> I[地図表示・カメラ移動]
    I --> J{ユーザー操作}
    J -->|カメラ移動| K[onCameraMove: position更新]
    J -->|カメラ停止| L[onCameraIdle: getLocation]
    J -->|現在地ボタン| D
    J -->|検索ボタン| M[PlaceSearch画面へ]
    J -->|住所エリアタップ| N[Navigator.pop with addressMap]
    K --> J
    L --> O[逆ジオコーディング]
    O --> P[addressMap更新]
    P --> J
    M --> Q{場所選択?}
    Q -->|Yes| R[placeSearch: カメラ移動]
    Q -->|No| J
    R --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-73-01 | 初期位置決定 | addressパラメータがある場合はそこからジオコーディング、なければGPS現在位置 | 画面初期化時 |
| BR-73-02 | デフォルト座標 | GPS取得失敗時はデフォルト座標（28.6296987, 77.3762753）を使用 | GPS取得失敗時 |
| BR-73-03 | 逆ジオコーディング | カメラ移動停止時に自動的に住所情報を取得 | カメラ操作完了時 |
| BR-73-04 | 住所コンポーネント分解 | Placemarkから各住所コンポーネントを個別に抽出 | 逆ジオコーディング時 |
| BR-73-05 | 言語設定連動 | 場所検索APIはGlobalData.localeの言語設定を使用 | 検索実行時 |

### 計算ロジック

特になし。

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

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

本機能ではデータベース操作は発生しない。外部APIからのデータ取得のみ。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 位置情報取得失敗 | GPS許可なし/取得エラー | 画面を閉じる（Navigator.pop） |
| - | ジオコーディング失敗 | addressパラメータから座標変換失敗 | GPSフォールバック |
| - | 逆ジオコーディング失敗 | 座標から住所変換失敗 | address/addressMapが空のまま |
| - | Places API エラー | 検索API呼び出し失敗 | SearchPlaceErrorState発行 |

### リトライ仕様

特別なリトライ処理は実装されていない。ユーザーは「現在地」ボタンで再取得を試みることができる。

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

本機能ではトランザクション管理は不要（API呼び出しのみ）。

## パフォーマンス要件

- 地図表示：Google Maps SDKのパフォーマンスに依存
- 逆ジオコーディング：カメラ停止後1-2秒以内で住所取得
- 場所検索：入力変更ごとにAPI呼び出し（デバウンス処理なし）

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

- Google Maps APIキーはソースコード内に記載（本番環境では環境変数化推奨）
- 位置情報は呼び出し元画面への返却のみに使用され、永続化されない

## 備考

- デフォルト座標はインド・ノイダ付近（Webkul社所在地と思われる）
- ズームレベルは16.0固定
- 地図上の中央にピンアイコンを固定表示し、ユーザーは地図をスクロールして位置を選択

---

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

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

### 推奨読解順序

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

位置情報機能で使用されるデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | location_state.dart | `lib/screens/location/bloc/location_state.dart` | LocationScreenState、SearchPlaceSuccessState、GooglePlaceModel |
| 1-2 | location_event.dart | `lib/screens/location/bloc/location_event.dart` | SearchPlaceEvent、SearchPlaceInitialEvent |

**読解のコツ**: LocationScreenStateはEquatableを継承しており、状態比較に使用される。GooglePlaceModelはGoogle Places APIのレスポンスをマッピングしたモデルクラス。

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

LocationScreenの初期化と地図表示を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | location_screen.dart | `lib/screens/location/view/location_screen.dart` | StatefulWidgetの構造、状態変数 |

**主要処理フロー**:
1. **27-38行目**: 状態変数定義（latitude, longitude, position, address, addressMap等）
2. **40-48行目**: initState()でaddressパラメータ取得とgetCurrentLocation()呼び出し
3. **55-214行目**: _buildUI()でGoogle Map表示とUI構築

#### Step 3: 現在位置取得処理を理解する

GPSとジオコーディングによる位置取得を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | location_screen.dart | `lib/screens/location/view/location_screen.dart` | getCurrentLocation()メソッド |

**主要処理フロー**:
- **216-243行目**: getCurrentLocation()
  - **219行目**: addressからlocationFromAddress()でジオコーディング試行
  - **220-224行目**: 成功時は座標設定
  - **225-227行目**: 失敗時はGPS現在位置取得
  - **238-242行目**: カメラをアニメーション移動

#### Step 4: 逆ジオコーディング処理を理解する

座標から住所への変換処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | location_screen.dart | `lib/screens/location/view/location_screen.dart` | getLocation()メソッド |

**主要処理フロー**:
- **259-298行目**: getLocation()
  - **260-263行目**: placemarkFromCoordinates()で逆ジオコーディング
  - **265-296行目**: Placemarkの各フィールドをaddress文字列とaddressMapに設定
  - street, thoroughfare, subLocality, locality, administrativeArea, postalCode, country, isoCountryCodeを順に処理

#### Step 5: 場所検索機能を理解する

PlaceSearch画面とGoogle Places API連携を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | place_search.dart | `lib/screens/location/view/place_search.dart` | テキスト入力と検索結果表示 |
| 5-2 | location_bloc.dart | `lib/screens/location/bloc/location_bloc.dart` | SearchPlaceEvent処理 |
| 5-3 | location_repo.dart | `lib/screens/location/bloc/location_repo.dart` | Google Places API呼び出し |

**主要処理フロー**:
- **78-83行目（place_search）**: onChanged()でSearchPlaceEvent発行
- **23-34行目（bloc）**: SearchPlaceEvent処理、repository.getPlace()呼び出し
- **20-34行目（repo）**: Google Places API呼び出し（GooglePlaceApiClient使用）
- **130-145行目（place_search）**: 検索結果タップでLatLng返却

#### Step 6: 呼び出し元との連携を理解する

住所追加・編集画面からの呼び出しと結果受け取りを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | add_edit_address_screen.dart | `lib/screens/add_edit_address/view/add_edit_address_screen.dart` | LocationScreen呼び出しと結果処理 |

**主要処理フロー**:
- **127-150行目**: LocationScreen呼び出しとthen()での結果処理
  - **132行目**: Navigator.pushでLocationScreen表示
  - **133-149行目**: 返却されたMapから各フィールドを取得してコントローラーに設定

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

```
AddNewAddress（住所追加・編集画面）
    │
    └─ Navigator.push(LocationScreen)
           │
           ├─ initState()
           │      └─ getCurrentLocation()
           │             ├─ locationFromAddress()（ジオコーディング）
           │             └─ currentLocation.getLocation()（GPS）
           │
           ├─ _buildUI()
           │      │
           │      ├─ GoogleMap
           │      │      ├─ onCameraMove → position更新
           │      │      └─ onCameraIdle → getLocation()
           │      │                             └─ placemarkFromCoordinates()
           │      │
           │      ├─ 検索バー → Navigator.push(PlaceSearch)
           │      │                    │
           │      │                    └─ LocationScreenBloc
           │      │                           └─ SearchPlaceEvent
           │      │                                  └─ LocationRepositoryImp.getPlace()
           │      │                                         └─ GooglePlaceApiClient
           │      │
           │      └─ 現在地ボタン → getCurrentLocation()
           │
           └─ 住所エリアタップ → Navigator.pop(addressMap)
                                       │
                                       ▼
                              AddNewAddress.then()
                                  └─ 各コントローラーに値設定
```

### データフロー図

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

addressパラメータ ─────▶ locationFromAddress() ─────▶ LatLng（緯度経度）
                               │
                               ▼
デバイスGPS ───────────▶ currentLocation.getLocation() ─▶ LatLng
                               │
                               ▼
                          GoogleMap表示
                               │
カメラ移動 ────────────▶ onCameraMove ───────────────▶ position更新
                               │
カメラ停止 ────────────▶ onCameraIdle
                               │
                               ▼
                          placemarkFromCoordinates()
                               │
座標 ─────────────────────────▶│───────────────────▶ Placemark
                               │
                               ▼
                          getLocation()
                               │
                               ▼
                          addressMap生成
                               │
住所エリアタップ ──────▶ Navigator.pop(addressMap) ──▶ 呼び出し元画面

検索テキスト ─────────▶ SearchPlaceEvent
                               │
                               ▼
                          LocationRepositoryImp.getPlace()
                               │
                               ▼
                          Google Places API
                               │
                               ▼
                          GooglePlaceModel
                               │
結果タップ ───────────▶ Navigator.pop(LatLng)
                               │
                               ▼
                          placeSearch() ───────────▶ カメラ移動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| location_screen.dart | `lib/screens/location/view/location_screen.dart` | ソース | 地図表示・位置選択メイン画面 |
| place_search.dart | `lib/screens/location/view/place_search.dart` | ソース | 場所検索画面 |
| location_bloc.dart | `lib/screens/location/bloc/location_bloc.dart` | ソース | 位置情報BLoC |
| location_repo.dart | `lib/screens/location/bloc/location_repo.dart` | ソース | Places APIリポジトリ |
| location_state.dart | `lib/screens/location/bloc/location_state.dart` | ソース | 状態定義 |
| location_event.dart | `lib/screens/location/bloc/location_event.dart` | ソース | イベント定義 |
| index.dart | `lib/screens/location/utils/index.dart` | ソース | エクスポート定義 |
| add_edit_address_screen.dart | `lib/screens/add_edit_address/view/add_edit_address_screen.dart` | ソース | 呼び出し元（住所追加・編集画面） |
