# 機能設計書 65-地域CRUD

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける販売地域（リージョン）のCRUD機能の設計を記述する。地域の作成、取得、更新、削除、および地域と国の紐付け管理を提供する。

### 本機能の処理概要

**業務上の目的・背景**：グローバルなECサイト運営では、地域ごとに異なる通貨、税制、配送オプションを適用する必要がある。地域CRUD機能は、販売対象となる地域を定義し、各地域に適切な通貨コードと含まれる国を設定することで、地域特有のビジネスルールを適用可能にする。これにより、多国籍展開時の運用効率が向上する。

**機能の利用シーン**：
- 新規販売地域の追加（例：ヨーロッパ地域をEUR通貨で設定）
- 地域一覧画面での地域情報確認
- 地域に含まれる国の追加・削除
- 地域の通貨変更
- 不要になった地域の削除
- 自動税金計算の有効化・無効化設定

**主要な処理内容**：
1. 地域一覧取得（フィルタ・ページネーション対応）
2. 特定地域の詳細情報取得（国一覧含む）
3. 地域作成（通貨コード、国コードリスト設定）
4. 地域更新（名前、通貨、国の変更）
5. 地域削除（ソフトデリート、国の紐付け解除）

**関連システム・外部連携**：
- 価格設定モジュールとの連携（地域別税込価格設定）
- 支払いプロバイダーとの連携（地域別決済設定）
- フルフィルメントモジュールとの連携（地域別配送設定）

**権限による制御**：地域の作成・更新・削除は認証済み管理者のみ可能。一覧・詳細取得は認証済みユーザーがアクセス可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 113 | リージョン一覧画面 | 主画面 | リージョン一覧の取得・表示 |
| 114 | リージョン作成画面 | 主画面 | 新規リージョンの作成 |
| 115 | リージョン詳細画面 | 主画面 | リージョン詳細の表示 |
| 116 | リージョン編集画面 | 主画面 | リージョン情報の編集 |
| 118 | リージョンメタデータ編集画面 | 主画面 | リージョンメタデータの編集 |

## 機能種別

CRUD操作

## 入力仕様

### 入力パラメータ

#### 地域作成

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | 地域名 | トリミング処理適用 |
| currency_code | string | Yes | 通貨コード | 小文字に正規化 |
| countries | string[] | No | 国コード（ISO 3166-1 alpha-2）リスト | 有効な国コード、重複なし |
| automatic_taxes | boolean | No | 自動税計算有効化 | デフォルトtrue |
| payment_providers | string[] | No | 支払いプロバイダーID | - |
| is_tax_inclusive | boolean | No | 税込価格フラグ | - |
| metadata | object | No | メタデータ | - |

#### 地域更新

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | Yes | 地域ID | 存在する地域 |
| name | string | No | 地域名 | - |
| currency_code | string | No | 通貨コード | 小文字に正規化 |
| countries | string[] | No | 国コードリスト | 有効な国コード |
| automatic_taxes | boolean | No | 自動税計算 | - |
| metadata | object | No | メタデータ | - |

### 入力データソース

- Admin API HTTPリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | 地域ID（reg_プレフィックス） |
| name | string | 地域名 |
| currency_code | string | 通貨コード |
| automatic_taxes | boolean | 自動税計算フラグ |
| countries | RegionCountryDTO[] | 含まれる国のリスト |
| metadata | object | null | メタデータ |
| created_at | Date | 作成日時 |
| updated_at | Date | 更新日時 |
| deleted_at | Date | null | 削除日時 |

### 出力先

- Admin API HTTPレスポンス
- イベント発行（region.created, region.updated, region.deleted）

## 処理フロー

### 処理シーケンス

```
1. 地域作成
   ├─ 入力正規化（currency_code小文字化、name trim、countries小文字化）
   ├─ 地域レコード作成
   ├─ 国バリデーション（validateCountries）
   │   ├─ 重複チェック
   │   ├─ 国コード存在チェック
   │   └─ 他地域への紐付けチェック
   ├─ 国の地域紐付け更新
   ├─ 支払いプロバイダー設定
   ├─ 価格優先設定作成
   └─ イベント発行（CREATED）

2. 地域更新
   ├─ 入力正規化
   ├─ 既存国紐付け解除（countries更新の場合）
   ├─ 国バリデーション
   ├─ 新規国紐付け設定
   └─ 地域レコード更新

3. 地域削除
   ├─ 地域ソフトデリート
   └─ 紐付き国のregion_idをnullに更新
```

