# 通知設計書 4-商品エクスポート成功通知

## 概要

本ドキュメントは、Medusa ECプラットフォームにおける商品エクスポート完了時の管理者向けフィード通知機能について、その仕様と実装詳細を記述する。

### 本通知の処理概要

本通知は、管理者が商品データをCSVファイルにエクスポートする際、エクスポート処理が正常に完了したことを管理画面のフィード（通知一覧）に表示する機能を提供する。exportProductsWorkflowが正常終了した際にsendNotificationsStepが実行され、ダウンロードリンク付きの成功通知を管理者に送信する。

**業務上の目的・背景**：商品エクスポートはバックグラウンドで非同期実行されるため、管理者は処理の完了を即座に確認できない。この通知により、管理者は商品エクスポートが正常に完了したことを知り、すぐにダウンロードリンクからCSVファイルを取得できる。大量の商品データを扱う際の作業効率を大幅に向上させる。

**通知の送信タイミング**：商品エクスポートワークフロー（exportProductsWorkflow）がexportProductsStep、useQueryGraphStepを含むすべてのステップを正常に完了し、ファイルのアップロードとURL取得が完了した後、sendNotificationsStepが実行される時点で送信される。

**通知の受信者**：管理者全般。現在の実装では特定の受信者を指定せず（to: ""）、管理画面のフィードに表示される形式となっている。将来的には特定ユーザーへのプッシュ通知も検討されている（コードコメントより）。

**通知内容の概要**：エクスポート成功メッセージとともに、ダウンロード用のファイル情報（ファイル名、URL、MIMEタイプ）が含まれる。管理者は通知から直接CSVファイルをダウンロードできる。

**期待されるアクション**：管理者は通知を確認し、ダウンロードリンクからCSVファイルを取得する。必要に応じて、ファイルの内容を確認し、他システムへの連携や分析に使用する。

## 通知種別

管理画面フィード（feed）/ アプリ内通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ワークフロー内ステップ） |
| 優先度 | 中 |
| リトライ | 無（ワークフロー補償処理なし） |

### 送信先決定ロジック

現在の実装では、送信先（to）は空文字列に設定されており、特定の受信者を指定しない。管理画面のフィード機能により、全管理者が閲覧可能な形式で表示される。

```typescript
to: ""  // 特定受信者なし
```

## 通知テンプレート

### フィード通知の場合

| 項目 | 内容 |
|-----|------|
| チャネル | feed |
| テンプレートID | admin-ui |
| タイトル | Product export |
| 説明 | Product export completed successfully! |

### 本文テンプレート

