# 機能設計書 20-デフォルト住所設定

## 概要

本ドキュメントは、Shopwareストアフロントにおける「デフォルト住所設定」機能の設計内容を記載する。顧客が登録済みの住所をデフォルトの請求先または配送先として設定する機能であり、注文時に自動選択される住所を変更する。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトでは、注文時に請求先・配送先住所を選択する必要があるが、よく使う住所をデフォルトとして設定しておくことで、注文プロセスを簡略化できる。本機能は、顧客が任意の登録済み住所をデフォルトの請求先または配送先として設定できるようにする。

**機能の利用シーン**：
- 引っ越し後に新しい住所をデフォルトに設定したい場合
- 普段使いの住所を変更したい場合
- 請求先と配送先を別々に設定したい場合

**主要な処理内容**：
1. ログイン認証の確認
2. 住所所有権の確認
3. 住所タイプ（billing/shipping）の判定
4. デフォルト住所IDの更新
5. イベントの発火
6. 成功・エラーメッセージの表示とリダイレクト

**関連システム・外部連携**：Store API（AbstractSwitchDefaultAddressRoute）およびAccountServiceを経由してデータを更新。

**権限による制御**：ログイン必須（`LOGIN_REQUIRED`属性）。ゲストユーザーも一部許可（チェックアウト時の住所切替）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | 住所帳ページ | 主画面 | デフォルト住所の設定操作 |
| 10 | 注文確認ページ | 参照画面 | チェックアウト時の住所選択 |

## 機能種別

CRUD操作（Update）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | string | Yes | 住所タイプ（billing/shipping） | "billing"または"shipping" |
| addressId | string | Yes | 設定する住所ID | 有効なUUID、顧客所有確認 |
| context | SalesChannelContext | Yes | 販売チャネルコンテキスト | ログイン顧客情報を含む |
| customer | CustomerEntity | Yes | ログイン中の顧客エンティティ | セッションから自動取得 |

### 入力データソース

- URLパラメータ（type, addressId）
- セッション情報（ログイン顧客情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| flashMessage | string | 成功/エラーメッセージ |
| NoContentResponse | Response | 設定成功時のレスポンス（Store API） |

### 出力先

- データベース（customer テーブルのdefault_billing_address_id/default_shipping_address_id更新）
- セッション（フラッシュメッセージ）
- 画面リダイレクト（frontend.account.address.page）

## 処理フロー

### 処理シーケンス

