# 通知設計書 5-商品エクスポート失敗通知

## 概要

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

### 本通知の処理概要

本通知は、管理者が商品データをCSVファイルにエクスポートする際、エクスポート処理が失敗した場合に管理画面のフィード（通知一覧）にエラーを表示する機能を提供する。notifyOnFailureStepの補償処理（compensation）として実行され、exportProductsWorkflow内のいずれかのステップが失敗した時点で自動的にトリガーされる。

**業務上の目的・背景**：商品エクスポートはバックグラウンドで非同期実行されるため、管理者は処理の失敗を即座に検知できない。この通知により、管理者はエクスポート処理が失敗したことを速やかに把握し、再試行やシステム担当者への問い合わせなどの対応を取ることができる。業務の中断を最小限に抑え、問題の早期発見・解決を支援する。

**通知の送信タイミング**：商品エクスポートワークフロー（exportProductsWorkflow）のいずれかのステップ（exportProductsStep、useQueryGraphStep、sendNotificationsStep）が失敗し、ワークフローの補償処理が実行される時点で送信される。notifyOnFailureStepのcompensate関数が呼び出されるタイミング。

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

**通知内容の概要**：エクスポート失敗メッセージが表示される。「Failed to export products, please try again later.」という形式で、再試行を促すメッセージが含まれる。具体的なエラー原因や対象データの情報は含まれない。

**期待されるアクション**：管理者は通知を確認し、しばらく時間をおいてから再度エクスポートを試みることが期待される。問題が繰り返し発生する場合は、システムログを確認するか、システム担当者に問い合わせる。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（ワークフロー補償処理） |
| 優先度 | 高 |
| リトライ | 無（補償処理内でのエラーはワークフローフレームワークに依存） |

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

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

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

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| チャネル | feed |
| テンプレートID | admin-ui |
| タイトル | Product export |
| 説明 | Failed to export products, please try again later. |

### 本文テンプレート

