# 機能設計書 6-商品タグ管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける商品タグ（Product Tag）管理機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：
商品タグは、商品に付与するラベル・キーワードとして機能し、商品の検索性向上やフィルタリングに使用される。カテゴリやコレクションとは異なり、1つの商品に複数のタグを付与できる多対多の関係を持つ。

**機能の利用シーン**：
- 商品の検索用キーワードとしてタグを追加
- シーズン（「春夏」「秋冬」）や特性（「セール」「新着」「限定」）でタグ付け
- ストアフロントでのタグフィルター機能
- タグ名の変更・統合
- 不要なタグの削除

**主要な処理内容**：
1. タグの新規作成（値の設定）
2. タグの一覧取得
3. タグの個別取得
4. タグの更新
5. タグの削除

**関連システム・外部連携**：
- 商品モジュール（Product Module）：商品とタグの多対多関連
- ストアフロント：タグ別商品フィルター機能

**権限による制御**：
- Admin API経由のアクセスには認証が必要（AuthenticatedMedusaRequest）
- タグの作成・更新・削除は管理者権限を持つユーザーのみ実行可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 商品編集画面 | 関連画面 | タグの選択・追加 |

## 機能種別

CRUD操作（Create / Read / Update / Delete）

## 入力仕様

### 入力パラメータ

#### タグ作成（POST /admin/product-tags）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| value | string | Yes | タグ値 | ユニーク（deleted_at IS NULL） |
| metadata | object | No | メタデータ | JSON形式 |

#### タグ更新（POST /admin/product-tags/:id）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| value | string | No | タグ値 | ユニーク |
| metadata | object | No | メタデータ | - |

### 入力データソース

- 管理画面（Admin Dashboard）からのフォーム入力
- REST API経由のJSON/リクエストボディ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | タグID（ptag_xxx形式） |
| value | string | タグ値 |
| products | array | 関連商品配列 |
| metadata | object | メタデータ |
| created_at | datetime | 作成日時 |
| updated_at | datetime | 更新日時 |
| deleted_at | datetime | 削除日時 |

### 出力先

- REST APIレスポンス（JSON形式）
- 管理画面への表示

## 処理フロー

### 処理シーケンス

```
1. タグ作成フロー
   ├─ タグ作成（createProductTagsStep）
   ├─ フック実行（productTagsCreated）
   └─ イベント発行（ProductTagWorkflowEvents.CREATED）

2. タグ取得フロー
   ├─ フィルタ条件の適用
   ├─ refetchEntitiesによるデータ取得
   └─ レスポンス整形

3. タグ更新フロー
   ├─ 既存タグの存在確認
   ├─ タグ更新（updateProductTagsStep）
   ├─ フック実行（productTagsUpdated）
   └─ イベント発行（ProductTagWorkflowEvents.UPDATED）

4. タグ削除フロー
   ├─ タグ削除（deleteProductTagsStep）
   ├─ フック実行（productTagsDeleted）
   └─ イベント発行（ProductTagWorkflowEvents.DELETED）
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-T01 | タグ値一意性 | valueは削除されていないタグ間でユニーク | タグ作成・更新時 |
| BR-T02 | 商品多重所属 | 1つの商品は複数のタグに属することができる | 商品タグ関連付け時 |
| BR-T03 | タグ共有 | 1つのタグは複数の商品に付与可能 | 商品タグ関連付け時 |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | product_tag | INSERT | タグレコードの挿入 |
| 取得 | product_tag | SELECT | タグの取得 |
| 更新 | product_tag | UPDATE | タグの更新 |
| 削除 | product_tag | UPDATE | deleted_atの設定（論理削除） |

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

#### product_tag

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | 自動生成（ptag_xxx形式） | generateEntityId使用 |
| INSERT | value | リクエストの値 | 必須、ユニーク |
| DELETE | deleted_at | 現在日時 | 論理削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | 404 | 指定IDのタグが存在しない | 正しいIDを指定 |
| INVALID_DATA | 400 | valueが重複 | ユニークな値を指定 |

## 備考

- タグのIDプレフィックスは「ptag」
- タグは商品と多対多（manyToMany）の関係
- valueフィールドはsearchable/translatable属性を持つ

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | product-tag.ts | `packages/modules/product/src/models/product-tag.ts` | タグモデル定義 |

**主要処理フロー（product-tag.ts）**:
- **4-15行目**: ProductTagモデル定義
- **8行目**: IDプレフィックス「ptag」
- **9行目**: valueフィールド（searchable, translatable）
- **11-13行目**: 商品との多対多リレーション
- **16-22行目**: ユニークインデックス（value）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | route.ts | `packages/medusa/src/api/admin/product-tags/route.ts` | 一覧・作成エンドポイント |
| 2-2 | [id]/route.ts | `packages/medusa/src/api/admin/product-tags/[id]/route.ts` | 詳細・更新・削除 |

**主要処理フロー（route.ts）**:
- **11-29行目**: GET - refetchEntitiesでタグ一覧取得
- **31-52行目**: POST - createProductTagsWorkflowでタグ作成

**主要処理フロー（[id]/route.ts）**:
- **13-27行目**: GET - 個別タグ取得
- **29-65行目**: POST - 更新前存在確認、updateProductTagsWorkflow実行
- **67-82行目**: DELETE - deleteProductTagsWorkflow実行

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create-product-tags.ts | `packages/core/core-flows/src/product/workflows/create-product-tags.ts` | 作成ワークフロー |
| 3-2 | update-product-tags.ts | `packages/core/core-flows/src/product/workflows/update-product-tags.ts` | 更新ワークフロー |
| 3-3 | delete-product-tags.ts | `packages/core/core-flows/src/product/workflows/delete-product-tags.ts` | 削除ワークフロー |

**主要処理フロー（create-product-tags.ts）**:
- **54-78行目**: createProductTagsWorkflow定義
- **57行目**: createProductTagsStepでタグ作成
- **58-61行目**: productTagsCreatedフック
- **69-72行目**: ProductTagWorkflowEvents.CREATEDイベント発行

**主要処理フロー（update-product-tags.ts）**:
- **59-90行目**: updateProductTagsWorkflow定義
- **62行目**: updateProductTagsStepで更新
- **63-66行目**: productTagsUpdatedフック
- **81-84行目**: ProductTagWorkflowEvents.UPDATEDイベント発行

**主要処理フロー（delete-product-tags.ts）**:
- **46-69行目**: deleteProductTagsWorkflow定義
- **49行目**: deleteProductTagsStepで削除
- **50-52行目**: productTagsDeletedフック
- **60-63行目**: ProductTagWorkflowEvents.DELETEDイベント発行

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

```
[Admin Dashboard / REST Client]
    │
    ▼
