# 機能設計書 66-地域国設定

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける地域と国の紐付け設定機能の設計を記述する。地域に含まれる国の追加・削除を管理する。

### 本機能の処理概要

**業務上の目的・背景**：地域（リージョン）に対してどの国を含めるかを設定することで、その国の顧客に対して地域固有の通貨、税制、配送オプションを適用できる。地域国設定機能は、地域作成時および更新時に国コードリストを指定することで、国と地域の紐付けを管理する。これにより、柔軟な地域構成が可能となり、ビジネス要件の変化に対応できる。

**機能の利用シーン**：
- 地域作成時に含める国を指定
- 既存地域に新たな国を追加
- 地域から特定の国を除外
- 地域間で国を移動（一方から除外、他方に追加）

**主要な処理内容**：
1. 国コードリストの正規化（小文字変換）
2. 国コードの重複チェック
3. 国コードの存在確認（region_countryテーブル）
4. 他地域への紐付き状態チェック
5. 国のregion_id更新による紐付け設定

**関連システム・外部連携**：
- 地域CRUD機能との連携（地域作成・更新時に実行）

**権限による制御**：地域国設定は地域CRUDの一部として実行されるため、地域の作成・更新権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 114 | リージョン作成画面 | 主画面 | リージョンに含める国の設定 |
| 115 | リージョン詳細画面 | 補助機能 | 含まれる国の表示 |
| 117 | 国追加画面 | 主画面 | リージョンに国を追加 |

## 機能種別

データ関連付け処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| countries | string[] | No | 国コード（ISO 3166-1 alpha-2）リスト | 有効な国コード、小文字に正規化、重複なし |

### 入力データソース

- 地域作成・更新APIのcountriesパラメータ

## 出力仕様

### 出力データ

地域国設定単体での出力はなく、地域CRUDの出力に含まれる。

| 項目名 | 型 | 説明 |
|--------|-----|------|
| countries | RegionCountryDTO[] | 地域に含まれる国のリスト |

#### RegionCountryDTO

| 項目名 | 型 | 説明 |
|--------|-----|------|
| iso_2 | string | ISO 3166-1 alpha-2国コード |
| iso_3 | string | ISO 3166-1 alpha-3国コード |
| num_code | string | ISO 3166-1数字コード |
| name | string | 国名 |
| display_name | string | 表示用国名 |
| region_id | string | null | 紐付き地域ID |

### 出力先

- 地域レスポンスのcountriesフィールド

## 処理フロー

### 処理シーケンス

```
1. 入力正規化
   └─ 国コードを小文字に変換

2. 重複チェック
   ├─ 入力リスト内での重複検出
   └─ 重複ありの場合エラー

3. 国存在確認
   ├─ region_countryテーブルで検索
   └─ 存在しない国コードありの場合エラー

4. 他地域紐付きチェック
   ├─ region_idがnullでない国の検出
   └─ 紐付きありの場合エラー

5. 地域紐付け更新
   └─ countryService_.updateでregion_idを設定

6. 地域更新時の追加処理
   ├─ 既存紐付きの解除（region_id = null）
   └─ 新規紐付けの設定
```

### フローチャート