### フローチャート

```mermaid
flowchart TD
    A[API リクエスト] --> B{操作種別}
    B -->|GET /regions| C[地域一覧取得]
    B -->|GET /regions/:id| D[地域詳細取得]
    B -->|POST /regions| E[地域作成]
    B -->|POST /regions/:id| F[地域更新]
    B -->|DELETE /regions/:id| G[地域削除]

    E --> H[入力正規化]
    H --> I[地域レコード作成]
    I --> J{国指定あり?}
    J -->|Yes| K[国バリデーション]
    K --> L{バリデーションOK?}
    L -->|No| M[エラー返却]
    L -->|Yes| N[国紐付け更新]
    N --> O[支払いプロバイダー設定]
    J -->|No| O

    F --> P[入力正規化]
    P --> Q{国変更あり?}
    Q -->|Yes| R[既存紐付け解除]
    R --> S[国バリデーション]
    S --> T[新規紐付け設定]
    Q -->|No| U[地域レコード更新]
    T --> U

    G --> V[ソフトデリート]
    V --> W[国紐付け解除]

    C --> X[remoteQuery実行]
    D --> X
    O --> Y[イベント発行]
    U --> Y
    W --> Y
    X --> Z[レスポンス返却]
    Y --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-65-01 | 通貨コード正規化 | currency_codeは小文字に正規化して保存 | 作成・更新時 |
| BR-65-02 | 国コード正規化 | 国コードは小文字に正規化 | 作成・更新時 |
| BR-65-03 | 国重複禁止 | 同一地域への重複国コード指定は不可 | 作成・更新時 |
| BR-65-04 | 他地域紐付き禁止 | 既に他の地域に紐付いている国は指定不可 | 作成・更新時 |
| BR-65-05 | 国存在確認 | 指定された国コードはDBに存在すること | 作成・更新時 |
| BR-65-06 | 削除時紐付け解除 | 地域削除時、紐付き国のregion_idはnullに設定 | 削除時 |
| BR-65-07 | 自動税計算デフォルト | automatic_taxesはデフォルトtrue | 作成時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | region | SELECT | フィルタ・ページネーション付き |
| 詳細取得 | region | SELECT | ID指定、国リレーション含む |
| 作成 | region | INSERT | 新規地域レコード |
| 作成 | region_country | UPDATE | region_id設定 |
| 更新 | region | UPDATE | 地域情報更新 |
| 更新 | region_country | UPDATE | region_id変更 |
| 削除 | region | UPDATE | deleted_at設定 |
| 削除 | region_country | UPDATE | region_idをnullに |

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

#### region

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | 自動生成（reg_プレフィックス） | - |
| INSERT | name | 入力値（トリミング済み） | searchable |
| INSERT | currency_code | 入力値（小文字化） | searchable |
| INSERT | automatic_taxes | 入力値またはtrue | デフォルトtrue |
| INSERT | metadata | 入力値 | nullable |

#### region_country

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | region_id | 地域ID | WHERE iso_2 IN (国コードリスト) |
| UPDATE | region_id | null | 地域削除時、紐付け解除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | MedusaError | 指定IDの地域が存在しない | 404レスポンス |
| INVALID_DATA | MedusaError | 国コード重複 | 400レスポンス、重複国コード表示 |
| INVALID_DATA | MedusaError | 存在しない国コード | 400レスポンス、不明国コード表示 |
| INVALID_DATA | MedusaError | 他地域に紐付き済みの国 | 400レスポンス、該当国コード表示 |

### リトライ仕様

データベース操作失敗時のリトライはワークフローエンジンで管理。

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

- 地域作成・更新・削除はワークフロー内でトランザクション管理
- @InjectTransactionManagerデコレータで内部トランザクションを制御
- 国紐付け更新も同一トランザクション内で実行

## パフォーマンス要件

- name, currency_codeカラムはsearchableで全文検索対応
- 地域IDに主キーインデックス

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

- 認証必須エンドポイント
- RBACによる権限制御可能

## 備考

- 地域IDはreg_プレフィックス付きで自動生成
- 地域名はtranslatableで多言語対応可能
- 地域削除後、同じ国を新しい地域に紐付け可能（region_idがnullになるため）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | region.ts | `packages/modules/region/src/models/region.ts` | Regionモデルの構造（id, name, currency_code, automatic_taxes, countries） |
| 1-2 | country.ts | `packages/modules/region/src/models/country.ts` | Countryモデルの構造（iso_2, iso_3, name, region） |

**読解のコツ**: RegionとCountryは1対多のリレーション。Countryはiso_2を主キーとし、region_idで地域と紐付く。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | route.ts | `packages/medusa/src/api/admin/regions/route.ts` | GET - 一覧取得、POST - 作成 |
| 2-2 | [id]/route.ts | `packages/medusa/src/api/admin/regions/[id]/route.ts` | GET, POST, DELETE - 個別操作 |

**主要処理フロー**:
1. **route.ts 13-36行目**: 一覧取得、remoteQuery使用
2. **route.ts 38-58行目**: 作成処理、createRegionsWorkflow使用
3. **[id]/route.ts 35-64行目**: 更新処理、updateRegionsWorkflow使用
4. **[id]/route.ts 66-81行目**: 削除処理、deleteRegionsWorkflow使用

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | region-module.ts | `packages/modules/region/src/services/region-module.ts` | RegionModuleServiceの実装 |

**主要処理フロー**:
- **84-94行目**: createRegions - 入力正規化、レコード作成
- **97-134行目**: createRegions_ - 国バリデーション、紐付け更新
- **256-304行目**: updateRegions_ - 既存紐付け解除、新規紐付け
- **325-377行目**: validateCountries - 国バリデーション処理

#### Step 4: ワークフローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | create-regions.ts | `packages/core/core-flows/src/region/workflows/create-regions.ts` | 作成ワークフロー |

**主要処理フロー**:
- **41-124行目**: 地域作成、支払いプロバイダー設定、価格優先設定、イベント発行

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

```
Admin API Route
    │
    ├─ POST /regions
    │      └─ createRegionsWorkflow
    │             ├─ createRegionsStep
    │             │      └─ regionService.createRegions
    │             │             ├─ normalizeInput
    │             │             ├─ regionService_.create
    │             │             ├─ validateCountries
    │             │             └─ countryService_.update
    │             ├─ setRegionsPaymentProvidersStep
    │             └─ createPricePreferencesWorkflow
    │
    ├─ POST /regions/:id
    │      └─ updateRegionsWorkflow
    │             └─ updateRegionsStep
    │                    └─ regionService.updateRegions
    │
    └─ DELETE /regions/:id
           └─ deleteRegionsWorkflow
                  └─ regionService.softDeleteRegions
                         └─ countryService_.update (region_id = null)
