# 通知設計書 3-商品インポート失敗通知

## 概要

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

### 本通知の処理概要

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

**業務上の目的・背景**：商品インポートはバックグラウンドで非同期実行されるため、管理者は処理の失敗を即座に検知できない。この通知により、管理者はインポート処理が失敗したことを速やかに把握し、CSVファイルの修正やリトライなどの対応を取ることができる。業務効率の低下を防ぎ、問題の早期発見・解決を支援する。

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

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

**通知内容の概要**：インポートしたファイル名を含む失敗メッセージが表示される。「Failed to import products from file {filename}」という形式で、どのファイルのインポートが失敗したかを明示する。ただし、具体的なエラー原因は含まれない（現在の実装上の制限）。

**期待されるアクション**：管理者は通知を確認し、CSVファイルの内容を確認・修正してから再度インポートを試みることが期待される。必要に応じて、システムログを確認して詳細なエラー原因を調査する。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

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

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| チャネル | feed |
| テンプレートID | admin-ui |
| タイトル | Product import |
| 説明 | Failed to import products from file {filename} |

### 本文テンプレート

```
タイトル: Product import
説明: Failed to import products from file {ファイル名}

例:
タイトル: Product import
説明: Failed to import products from file products.csv
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| title | 通知タイトル | 固定値 "Product import" | Yes |
| description | 通知説明文 | ワークフロー入力のfilename | Yes |

## 送信トリガー・条件

### トリガー一覧

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

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| notifyOnFailureStep前の失敗 | normalizeCsvStep、waitConfirmationProductImportStepなど、notifyOnFailureStep登録前に失敗した場合 |
| 正常完了 | ワークフローが正常に完了した場合（補償処理が実行されない） |
| feedプロバイダー未設定 | feedチャネルに対応するNotification Providerが未設定の場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[商品インポートAPI呼び出し] --> B[importProductsWorkflow開始]
    B --> C[normalizeCsvStep: CSV解析]
    C --> D[waitConfirmationProductImportStep: 確認待ち]
    D --> E{ユーザー確認}
    E -->|キャンセル| F[処理終了]
    E -->|確認| G[notifyOnFailureStep登録]
    G --> H[batchProductsWorkflow実行]
    H --> I{インポート成功?}
    I -->|成功| J[成功通知送信]
    I -->|失敗| K[ワークフロー補償処理開始]
    K --> L[notifyOnFailureStep.compensate実行]
    L --> M[失敗通知データ取得]
    M --> N[notificationService.createNotifications]
    N --> O[フィードに失敗通知表示]
    O --> P[補償処理完了]
    J --> Q[終了]
    F --> Q
    P --> Q
```

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

### 参照テーブル一覧

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

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

#### notification_provider

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

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| notification | INSERT | 通知レコードの作成 |

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

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| プロバイダー未設定 | feedチャネルのプロバイダーが見つからない | 補償処理内でエラー、ワークフローフレームワークに伝播 |
| プロバイダー無効 | プロバイダーのis_enabled=false | 補償処理内でエラー、ワークフローフレームワークに伝播 |
| 補償データなし | data引数がnull/undefined | 早期リターンで処理スキップ |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（インポート失敗時に即時通知）

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

- 通知は管理者向けであり、顧客の個人情報は含まれない
- ファイル名のみが通知内容に含まれるため、機密情報の漏洩リスクは低い
- 管理画面へのアクセスには認証が必要
- エラーの詳細情報は通知に含まれない（セキュリティ上の配慮として適切）

## 備考

- 現在の実装では具体的なエラー原因を通知に含めることができない（コードコメント「Q: Can we somehow access the error from the step that threw here?」より）
- notifyOnFailureStepは成功通知（sendNotificationsStep）より前に配置されており、確実に補償処理として登録される
- notifyOnFailureStepのmainActionは何も処理せず、補償データを渡すのみ
- 補償関数内でdata引数がない場合は早期リターンする安全設計
- 失敗通知と成功通知のタイトルは同じ「Product import」だが、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 | import-products.ts | `packages/core/core-flows/src/product/workflows/import-products.ts` | 失敗通知データ構築とステップ登録 |
| 2-2 | import-products-as-chunks.ts | `packages/core/core-flows/src/product/workflows/import-products-as-chunks.ts` | チャンク版ワークフローでの同様の実装 |

**主要処理フロー (import-products.ts)**:
1. **行104コメント**: エラー情報へのアクセスに関する質問（現状の制限）
2. **行105-118**: transform - 失敗通知データ構築
3. **行109**: to: "" - 送信先は空文字列
4. **行110**: channel: "feed" - フィードチャネル
5. **行111**: template: "admin-ui" - テンプレートID
6. **行113**: title: "Product import" - タイトル
7. **行114**: description - ファイル名を含む失敗メッセージ
8. **行120**: notifyOnFailureStep(failureNotification) - ステップ登録

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

notifyOnFailureStepの補償処理を理解。

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

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

#### Step 4: 通知モジュールサービスを理解する

通知の作成・送信ロジックを確認。

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

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

```
[商品インポートAPI]
    │
    └─ importProductsWorkflow
           │
           ├─ normalizeCsvStep
           │
           ├─ waitConfirmationProductImportStep
           │
           ├─ transform (失敗通知データ構築)
           │      │   行105-118
           │      │
           │      └─ 失敗通知データ生成
           │           {to: "", channel: "feed", template: "admin-ui",
           │            data: {title, description}}
           │
           ├─ notifyOnFailureStep.invoke
           │      │   行120
           │      │
           │      └─ StepResponse(void 0, failureNotification)
           │            補償データとして失敗通知データを保存
           │
           ├─ batchProductsWorkflow.runAsStep
           │      │
           │      └─ [失敗時] ワークフロー補償開始
           │
           └─ [補償処理]
                  │
                  └─ notifyOnFailureStep.compensate
                         │   行80-89
                         │
                         ├─ dataがnullならreturn (行81-83)
                         │
                         ├─ container.resolve(Modules.NOTIFICATION)
                         │      行85-87
                         │
                         └─ service.createNotifications(data)
                                行88
```

### データフロー図

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

ImportProductsDTO        ───▶  ワークフロー開始
  │                                   │
  └─ filename ─────────────────▶ transform ──────────────────▶ 失敗通知データ
                                      │                              │
                                      │                              ├─ to: ""
                                      │                              ├─ channel: "feed"
                                      │                              ├─ template: "admin-ui"
                                      │                              └─ data:
                                      │                                   ├─ title: "Product import"
                                      │                                   └─ description:
                                      │                                      "Failed to import
                                      │                                       products from file
                                      │                                       {filename}"
                                      │
                                      ▼
                               notifyOnFailureStep
                                      │
                                      │ mainAction: 補償データとして保存
                                      │
                               [ワークフロー失敗時]
                                      │
                                      ▼
                               notifyOnFailureStep.compensate
                                      │
                                      ▼
                               NotificationModuleService
                                .createNotifications
                                      │
                                      ▼
                               [notification テーブル]
                                      │
                                      ▼
                               [管理画面フィード表示]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| import-products.ts | `packages/core/core-flows/src/product/workflows/import-products.ts` | ソース | 商品インポートワークフロー、失敗通知データ定義 |
| import-products-as-chunks.ts | `packages/core/core-flows/src/product/workflows/import-products-as-chunks.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型定義 |