POST /admin/product-tags
    │
    ├──▶ createProductTagsWorkflow
    │       ├── createProductTagsStep
    │       ├── createHook("productTagsCreated")
    │       └── emitEventStep(ProductTagWorkflowEvents.CREATED)
    │
POST /admin/product-tags/:id (更新)
    │
    ├──▶ updateProductTagsWorkflow
    │       ├── updateProductTagsStep
    │       ├── createHook("productTagsUpdated")
    │       └── emitEventStep(ProductTagWorkflowEvents.UPDATED)
    │
DELETE /admin/product-tags/:id
    │
    └──▶ deleteProductTagsWorkflow
            ├── deleteProductTagsStep
            ├── createHook("productTagsDeleted")
            └── emitEventStep(ProductTagWorkflowEvents.DELETED)
```

### データフロー図

```
┌─────────────────────────────────────────────────────────┐
│                     Admin API Layer                      │
│  ┌─────────────────────────────────────────────────────┐│
│  │              /admin/product-tags/                   ││
│  │  ┌──────────┐  ┌──────────┐  ┌──────────────────┐  ││
│  │  │   GET    │  │   POST   │  │   POST/:id       │  ││
│  │  │(一覧取得)│  │  (作成)  │  │  (更新/削除)     │  ││
│  │  └────┬─────┘  └────┬─────┘  └────┬─────────────┘  ││
│  └───────┼─────────────┼─────────────┼────────────────┘│
└──────────┼─────────────┼─────────────┼─────────────────┘
           │             │             │
           ▼             ▼             ▼
┌─────────────────────────────────────────────────────────┐
│                   Workflow Layer                         │
│  ┌────────────────────┬───────────────┬───────────────┐ │
│  │  createProductTags │ updateProduct │ deleteProduct │ │
│  │  Workflow          │ TagsWorkflow  │ TagsWorkflow  │ │
│  └─────────┬──────────┴───────┬───────┴───────┬───────┘ │
│            │                  │               │         │
│            ▼                  ▼               ▼         │
│  ┌────────────────────────────────────────────────────┐ │
│  │           Product Module (Product Tag)            │ │
│  │  ┌────────────┬────────────┬────────────────────┐ │ │
│  │  │   create   │   update   │      delete        │ │ │
│  │  └─────┬──────┴─────┬──────┴─────────┬──────────┘ │ │
│  └────────┼────────────┼────────────────┼────────────┘ │
└───────────┼────────────┼────────────────┼──────────────┘
            │            │                │
            ▼            ▼                ▼
┌─────────────────────────────────────────────────────────┐
│                   Database Layer                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │              product_tag table                    │  │
│  │  id (ptag_xxx) | value | metadata | deleted_at   │  │
│  └───────────────────────────────────────────────────┘  │
│                         ▲                               │
│                         │ manyToMany                    │
│                         ▼                               │
│  ┌───────────────────────────────────────────────────┐  │
│  │           product_tag_product (中間テーブル)       │  │
│  │         product_id | product_tag_id              │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product-tag.ts | `packages/modules/product/src/models/product-tag.ts` | モデル | タグエンティティ定義 |
| route.ts | `packages/medusa/src/api/admin/product-tags/route.ts` | API | 一覧・作成エンドポイント |
| [id]/route.ts | `packages/medusa/src/api/admin/product-tags/[id]/route.ts` | API | 詳細・更新・削除 |
| create-product-tags.ts | `packages/core/core-flows/src/product/workflows/create-product-tags.ts` | ワークフロー | 作成処理 |
| update-product-tags.ts | `packages/core/core-flows/src/product/workflows/update-product-tags.ts` | ワークフロー | 更新処理 |
| delete-product-tags.ts | `packages/core/core-flows/src/product/workflows/delete-product-tags.ts` | ワークフロー | 削除処理 |
