# 機能設計書 22-カート住所管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおけるカートに紐づく配送先・請求先住所の管理機能について記載する。

### 本機能の処理概要

本機能は、ECサイトの購入フローにおいて、カートに配送先住所および請求先住所を設定・更新する機能である。顧客がチェックアウトプロセスで商品の配送先を指定し、請求先住所を設定するために使用される。住所情報はカートに直接紐付けられ、注文確定時に注文データに引き継がれる。

**業務上の目的・背景**：ECサイトにおいて、商品を顧客に届けるためには配送先住所が必須である。また、請求書の送付先や決済関連の住所確認のために請求先住所も必要となる。カート段階で住所を管理することで、チェックアウトプロセスの途中離脱時にも情報が保持され、顧客の利便性が向上する。さらに、配送先住所に基づいて利用可能な配送オプションや税率が決定されるため、正確な住所設定が重要となる。

**機能の利用シーン**：顧客がカートからチェックアウトに進む際に配送先住所を入力するフェーズで使用される。また、ログイン済み顧客の場合は登録済み住所から選択することも可能。住所変更時には配送オプションや税金の再計算がトリガーされる。

**主要な処理内容**：
1. 配送先住所（shipping_address）の作成・更新
2. 請求先住所（billing_address）の作成・更新
3. カートへの住所の関連付け
4. 住所変更に伴う配送オプション・税金の再計算トリガー
5. 住所の取得・参照

**関連システム・外部連携**：住所に基づいて税計算モジュール（Tax Module）との連携が行われ、配送先住所の国・地域に応じた税率が適用される。また、配送モジュール（Fulfillment Module）との連携により、配送先住所に対して利用可能な配送オプションがフィルタリングされる。

**権限による制御**：Store API経由では顧客が自身のカートに対してのみ住所を設定可能。Admin APIでは管理者が任意のカートの住所を管理可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | チェックアウト画面（住所入力） | 主画面 | 配送先・請求先住所の入力・設定 |

## 機能種別

CRUD操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | Yes | カートID | カートが存在すること |
| shipping_address | AddressDTO | No | 配送先住所 | - |
| shipping_address.first_name | string | No | 名 | - |
| shipping_address.last_name | string | No | 姓 | - |
| shipping_address.company | string | No | 会社名 | - |
| shipping_address.address_1 | string | No | 住所1 | - |
| shipping_address.address_2 | string | No | 住所2 | - |
| shipping_address.city | string | No | 市区町村 | - |
| shipping_address.province | string | No | 都道府県 | - |
| shipping_address.postal_code | string | No | 郵便番号 | - |
| shipping_address.country_code | string | No | 国コード | ISO 3166-1 alpha-2 |
| shipping_address.phone | string | No | 電話番号 | - |
| billing_address | AddressDTO | No | 請求先住所 | shipping_addressと同様の構造 |

### 入力データソース

- Store API: POST /store/carts/{id}（カート更新時に住所を含める）
- Admin API: POST /admin/carts/{id}

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| cart | CartDTO | 更新後のカート情報 |
| cart.shipping_address | AddressDTO | 配送先住所 |
| cart.billing_address | AddressDTO | 請求先住所 |
| cart.shipping_address.id | string | 配送先住所ID（caaddrプレフィックス） |
| cart.shipping_address.first_name | string | 名 |
| cart.shipping_address.last_name | string | 姓 |
| cart.shipping_address.country_code | string | 国コード |

### 出力先

- APIレスポンス（JSON形式）
- データベース（cart_addressテーブル）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ カートIDと住所情報を取得

2. カートの取得
   └─ カートの存在確認

3. 分散ロックの取得
   └─ カートIDをキーとしてロック取得

4. 住所データの処理
   ├─ 新規住所の場合: 住所レコード作成
   └─ 既存住所の更新の場合: 住所レコード更新

5. カートへの関連付け
   └─ shipping_address_id / billing_address_id を更新

6. 配送方法・税金の再計算（住所変更時）
   └─ 住所変更により利用可能な配送オプションや税率が変わる可能性

7. イベント発行
   └─ cart.updatedイベント発行