```
1. ルーティング処理
   └─ /account/address/default-{type}/{addressId} パスへのPOSTリクエストを受信

2. コントローラー処理 (AddressController::switchDefaultAddress)
   ├─ addressIdの有効性確認（UUID形式）
   ├─ typeに応じてAccountServiceを呼び出し
   │    ├─ type = shipping → setDefaultShippingAddress
   │    └─ type = billing → setDefaultBillingAddress
   └─ 成功/エラーメッセージの設定

3. AccountService処理
   └─ SwitchDefaultAddressRouteを呼び出し

4. デフォルト住所切替ルート処理 (SwitchDefaultAddressRoute::swap)
   ├─ 住所所有権の検証（validateAddress）
   ├─ typeに応じたイベントの発火
   │    ├─ type = billing → CustomerSetDefaultBillingAddressEvent
   │    └─ type = shipping → CustomerSetDefaultShippingAddressEvent
   └─ customerリポジトリの更新

5. レスポンス生成
   └─ 住所一覧ページへリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[POST /account/address/default-{type}/{addressId}] --> B{ログイン済み?}
    B -->|No| C[ログイン画面へリダイレクト]
    B -->|Yes| D{addressId有効なUUID?}
    D -->|No| E[UuidException発生]
    D -->|Yes| F{type判定}
    F -->|shipping| G[AccountService::setDefaultShippingAddress]
    F -->|billing| H[AccountService::setDefaultBillingAddress]
    F -->|その他| I[addressDefaultNotChangedメッセージ]
    G --> J[SwitchDefaultAddressRoute::swap]
    H --> J
    J --> K[validateAddress - 所有権確認]
    K --> L{所有権OK?}
    L -->|No| M[AddressNotFoundException]
    M --> N[addressDefaultNotChangedメッセージ]
    L -->|Yes| O{type判定}
    O -->|billing| P[CustomerSetDefaultBillingAddressEvent発火]
    O -->|shipping| Q[CustomerSetDefaultShippingAddressEvent発火]
    P --> R[customerRepository.update]
    Q --> R
    R --> S[NoContentResponse返却]
    S --> T[addressDefaultChangedメッセージ]
    T --> U[住所一覧へリダイレクト]
    I --> U
    N --> U
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-20-01 | ログイン必須 | 未ログインユーザーはアクセス不可 | 全リクエスト |
| BR-20-02 | 所有権確認 | 設定対象の住所が自分のものであることを確認 | 全リクエスト |
| BR-20-03 | 住所タイプ | billing（請求先）またはshipping（配送先）のみ有効 | 全リクエスト |
| BR-20-04 | イベント発火 | タイプに応じたイベントを発火（プラグイン拡張ポイント） | 設定成功時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| デフォルト住所更新 | customer | UPDATE | default_billing_address_idまたはdefault_shipping_address_idの更新 |

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

#### customer

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | id | ログイン顧客のID | WHERE条件 |
| UPDATE | default_billing_address_id | 設定するaddressId | type=billingの場合 |
| UPDATE | default_shipping_address_id | 設定するaddressId | type=shippingの場合 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | UuidException::invalidUuid | 無効なUUID形式 | エラーメッセージ表示 |
| - | AddressNotFoundException | 住所が存在しないまたは所有権なし | エラーメッセージ表示 |
| - | - | 無効なtype値 | エラーメッセージ表示（変更されなかった） |

### リトライ仕様

特になし

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

DAL（Data Abstraction Layer）のupdateメソッドにより、1件のUPDATEがトランザクション内で実行される。

## パフォーマンス要件

- 単一レコードの更新のため、特別なパフォーマンス要件なし

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

- LOGIN_REQUIRED属性によりログイン必須を強制
- CustomerAddressValidationTraitにより住所所有権を検証
- 他の顧客の住所はデフォルトに設定不可

## 備考

- デフォルト住所を変更しても、現在のカートのアクティブ住所は自動的には変更されない
- チェックアウト時の住所切替（checkoutSwitchDefaultAddress）は別のルートで処理される
- CustomerSetDefaultBillingAddressEvent/CustomerSetDefaultShippingAddressEventにより、プラグインがデフォルト住所変更を検知・処理可能

---

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

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

### 推奨読解順序

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

顧客エンティティとデフォルト住所の関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CustomerEntity.php | `src/Core/Checkout/Customer/CustomerEntity.php` | defaultBillingAddressId, defaultShippingAddressIdフィールドを確認 |
| 1-2 | CustomerAddressEntity.php | `src/Core/Checkout/Customer/Aggregate/CustomerAddress/CustomerAddressEntity.php` | 住所エンティティの構造を確認 |

**読解のコツ**: CustomerEntityにはdefault_*_address_idと、それに対応するdefaultBillingAddress/defaultShippingAddressのエンティティ両方がある。

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

コントローラーでのリクエスト処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AddressController.php | `src/Storefront/Controller/AddressController.php` | switchDefaultAddressメソッド（138-169行目）がエントリーポイント |

**主要処理フロー**:
1. **150-152行目**: addressIdのUUID形式検証
2. **155-157行目**: type=shippingの場合、setDefaultShippingAddress呼び出し
3. **158-160行目**: type=billingの場合、setDefaultBillingAddress呼び出し
4. **161-162行目**: その他のtypeの場合、エラーメッセージ
5. **164-165行目**: AddressNotFoundException時、エラーメッセージ
6. **168行目**: 住所一覧ページへリダイレクト

#### Step 3: AccountServiceを理解する

デフォルト住所設定のサービス層を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AccountService.php | `src/Core/Checkout/Customer/SalesChannel/AccountService.php` | setDefaultBillingAddress/setDefaultShippingAddressメソッド（56-69行目） |

**主要処理フロー**:
- **58行目**: setDefaultBillingAddressはSwitchDefaultAddressRoute::swap(TYPE_BILLING)を呼び出し
- **67行目**: setDefaultShippingAddressはSwitchDefaultAddressRoute::swap(TYPE_SHIPPING)を呼び出し

#### Step 4: Store APIルートを理解する

実際のデフォルト住所設定ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SwitchDefaultAddressRoute.php | `src/Core/Checkout/Customer/SalesChannel/SwitchDefaultAddressRoute.php` | swapメソッド（65-95行目）の処理フローを確認 |

**主要処理フロー**:
- **67行目**: validateAddressで所有権確認
- **69-78行目**: type=billingの場合、defaultBillingAddressIdを更新、CustomerSetDefaultBillingAddressEvent発火
- **79-88行目**: type=shipping（default）の場合、defaultShippingAddressIdを更新、CustomerSetDefaultShippingAddressEvent発火
- **92行目**: customerリポジトリの更新
- **94行目**: NoContentResponse返却

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

```
AddressController::switchDefaultAddress
    │
    ├─ Uuid::isValid (UUID検証)
    │
    ├─ AccountService::setDefaultShippingAddress (type=shipping)
    │      │
    │      └─ SwitchDefaultAddressRoute::swap(TYPE_SHIPPING)
    │
    └─ AccountService::setDefaultBillingAddress (type=billing)
           │
           └─ SwitchDefaultAddressRoute::swap(TYPE_BILLING)
                  │
                  ├─ validateAddress (所有権確認)
                  │      └─ CustomerAddressValidationTrait
                  │
                  ├─ CustomerSetDefault*AddressEvent発火
                  │
                  └─ customerRepository.update
