# バッチ設計書 8-mentions-email-report

## 概要

本ドキュメントは、Ghostプラットフォームにおける Webmention通知メールバッチ「mentions-email-report」の設計仕様を記載したものです。このバッチは、新しいWebmentionがあった場合に管理者へメールで通知レポートを送信する役割を担います。

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

**業務上の目的・背景**：Webmentionは、他のサイトからの言及（リンク、引用など）を通知する仕組みです。サイト運営者は自分のコンテンツがどこで言及されているかを把握したいというニーズがあります。このバッチは、過去24時間以内に受け取ったWebmentionをまとめて、管理者にメールレポートとして送信することで、他サイトからの言及を効率的に把握できるようにします。

**バッチの実行タイミング**：1時間ごとにランダムな分・秒で実行されます。ただし、前回のレポート送信から24時間以上経過している場合のみレポートを送信します。

**主要な処理内容**：
1. 前回レポート送信日時（last_mentions_report_email_timestamp）を取得
2. 前回送信から24時間以上経過しているかチェック
3. 経過している場合、その期間のWebmentionレポートを生成
4. mention-received通知を有効にしているユーザーにメールを送信
5. 送信日時を更新

**前後の処理との関連**：Webmention受信処理でmentionsテーブルにデータが蓄積されます。このバッチがそれを集約してレポートメールを送信します。

**影響範囲**：settings（last_mentions_report_email_timestamp）が更新されます。管理者へのメール通知に影響します。

## バッチ種別

通知配信 / レポート生成

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 1時間ごと |
| 実行時刻 | ランダムな分・秒（`${s} ${m} * * * *`） |
| 実行曜日 | 毎日 |
| 実行日 | 毎日 |
| トリガー | cron + 起動時イベント |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| Webmention機能 | labs.isSet('webmentions')がtrueであること |
| 初期化完了 | サービスが初期化されていること |
| 24時間経過 | 前回レポート送信から24時間以上経過していること |

### 実行可否判定

- labs.isSet('webmentions')がtrueの場合のみ処理
- 前回送信から24時間未満の場合は0を返して終了
- Webmentionが0件の場合は0を返して終了

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | パラメータなし |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| settings テーブル | DB | last_mentions_report_email_timestamp |
| mentions API | API | Webmentionレポートデータ |
| users テーブル | DB | mention-received通知有効ユーザー |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| メール | SMTP | Webmentionレポートメール |
| settings テーブル | DB | last_mentions_report_email_timestamp更新 |

### 出力ファイル仕様

ファイル出力なし

## 処理フロー

### 処理シーケンス

```
1. sendLatestReport()開始
   └─ getLatestReportDate()で前回送信日時を取得

2. 24時間経過チェック
   └─ 現在時刻 - 前回送信 < 24時間 の場合は0を返して終了

3. レポート生成
   └─ getMentionReport(lastReport, now)でレポート取得
   └─ mentionsデータを正規化（targetUrl, sourceUrl等）

4. Mention有無チェック
   └─ mentions.length === 0 の場合は0を返して終了

5. 受信者取得
   └─ getMentionReportRecipients()でユーザー取得
   └─ User.getEmailAlertUsers('mention-received')

6. メール送信
   └─ 各受信者に対して:
   └─ renderSubject(): サブジェクト生成
   └─ renderHTML(): HTML本文生成
   └─ renderText(): テキスト本文生成
   └─ emailService.send()でメール送信

7. 送信日時更新
   └─ setLatestReportDate(now)で設定を更新

8. 結果返却
   └─ mentions.lengthを返す
```

### フローチャート

```mermaid
flowchart TD
    A[sendLatestReport開始] --> B[前回送信日時取得]
    B --> C{24時間経過?}
    C -->|No| D[0を返して終了]
    C -->|Yes| E[レポート生成]
    E --> F{Mention件数 > 0?}
    F -->|No| D
    F -->|Yes| G[受信者取得]
    G --> H[各受信者にメール送信]
    H --> I[送信日時更新]
    I --> J[件数を返して終了]
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 前回送信日時取得 | settings | SELECT | last_mentions_report_email_timestamp |
| 受信者取得 | users | SELECT | mention-received通知有効ユーザー |
| 送信日時更新 | settings | UPDATE | last_mentions_report_email_timestamp |

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

#### settings

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | value | key = 'last_mentions_report_email_timestamp' | settingsCacheから取得 |
| UPDATE | value | 現在時刻のgetTime() | Settings.edit() |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 設定値不正 | 不正なタイムスタンプ | 24時間前をデフォルト値として使用 |
| - | メール送信エラー | SMTP送信失敗 | ログ出力（処理続行） |

### リトライ仕様

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

### 障害時対応

- 設定値が不正な場合は24時間前をデフォルト値として処理続行
- メール送信エラーは次回実行時に再度レポート生成

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 設定更新のみ |
| コミットタイミング | Settings.edit()完了時 |
| ロールバック条件 | 更新失敗時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | Webmention件数に依存 |
| 目標処理時間 | 数秒〜数十秒 |
| メモリ使用量上限 | 特になし |

## 排他制御

- initialised フラグで重複初期化を防止
- 24時間間隔による自然な排他

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| なし（明示的ログなし） | - | - |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| なし | - | - |

## 備考

- labs.isSet('webmentions')がtrueの場合のみ動作（実験的機能フラグ）
- 起動時にStartMentionEmailReportJobイベントを発火してレポート漏れを防止
- メールサブジェクトは言及元サイト数に応じて動的生成:
  - 1サイト: "${サイト名} mentioned you"
  - 2サイト: "${サイト名} & 1 other mentioned you"
  - 3サイト以上: "${サイト名} & ${n-1} others mentioned you"
- 重複するsourceUrlのmentionはフィルタリング
- HTMLとテキストの両形式でメール送信
- mention-received通知設定が有効なユーザーのみに送信