8. ロック解放とレスポンス返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[カート取得]
    B --> C{カート存在?}
    C -->|No| D[エラー返却]
    C -->|Yes| E[ロック取得]
    E --> F{住所データあり?}
    F -->|No| G[他の更新処理]
    F -->|Yes| H{新規 or 更新?}
    H -->|新規| I[住所レコード作成]
    H -->|更新| J[住所レコード更新]
    I --> K[カートに関連付け]
    J --> K
    K --> L{country_code変更?}
    L -->|Yes| M[配送・税金再計算]
    L -->|No| N[イベント発行]
    M --> N
    G --> N
    N --> O[ロック解放]
    O --> P[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-22-01 | 住所分離 | 配送先住所と請求先住所は別々に管理される | 常時 |
| BR-22-02 | 住所任意 | 住所の各フィールドは基本的に任意入力 | 常時 |
| BR-22-03 | 国コード影響 | country_codeの変更は税率・配送オプションに影響する | 住所更新時 |
| BR-22-04 | 住所継承 | 注文確定時にカートの住所は注文にコピーされる | 注文作成時 |

### 計算ロジック

住所自体に計算ロジックはないが、住所の変更は以下の再計算をトリガーする：
- 税金計算: 配送先住所のcountry_code/provinceに基づく税率適用
- 配送料金: 配送先住所に対応する配送オプションの価格

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 住所作成 | cart_address | INSERT | 新規住所レコード作成 |
| 住所更新 | cart_address | UPDATE | 既存住所レコード更新 |
| カート更新 | cart | UPDATE | shipping_address_id/billing_address_id更新 |

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

#### cart_address

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | id | 自動生成（caaddrプレフィックス） | 主キー |
| INSERT/UPDATE | customer_id | 顧客ID（任意） | 顧客との関連 |
| INSERT/UPDATE | company | 会社名 | NULL許可 |
| INSERT/UPDATE | first_name | 名 | NULL許可 |
| INSERT/UPDATE | last_name | 姓 | NULL許可 |
| INSERT/UPDATE | address_1 | 住所1 | NULL許可 |
| INSERT/UPDATE | address_2 | 住所2 | NULL許可 |
| INSERT/UPDATE | city | 市区町村 | NULL許可 |
| INSERT/UPDATE | country_code | 国コード | NULL許可 |
| INSERT/UPDATE | province | 都道府県 | NULL許可 |
| INSERT/UPDATE | postal_code | 郵便番号 | NULL許可 |
| INSERT/UPDATE | phone | 電話番号 | NULL許可 |
| INSERT/UPDATE | metadata | メタデータ | JSON形式 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | MedusaError | カートが存在しない | 有効なカートIDを指定 |
| INVALID_DATA | MedusaError | country_codeが無効な形式 | 有効なISO国コードを指定 |

### リトライ仕様

分散ロック取得時にタイムアウトが発生した場合、再試行可能。

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

- カート更新ワークフロー内でトランザクション管理
- 住所の作成/更新とカートへの関連付けは同一トランザクション内で実行
- エラー発生時はロールバック

## パフォーマンス要件

- レスポンス時間: 1秒以内（住所更新のみの場合）
- 住所変更により税金・配送オプションの再計算が発生する場合は追加時間がかかる

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

- 住所情報は個人情報として適切に保護
- カートの所有者のみが住所を設定可能
- APIレベルでの認証・認可

## 備考

- 住所の各フィールドは基本的にすべてNULL許可となっており、段階的な入力が可能
- 顧客IDを住所に関連付けることで、登録済み住所との紐付けが可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | address.ts | `packages/modules/cart/src/models/address.ts` | カート住所のモデル定義 |
| 1-2 | cart.ts | `packages/modules/cart/src/models/cart.ts` | カートモデルと住所との関連 |

**読解のコツ**: Addressモデルはカート専用の住所テーブル（cart_address）を使用。顧客の住所テーブル（customer_address）とは別管理。

**主要処理フロー（address.ts）**:
- **3-20行目**: Addressモデル定義
- **6行目**: IDプレフィックスはcaaddr
- **7-18行目**: 各住所フィールド（すべてNULL許可）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | route.ts | `packages/medusa/src/api/store/carts/[id]/route.ts` | Store APIでのカート更新（住所含む） |

**主要処理フロー**:
- **21-47行目**: POST メソッド - カート更新のエントリーポイント
- **30-38行目**: updateCartWorkflowIdを使用してカート更新

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cart-module.ts | `packages/modules/cart/src/services/cart-module.ts` | 住所作成・更新メソッド |

**主要処理フロー**:
- **617-656行目**: createAddresses - 住所作成
- **649-655行目**: createAddresses_ - addressService_.createを呼び出し
- **657-695行目**: updateAddresses - 住所更新
- **689-694行目**: updateAddresses_ - addressService_.updateを呼び出し

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

```
POST /store/carts/{id}
    │
    ├─ updateCartWorkflow
    │      │
    │      ├─ acquireLockStep
    │      │
    │      ├─ useRemoteQueryStep (カート取得)
    │      │
    │      ├─ 住所処理（入力に含まれる場合）
    │      │      ├─ CartModuleService.createAddresses
    │      │      │      └─ addressService_.create
    │      │      └─ CartModuleService.updateAddresses
    │      │             └─ addressService_.update
    │      │
    │      ├─ updateCartsStep (カートに住所ID関連付け)
    │      │
    │      ├─ 配送・税金再計算（住所変更の場合）
    │      │
    │      └─ emitEventStep / releaseLockStep
    │
    └─ refetchCart
```

### データフロー図

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

cart_id          ───┐
shipping_address ───┼──▶ updateCartWorkflow ───▶ 更新後カート
billing_address  ───┘         │
                              ├─▶ 住所レコード作成/更新 ───▶ cart_address
                              │
                              ├─▶ カートに住所ID関連付け ───▶ cart
                              │
                              └─▶ 税・配送オプション再計算
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| address.ts | `packages/modules/cart/src/models/address.ts` | ソース | 住所モデル定義 |
| cart.ts | `packages/modules/cart/src/models/cart.ts` | ソース | カートモデル（住所との関連含む） |
| route.ts | `packages/medusa/src/api/store/carts/[id]/route.ts` | ソース | Store APIルート |
| cart-module.ts | `packages/modules/cart/src/services/cart-module.ts` | ソース | カートモジュールサービス |