```mermaid
flowchart TD
    A[countries配列受信] --> B[小文字正規化]
    B --> C{重複あり?}
    C -->|Yes| D[INVALID_DATAエラー]
    C -->|No| E[region_countryテーブル検索]
    E --> F{全て存在?}
    F -->|No| G[INVALID_DATAエラー：存在しない国]
    F -->|Yes| H{他地域に紐付き?}
    H -->|Yes| I[INVALID_DATAエラー：紐付き済み]
    H -->|No| J[region_id更新]
    J --> K[紐付け完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-66-01 | 国コード正規化 | 国コードは小文字に正規化 | 紐付け処理前 |
| BR-66-02 | 重複禁止 | 同一リクエスト内で同じ国コードは指定不可 | 紐付け処理前 |
| BR-66-03 | 国存在必須 | 指定された国コードはregion_countryテーブルに存在すること | 紐付け処理前 |
| BR-66-04 | 単一地域所属 | 国は1つの地域にのみ所属可能 | 紐付け処理前 |
| BR-66-05 | 更新時クリーンスレート | 地域更新時の国設定は、既存紐付けをクリアしてから新規設定 | 地域更新時 |

### 計算ロジック

**重複検出**:
```typescript
const uniqueCountries = Array.from(new Set(countries))
if (uniqueCountries.length !== countries.length) {
  const duplicates = getDuplicates(countries)
  throw new MedusaError(...)
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 国存在確認 | region_country | SELECT | iso_2で検索 |
| 紐付き確認 | region_country | SELECT | region_idがnullでない国を検索 |
| 紐付け設定 | region_country | UPDATE | region_idを地域IDに設定 |
| 紐付け解除 | region_country | UPDATE | region_idをnullに設定 |

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

#### region_country

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | iso_2, region_id | WHERE iso_2 IN (国コードリスト) | 存在確認・紐付き確認 |
| UPDATE | region_id | 地域ID | WHERE iso_2 IN (国コードリスト) |
| UPDATE | region_id | null | WHERE region_id = 対象地域ID |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| INVALID_DATA | MedusaError | 同一リクエスト内で国コード重複 | 400レスポンス、エラーメッセージに重複国コード表示 |
| INVALID_DATA | MedusaError | 存在しない国コード指定 | 400レスポンス、エラーメッセージに不明国コード表示 |
| INVALID_DATA | MedusaError | 他地域に紐付き済みの国指定 | 400レスポンス、エラーメッセージに紐付き済み国コード表示 |

### リトライ仕様

紐付け処理自体にリトライは不要。上位の地域CRUD操作でトランザクション管理。

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

- 地域CRUDのトランザクション内で実行
- @InjectTransactionManagerデコレータにより制御
- 紐付け解除と設定は同一トランザクション内

## パフォーマンス要件

- iso_2カラムは主キーのため高速検索
- (region_id, iso_2)の複合ユニークインデックスあり

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

- 入力値の正規化（小文字変換）によるインジェクション防止
- 存在チェックによる不正データ排除

## 備考

- 国データ（region_countryテーブル）はシード処理で事前投入
- 新しい国の追加は別途マイグレーションが必要

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | country.ts | `packages/modules/region/src/models/country.ts` | Countryモデルの構造、regionとのリレーション |

**読解のコツ**: iso_2が主キー。region_idはnullable（地域に紐付いていない場合はnull）。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | region-module.ts | `packages/modules/region/src/services/region-module.ts` | validateCountries関数、国紐付け処理 |

**主要処理フロー**:
1. **306-315行目**: normalizeInput - 国コードの小文字化
2. **325-377行目**: validateCountries - 国バリデーション全体
3. **333-342行目**: 重複チェック（getDuplicates使用）
4. **344-361行目**: 国存在チェック
5. **364-375行目**: 他地域紐付きチェック
6. **122-130行目**: 国紐付け更新（countryService_.update）
7. **276-300行目**: 更新時の既存紐付け解除と新規設定

#### Step 3: 正規化関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | region-module.ts | `packages/modules/region/src/services/region-module.ts` | normalizeInput static関数 |

**主要処理フロー**:
- **306-315行目**: currency_code小文字化、name trim、countries小文字化

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

```
regionService.createRegions / updateRegions
    │
    ├─ normalizeInput (static)
    │      └─ countries.map(c => c.toLowerCase())
    │
    ├─ validateCountries
    │      │
    │      ├─ getDuplicates (重複チェック)
    │      │
    │      ├─ countryService_.list
    │      │      └─ SELECT iso_2, region_id WHERE iso_2 IN (...)
    │      │
    │      └─ region_idチェック
    │
    └─ countryService_.update
           └─ UPDATE region_country SET region_id = ? WHERE iso_2 IN (...)
```

### データフロー図

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

countries[] ─────────▶ normalizeInput ──────────▶ 小文字化された国コード配列
                            │
                            ▼
                     validateCountries
                            │
                   ┌────────┴────────┬──────────────┐
                   ▼                 ▼              ▼
              重複チェック      存在チェック    紐付きチェック
                   │                 │              │
                   ▼                 ▼              ▼
              OK / Error        OK / Error      OK / Error
                   │                 │              │
                   └────────┬────────┴──────────────┘
                            │
                            ▼
                     countryService_.update
                            │
                            ▼
                     region_countryテーブル更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| country.ts | `packages/modules/region/src/models/country.ts` | ソース | Countryモデル定義 |
| region-module.ts | `packages/modules/region/src/services/region-module.ts` | ソース | validateCountries、normalizeInput実装 |
| region.ts | `packages/modules/region/src/models/region.ts` | ソース | Regionモデル（countriesリレーション） |
