# バッチ設計書 18-configurable-notifications-handler

## 概要

本ドキュメントは、Medusaフレームワークにおける設定可能な通知イベント処理サブスクライバー「configurable-notifications-handler」の設計仕様を定義する。

### 本バッチの処理概要

configurable-notifications-handlerは、設定に基づいて各種ビジネスイベント（注文作成など）発生時に通知を送信するイベントサブスクライバーである。イベントとテンプレート、送信チャネル、宛先のマッピングを設定で定義し、対応するイベントが発生した際に自動的に通知を作成・送信する。

**業務上の目的・背景**：Eコマースでは顧客や管理者に対して様々な通知（注文確認、発送通知、在庫アラートなど）を送信する必要がある。これらの通知ロジックをハードコードするのではなく、設定ベースで柔軟に管理できるようにすることで、ビジネス要件の変化に迅速に対応できる。このハンドラは通知の送信を抽象化し、メール、SMS、プッシュ通知などの複数チャネルへの配信を統一的に処理する。

**バッチの実行タイミング**：設定で定義されたイベント（現在はorder.created）が発行されたとき。イベント駆動で自動的に実行される。

**主要な処理内容**：
1. イベント受信と設定済みハンドラの検索
2. イベントペイロードからの動的データ抽出
3. 通知データの構築（テンプレート、チャネル、宛先、データ）
4. Notificationモジュールによる通知作成

**前後の処理との関連**：注文作成ワークフローなど、各種ビジネスワークフローがイベントを発行する前段階がある。後続処理として、Notificationモジュールが実際の通知配信（メール送信など）を行う。

**影響範囲**：notificationテーブル。通知の作成と送信。

## バッチ種別

イベントハンドラ / 通知配信

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（イベント駆動） |
| 実行時刻 | 任意（イベント発生時） |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | 設定されたイベント（order.createdなど） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| Notificationモジュール有効 | 通知モジュールが設定されていること |
| 通知テンプレート存在 | 指定されたテンプレートが存在すること |
| 通知チャネル設定 | 指定されたチャネル（email等）が設定されていること |

### 実行可否判定

1. イベント名に対応するハンドラ設定が存在するか確認
2. 設定が存在しない場合は処理をスキップ（空配列の場合も同様）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| event | SubscriberArgs<any> | Yes | - | イベントデータ |
| container | MedusaContainer | Yes | - | 依存性注入コンテナ |

### HandlerConfig（ハンドラ設定）の構造

| フィールド | 型 | 説明 |
|-----------|-----|------|
| event | string | 対象イベント名 |
| template | string | 使用するテンプレート名 |
| channel | string | 送信チャネル（email等） |
| to | string | 宛先のパス（例: order.email） |
| resource_id | string | リソースIDのパス（例: order.id） |
| data | Record<string, string> | テンプレートに渡すデータのマッピング |

### 現在の設定（order.created）

```typescript
{
  event: "order.created",
  template: "order-created-template",
  channel: "email",
  to: "order.email",
  resource_id: "order.id",
  data: {
    order_id: "order.id",
  },
}
```

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| イベントペイロード | オブジェクト | イベントに含まれるデータ |
| handlerConfig | 配列 | ハードコードされた設定 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| notificationテーブル | DB | 通知レコードの作成 |

### 出力ファイル仕様

ファイル出力はなし。

## 処理フロー

### 処理シーケンス

```
1. イベント受信
   └─ 設定されたイベント（order.created等）を受信
2. ロガー・サービス取得
   └─ logger、notificationServiceをcontainerから取得
3. ハンドラ検索
   └─ configAsMapからイベント名に対応するハンドラを取得
4. ハンドラごとの処理（並列実行）
   └─ promiseAllで全ハンドラを並列処理
5. 通知データ構築
   ├─ template: handler.template
   ├─ channel: handler.channel
   ├─ to: pickValueFromObject(handler.to, payload)
   ├─ trigger_type: handler.event
   ├─ resource_id: pickValueFromObject(handler.resource_id, payload)
   └─ data: 各フィールドをpickValueFromObjectで抽出
6. 通知作成
   └─ notificationService.createNotifications(notificationData)
7. エラーハンドリング
   └─ 個別ハンドラのエラーはログ出力のみ（他のハンドラは続行）
```