```

### データフロー図

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

地域作成
  name ─────────────▶ normalizeInput ───────────▶ Region record
  currency_code              │
  countries[]                ▼
                     validateCountries
                            │
                   ┌────────┴────────┐
                   ▼                 ▼
              バリデーションOK    エラー
                   │                 │
                   ▼                 ▼
             countryService.update  MedusaError
             (region_id設定)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| region.ts | `packages/modules/region/src/models/region.ts` | ソース | Regionモデル定義 |
| country.ts | `packages/modules/region/src/models/country.ts` | ソース | Countryモデル定義 |
| region-module.ts | `packages/modules/region/src/services/region-module.ts` | ソース | RegionModuleService |
| route.ts | `packages/medusa/src/api/admin/regions/route.ts` | ソース | 地域一覧・作成API |
| [id]/route.ts | `packages/medusa/src/api/admin/regions/[id]/route.ts` | ソース | 地域個別API |
| create-regions.ts | `packages/core/core-flows/src/region/workflows/create-regions.ts` | ソース | 作成ワークフロー |
| update-regions.ts | `packages/core/core-flows/src/region/workflows/update-regions.ts` | ソース | 更新ワークフロー |
| delete-regions.ts | `packages/core/core-flows/src/region/workflows/delete-regions.ts` | ソース | 削除ワークフロー |