```

### データフロー図

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

POST /account/address/default-{type}/{addressId}
        │
        ▼
SalesChannelContext ───▶ AddressController::switchDefaultAddress
        │                         │
        ▼                         ▼
CustomerEntity ─────────▶ UUID検証
                                  │
                                  ▼
                          type判定
                                  │
                          ┌───────┴───────┐
                          ▼               ▼
                    type=billing    type=shipping
                          │               │
                          ▼               ▼
               setDefaultBillingAddress setDefaultShippingAddress
                          │               │
                          └───────┬───────┘
                                  │
                                  ▼
                    SwitchDefaultAddressRoute::swap
                                  │
                          ┌───────┴───────┐
                          ▼               ▼
                    所有権確認      イベント発火
                          │               │
                          └───────┬───────┘
                                  │
                                  ▼
                    customerRepository.update
                                  │
                                  ▼
                    フラッシュメッセージ設定
                                  │
                                  ▼
                    住所一覧へリダイレクト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AddressController.php | `src/Storefront/Controller/AddressController.php` | コントローラー | HTTPリクエスト処理のエントリーポイント |
| AccountService.php | `src/Core/Checkout/Customer/SalesChannel/AccountService.php` | サービス | デフォルト住所設定のファサード |
| SwitchDefaultAddressRoute.php | `src/Core/Checkout/Customer/SalesChannel/SwitchDefaultAddressRoute.php` | Store API | デフォルト住所設定ビジネスロジック |
| AbstractSwitchDefaultAddressRoute.php | `src/Core/Checkout/Customer/SalesChannel/AbstractSwitchDefaultAddressRoute.php` | 抽象クラス | Store APIの抽象定義 |
| CustomerAddressValidationTrait.php | `src/Core/Checkout/Customer/SalesChannel/CustomerAddressValidationTrait.php` | トレイト | 住所所有権検証 |
| CustomerSetDefaultBillingAddressEvent.php | `src/Core/Checkout/Customer/Event/CustomerSetDefaultBillingAddressEvent.php` | イベント | 請求先住所設定イベント |
| CustomerSetDefaultShippingAddressEvent.php | `src/Core/Checkout/Customer/Event/CustomerSetDefaultShippingAddressEvent.php` | イベント | 配送先住所設定イベント |
| CustomerEntity.php | `src/Core/Checkout/Customer/CustomerEntity.php` | エンティティ | 顧客データモデル |
| NoContentResponse.php | `src/Core/System/SalesChannel/NoContentResponse.php` | レスポンス | 204 No Contentレスポンス |