### フローチャート

```mermaid
flowchart TD
    A[イベント受信] --> B[logger、notificationService取得]
    B --> C[configAsMapからハンドラ取得]
    C --> D{ハンドラ存在?}
    D -->|No| E[処理終了 早期リターン]
    D -->|Yes| F[promiseAllで並列処理開始]
    F --> G[ハンドラ1の処理]
    F --> H[ハンドラ2の処理]
    F --> I[ハンドラNの処理]
    G --> J[通知データ構築]
    J --> K[pickValueFromObjectでto抽出]
    K --> L[pickValueFromObjectでresource_id抽出]
    L --> M[dataフィールドの動的抽出]
    M --> N[createNotifications呼び出し]
    N --> O{エラー発生?}
    O -->|Yes| P[logger.errorでログ出力]
    O -->|No| Q[処理完了]
    P --> Q
    Q --> R[全ハンドラ完了待ち]
    R --> S[処理終了]
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 通知作成 | notification | INSERT | 通知レコードの作成 |

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

#### notification

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | template | handler.template | テンプレート名 |
| INSERT | channel | handler.channel | 送信チャネル |
| INSERT | to | ペイロードから抽出 | 宛先 |
| INSERT | trigger_type | handler.event | トリガーイベント |
| INSERT | resource_id | ペイロードから抽出 | 関連リソースID |
| INSERT | data | ペイロードから抽出 | テンプレートデータ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | テンプレートエラー | 指定テンプレートが存在しない | テンプレートを作成 |
| - | チャネルエラー | 指定チャネルが設定されていない | チャネルを設定 |
| - | データ抽出エラー | ペイロードに必要なフィールドがない | イベントペイロードを確認 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（エラーはログのみ） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

### 障害時対応

1. エラーログを確認し、失敗箇所を特定
2. テンプレートやチャネルの設定を確認
3. イベントペイロードの構造を確認
4. 必要に応じて手動で通知を再送

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 通知作成単位 |
| コミットタイミング | 通知作成完了時 |
| ロールバック条件 | 通知作成失敗時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | イベント発生数に依存 |
| 目標処理時間 | 数秒以内 |
| メモリ使用量上限 | Node.jsデフォルト制限 |

## 排他制御

特別な排他制御はなし。各通知は独立して作成される。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| エラーログ | 通知作成失敗時 | Failed to send notification for {event.name} + エラーメッセージ |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 通知作成エラー | 設定による | 標準エラー出力 |

## 備考

- サブスクライバーID: configurable-notifications-handler
- 対象イベント: handlerConfigで定義されたイベント（現在はorder.created）
- TODOコメントによると、将来的には設定をmedusa-config.jsから動的に読み込む予定
- TODOコメントによると、より強力なテンプレート構文（フィールドの結合など）も検討されている
- pickValueFromObjectはドット区切りのパス（例: order.email）でオブジェクトから値を抽出する
- 個別ハンドラのエラーは他のハンドラの処理に影響しない（catchしてログ出力のみ）
- promiseAllで並列処理されるため、複数のハンドラが設定されていても効率的に処理される

### 設定拡張の例（将来対応）

```typescript
// medusa-config.jsでの設定例（将来対応予定）
{
  notifications: [
    {
      event: "order.created",
      template: "order-created",
      channel: "email",
      to: "order.customer.email",
      data: {
        order_number: "order.display_id",
        total: "order.total",
      },
    },
    {
      event: "order.shipped",
      template: "order-shipped",
      channel: "sms",
      to: "order.customer.phone",
      data: {
        tracking_number: "fulfillment.tracking_number",
      },
    },
  ],
}
```