```
タイトル: Product export
説明: Product export completed successfully!
ファイル情報:
  - filename: {タイムスタンプ}-product-exports.csv
  - url: {ファイルダウンロードURL}
  - mimeType: text/csv

例:
タイトル: Product export
説明: Product export completed successfully!
ファイル:
  - filename: 1708800000000-product-exports.csv
  - url: https://storage.example.com/exports/...
  - mimeType: text/csv
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| {タイムスタンプ}-product-exports.csv | CSV | 常時 | 商品エクスポートデータ（ダウンロードリンクとして提供） |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| title | 通知タイトル | 固定値 "Product export" | Yes |
| description | 通知説明文 | 固定値 "Product export completed successfully!" | Yes |
| file.filename | ファイル名 | exportProductsStep出力 | Yes |
| file.url | ダウンロードURL | useQueryGraphStep（fileエンティティ） | Yes |
| file.mimeType | MIMEタイプ | 固定値 "text/csv" | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ワークフロー | exportProductsWorkflow正常完了 | exportProductsStep、useQueryGraphStep成功後 | 商品エクスポート処理成功時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ワークフロー失敗 | 途中のステップでエラーが発生した場合、成功通知は送信されない |
| feedプロバイダー未設定 | feedチャネルに対応するNotification Providerが未設定の場合 |
| ファイルURL取得失敗 | useQueryGraphStepでファイル情報が取得できない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[商品エクスポートAPI呼び出し] --> B[exportProductsWorkflow開始]
    B --> C[exportProductsStep: CSV生成・アップロード]
    C --> D{エクスポート成功?}
    D -->|失敗| E[notifyOnFailureStep補償実行]
    D -->|成功| F[notifyOnFailureStep登録]
    F --> G[useQueryGraphStep: ファイル情報取得]
    G --> H[transform: 成功通知データ構築]
    H --> I[sendNotificationsStep実行]
    I --> J[notificationService.createNotifications]
    J --> K[フィードにダウンロードリンク付き通知表示]
    K --> L[ワークフロー完了]
    E --> M[失敗通知送信]
    M --> N[終了]
    L --> N
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| product | 商品データ取得 | エクスポート対象商品の取得 |
| region | 地域情報取得 | 価格情報の通貨コード等 |
| file | ファイル情報取得 | アップロードされたCSVファイルのURL取得 |
| notification_provider | プロバイダー情報取得 | feedチャネルに対応するプロバイダーを検索 |

### テーブル別参照項目詳細

#### product

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | 商品ID | フィルター条件に基づく |
| handle | 商品ハンドル | select指定項目 |
| その他select指定項目 | エクスポートデータ | ワークフロー入力のselect |

#### file

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | ファイルID | exportProductsStep出力のfileKey |
| url | ダウンロードURL | 通知に含めるリンク |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| file | INSERT | CSVファイルのアップロード |
| notification | INSERT | 通知レコードの作成 |

#### ファイルテーブル（file）

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | id | fileKey | ファイルモジュールが生成 |
| INSERT | filename | {timestamp}-product-exports.csv | タイムスタンプ付きファイル名 |
| INSERT | mime_type | text/csv | CSVファイル |

#### 送信ログテーブル（notification）

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | id | noti_xxx形式で自動生成 | - |
| INSERT | to | "" | 空文字列（全体通知） |
| INSERT | channel | "feed" | 固定値 |
| INSERT | template | "admin-ui" | テンプレートID |
| INSERT | data | {title, description, file} | 通知内容（ダウンロードリンク含む） |
| INSERT | status | "success" | 送信結果 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| エクスポート失敗 | exportProductsStepでエラー | notifyOnFailureStepの補償処理で失敗通知 |
| ファイルURL取得失敗 | useQueryGraphStepでファイル情報なし | ワークフロー失敗、補償処理実行 |
| プロバイダー未設定 | feedチャネルのプロバイダーなし | MedusaError発生、通知作成失敗 |
| プロバイダー無効 | プロバイダーのis_enabled=false | MedusaError発生、通知作成失敗 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

※ 失敗時はexportProductsStepの補償処理でファイルが削除される

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（feed通知のため） |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし（エクスポート完了時に即時通知）

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

- 通知は管理者向けであり、顧客の個人情報は含まれない
- ダウンロードURLは認証が必要な管理画面内でのみアクセス可能
- ファイルアクセス権限はファイルモジュールの設定に依存
- エクスポートされるデータには商品情報のみが含まれる

## 備考

- エクスポートはバックグラウンド実行（backgroundExecution: true）されるため、APIレスポンスは即座に返却される
- ファイル名にはタイムスタンプが含まれ、一意性が保証される
- デフォルトのバッチサイズは50件で、ページネーション処理で大量データにも対応
- 失敗時の補償処理でアップロードされたファイルは削除される
- ファイルURLはuseQueryGraphStepで取得され、fileエンティティから動的に解決される

---

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

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

### 推奨読解順序

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

まず、エクスポート入力とファイル出力の構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | export-products.ts (types) | `packages/core/types/src/workflow/product/export-products.ts` | ExportProductsDTOの構造を確認 |
| 1-2 | export-products.ts (steps) | `packages/core/core-flows/src/product/steps/export-products.ts` | ステップの入出力を確認 |

**読解のコツ**: ファイルID（fileKey）がどのように生成され、後続でどう使用されるかを追跡する。

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

ワークフロー定義が処理の起点。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | export-products.ts (workflow) | `packages/core/core-flows/src/product/workflows/export-products.ts` | ワークフロー全体の流れを把握 |

**主要処理フロー (export-products.ts)**:
1. **行53-108**: createWorkflowでワークフロー定義
2. **行58-61**: exportProductsStep実行（async: true, backgroundExecution: true）
3. **行63-76**: transform - 失敗通知データ構築
4. **行77**: notifyOnFailureStep - 失敗時通知登録
5. **行79-84**: useQueryGraphStep - ファイル情報取得
6. **行86-104**: transform - 成功通知データ構築（ダウンロードリンク含む）
7. **行106**: sendNotificationsStep - 成功通知送信

#### Step 3: エクスポートステップを理解する

CSVファイル生成の詳細を理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | export-products.ts (steps) | `packages/core/core-flows/src/product/steps/export-products.ts` | CSV生成とアップロード処理 |

**主要処理フロー**:
- **行15-100**: exportProductsStep定義
- **行30**: ファイル名生成（{Date.now()}-product-exports.csv）
- **行31-34**: ファイルアップロードストリーム取得
- **行45-84**: ページネーション処理でデータ取得・CSV変換
- **行90**: StepResponse(id: fileKey, filename)
- **行92-99**: 補償処理（ファイル削除）

#### Step 4: ファイル情報取得を理解する

useQueryGraphStepでのファイルURL取得を理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | export-products.ts (workflow) | `packages/core/core-flows/src/product/workflows/export-products.ts` 行79-84 | useQueryGraphStepの使用方法 |

**主要処理フロー**:
- **行79-84**: useQueryGraphStepでfileエンティティからid, urlを取得
- **行82**: filters: { id: file.id } でファイルIDで検索
- **行83**: options: { isList: false } で単一レコード取得

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

```
[商品エクスポートAPI]
    │
    └─ exportProductsWorkflow
           │   行53-108
           │
           ├─ exportProductsStep
           │      │   行58-61 (async: true, backgroundExecution: true)
           │      │
           │      ├─ query.graph (商品データ取得)
           │      │      行46-54
           │      │
           │      ├─ normalizeForExport (データ正規化)
           │      │      行60
           │      │
           │      ├─ json2csv (CSV変換)
           │      │      行62-70
           │      │
           │      ├─ writeStream.write (ファイル書き込み)
           │      │      行72-75
           │      │
           │      └─ StepResponse({id: fileKey, filename})
           │             行90
           │
           ├─ transform (失敗通知データ)
           │      行63-76
           │
           ├─ notifyOnFailureStep
           │      行77
           │
           ├─ useQueryGraphStep
           │      │   行79-84
           │      │
           │      └─ ファイル情報取得 (id, url)
           │
           ├─ transform (成功通知データ)
           │      │   行86-104
           │      │
           │      └─ ダウンロードリンク情報を含む通知データ生成
           │
           └─ sendNotificationsStep
                  行106