```
タイトル: Product export
説明: Failed to export products, please try again later.
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 失敗通知には添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| title | 通知タイトル | 固定値 "Product export" | Yes |
| description | 通知説明文 | 固定値 "Failed to export products, please try again later." | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ワークフロー補償 | exportProductsWorkflowの任意ステップ失敗 | notifyOnFailureStep以降のステップでエラー発生 | 補償処理でcompensate関数が呼び出される |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| notifyOnFailureStep前の失敗 | exportProductsStep.config呼び出し前に失敗した場合（通常は発生しない） |
| 正常完了 | ワークフローが正常に完了した場合（補償処理が実行されない） |
| feedプロバイダー未設定 | feedチャネルに対応するNotification Providerが未設定の場合 |

## 処理フロー

### 送信フロー

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| notification_provider | プロバイダー情報取得 | feedチャネルに対応するプロバイダーを検索 |
| notification | 重複チェック | idempotency_keyによる既存通知確認（設定時） |

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

#### notification_provider

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | プロバイダーID | channels配列に"feed"を含む |
| is_enabled | 有効フラグ | - |
| channels | 対応チャネル | - |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| notification | INSERT | 通知レコードの作成 |
| file | DELETE | 失敗時の補償処理でアップロードされたファイルを削除 |

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

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | id | noti_xxx形式で自動生成 | - |
| INSERT | to | "" | 空文字列（全体通知） |
| INSERT | channel | "feed" | 固定値 |
| INSERT | template | "admin-ui" | テンプレートID |
| INSERT | data | {title, description} | 通知内容（失敗メッセージ） |
| INSERT | status | "success" / "failure" | 通知送信自体の結果 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| エクスポート失敗 | exportProductsStepでエラー | 補償処理で失敗通知送信、ファイル削除 |
| ファイルURL取得失敗 | useQueryGraphStepでエラー | 補償処理で失敗通知送信 |
| プロバイダー未設定 | feedチャネルのプロバイダーなし | 補償処理内でエラー、ワークフローフレームワークに伝播 |
| 補償データなし | data引数がnull/undefined | 早期リターンで処理スキップ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | ワークフローフレームワーク依存 |
| リトライ間隔 | ワークフローフレームワーク依存 |
| リトライ対象エラー | ワークフローフレームワーク依存 |

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- 通知は管理者向けであり、顧客の個人情報は含まれない
- エラーの詳細情報は通知に含まれない（セキュリティ上の配慮）
- 管理画面へのアクセスには認証が必要
- 失敗時はアップロードされたファイルが削除され、不完全なデータが残らない

## 備考

- 失敗通知には具体的なエラー原因が含まれない（インポート失敗通知と同様の制限）
- exportProductsStepの補償処理により、失敗時はアップロードされたファイルが自動削除される
- 失敗メッセージにはファイル名や対象データの情報が含まれない（インポート失敗通知との違い）
- 「please try again later.」という再試行を促すメッセージが含まれる
- 失敗通知と成功通知のタイトルは同じ「Product export」だが、descriptionで区別可能

---

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

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

### 推奨読解順序

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

まず、通知データの構造と補償処理で渡されるデータを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | notify-on-failure.ts | `packages/core/core-flows/src/notification/steps/notify-on-failure.ts` | NotifyOnFailureStepInput型を確認 |
| 1-2 | common.ts | `packages/core/types/src/notification/common.ts` | NotificationDTOの構造を確認 |

**読解のコツ**: 補償処理で渡されるデータと、notificationService.createNotificationsに渡されるデータの対応を理解する。

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

ワークフロー内でのnotifyOnFailureStep登録箇所を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | export-products.ts (workflow) | `packages/core/core-flows/src/product/workflows/export-products.ts` | 失敗通知データ構築とステップ登録 |

**主要処理フロー (export-products.ts)**:
1. **行63-76**: transform - 失敗通知データ構築
2. **行65**: to: "" - 送信先は空文字列
3. **行66**: channel: "feed" - フィードチャネル
4. **行67**: template: "admin-ui" - テンプレートID
5. **行69**: title: "Product export" - タイトル
6. **行70**: description - 固定の失敗メッセージ
7. **行77**: notifyOnFailureStep(failureNotification) - ステップ登録

#### Step 3: 補償処理の仕組みを理解する

notifyOnFailureStepの補償処理を理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | notify-on-failure.ts | `packages/core/core-flows/src/notification/steps/notify-on-failure.ts` | ステップ全体の実装 |

**主要処理フロー**:
- **行74**: createStep定義開始
- **行76-77**: mainAction - StepResponse(void 0, data)で補償データを設定
- **行80-89**: compensateAction - 失敗時の通知送信
- **行81-83**: data引数のnullチェックと早期リターン
- **行85-87**: notificationService取得
- **行88**: createNotifications呼び出し

#### Step 4: ファイル削除の補償処理を理解する

exportProductsStepの補償処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | export-products.ts (steps) | `packages/core/core-flows/src/product/steps/export-products.ts` | 補償処理でのファイル削除 |

**主要処理フロー**:
- **行92-99**: compensate関数
- **行93-95**: fileIdのnullチェック
- **行97**: fileModule取得
- **行98**: fileModule.deleteFiles(fileId) - ファイル削除

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

```
[商品エクスポートAPI]
    │
    └─ exportProductsWorkflow
           │
           ├─ exportProductsStep.invoke
           │      │   行58-61
           │      │
           │      └─ StepResponse({id: fileKey, filename}, fileKey)
           │            補償データとしてfileKeyを保存
           │
           ├─ transform (失敗通知データ構築)
           │      │   行63-76
           │      │
           │      └─ 失敗通知データ生成
           │           {to: "", channel: "feed", template: "admin-ui",
           │            data: {title: "Product export",
           │                   description: "Failed to export products..."}}
           │
           ├─ notifyOnFailureStep.invoke
           │      │   行77
           │      │
           │      └─ StepResponse(void 0, failureNotification)
           │            補償データとして失敗通知データを保存
           │
           ├─ useQueryGraphStep / sendNotificationsStep
           │      │
           │      └─ [失敗時] ワークフロー補償開始
           │
           └─ [補償処理（逆順実行）]
                  │
                  ├─ notifyOnFailureStep.compensate
                  │      │   行80-89
                  │      │
                  │      └─ service.createNotifications(data)
                  │             失敗通知送信
                  │
                  └─ exportProductsStep.compensate
                         │   行92-99
                         │
                         └─ fileModule.deleteFiles(fileId)
                               アップロードファイル削除
```

### データフロー図

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

ExportProductsDTO        ───▶  ワークフロー開始
  │                                   │
  └─ (selectやfilter)                 │
                                      │
                                      ▼
                               transform (失敗通知データ)
                                      │
                                      ├─ to: ""
                                      ├─ channel: "feed"
                                      ├─ template: "admin-ui"
                                      └─ data:
                                           ├─ title: "Product export"
                                           └─ description:
                                              "Failed to export products,
                                               please try again later."
                                      │
                                      ▼
                               notifyOnFailureStep
                                      │
                                      │ mainAction: 補償データとして保存
                                      │
                               [ワークフロー失敗時]
                                      │
                                      ▼
                               notifyOnFailureStep.compensate
                                      │
                                      ▼
                               NotificationModuleService
                                .createNotifications
                                      │
                                      ▼
                               [notification テーブル]
                                      │
                                      ▼
                               [管理画面フィード表示]

                               exportProductsStep.compensate
                                      │
                                      ▼
                               fileModule.deleteFiles
                                      │
                                      ▼
                               [アップロードファイル削除]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| 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` | ソース | エクスポートステップ、ファイル削除補償処理 |
| 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` | ソース | 通知モジュールサービス |
| common.ts | `packages/core/types/src/notification/common.ts` | 型定義 | NotificationDTO型定義 |