```

### データフロー図

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

ExportProductsDTO        ───▶  exportProductsWorkflow
  │                                   │
  ├─ select                           │
  └─ filter                           │
                                      │
                                      ▼
                               exportProductsStep
                                      │
                                      ├─ 商品データ取得 (query.graph)
                                      │
                                      ├─ CSV変換 (json2csv)
                                      │
                                      └─ ファイルアップロード
                                             │
                                             ▼
                                      {id: fileKey, filename}
                                             │
                                             ▼
                               useQueryGraphStep
                                      │
                                      └─ ファイルURL取得
                                             │
                                             ▼
                               transform (成功通知データ)
                                      │
                                      ├─ title: "Product export"
                                      ├─ description: "...completed successfully!"
                                      └─ file:
                                           ├─ filename
                                           ├─ url
                                           └─ mimeType: "text/csv"
                                             │
                                             ▼
                               sendNotificationsStep
                                      │
                                      ▼
                               [管理画面フィード]
                               (ダウンロードリンク付き)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| export-products.ts (workflow) | `packages/core/core-flows/src/product/workflows/export-products.ts` | ソース | 商品エクスポートワークフロー定義 |
| export-products.ts (steps) | `packages/core/core-flows/src/product/steps/export-products.ts` | ソース | CSV生成・アップロードステップ |
| normalize-for-export.ts | `packages/core/core-flows/src/product/helpers/normalize-for-export.ts` | ソース | エクスポートデータ正規化ヘルパー |
| send-notifications.ts | `packages/core/core-flows/src/notification/steps/send-notifications.ts` | ソース | 通知送信ステップ |
| notify-on-failure.ts | `packages/core/core-flows/src/notification/steps/notify-on-failure.ts` | ソース | 失敗時通知ステップ |
| notification-module-service.ts | `packages/modules/notification/src/services/notification-module-service.ts` | ソース | 通知モジュールサービス |
| export-products.ts (types) | `packages/core/types/src/workflow/product/export-products.ts` | 型定義 | ワークフロー入力型 |
