# 通知設計書 8-新規コメント通知

## 概要

本ドキュメントは、Ghost CMSにおける新規コメント通知（New Comment Notification）の設計仕様を記載する。投稿に新しいコメントが追加された際に投稿の執筆者に送信される通知メールの送信ロジック、テンプレート構造、およびデータフローを定義する。

### 本通知の処理概要

本通知は、サイト訪問者（会員）が投稿にコメントを残した際に、その投稿の執筆者（著者）に対してメール通知を送信する機能である。

**業務上の目的・背景**：コンテンツ執筆者が読者からのフィードバックを迅速に把握できるようにする。コメントへの返信や、コンテンツ改善のきっかけとなるエンゲージメント向上を目的とする。

**通知の送信タイミング**：会員がコメントを投稿した直後、CommentCreatedEventがトリガーされた時点で送信される。

**通知の受信者**：投稿に紐づく全著者のうち、comment_notifications設定がtrueの著者に送信される。複数著者がいる場合は、それぞれに個別にメールが送信される。

**通知内容の概要**：メールにはコメント投稿者の名前、投稿タイトル、コメント内容（HTML）、コメントへのリンクが含まれる。

**期待されるアクション**：受信者は「View comments」ボタンをクリックして投稿ページのコメントセクションを確認し、必要に応じて返信する。

## 通知種別

メール通知（イベント駆動型通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（イベント駆動） |
| 優先度 | 中 |
| リトライ | 無 |

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

1. コメントが投稿された投稿（Post）を取得
2. 投稿に紐づく全著者（authors）を取得
3. 各著者のcomment_notifications設定を確認
4. trueの場合のみ、その著者のメールアドレスに送信

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | settingsHelpers.getMembersSupportAddress() |
| 送信元名称 | サイトタイトル |
| 件名 | `New comment on your post: {postTitle}` |
| 形式 | HTML + テキスト（マルチパート） |

### 本文テンプレート

```
件名: New comment on your post: {postTitle}

本文:
Hey there,

Someone just left a comment on your post {postTitle}.

[コメント投稿者アバター（イニシャル）]
{memberName}
{memberExpertise} - {commentDate}

{commentHtml}

[View comments ボタン]

---
You can also copy & paste this URL into your browser:
{postUrl}

---
This message was sent from {siteDomain} to {toEmail}
Manage your email preferences
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| siteTitle | サイト名 | settingsCache.get('title') | Yes |
| siteUrl | サイトURL | urlUtils.getSiteUrl() | Yes |
| siteDomain | サイトドメイン | urlUtils.getSiteUrl()から抽出 | Yes |
| postTitle | 投稿タイトル | post.get('title') | Yes |
| postUrl | コメント付き投稿URL | urlService.getUrlByResourceId() + '#ghost-comments-{commentId}' | Yes |
| commentHtml | コメント本文HTML | comment.get('html') | Yes |
| commentDate | コメント投稿日 | moment(comment.get('created_at')).format('D MMM YYYY') | Yes |
| memberName | コメント投稿者名 | member.get('name') または 'Anonymous' | Yes |
| memberExpertise | コメント投稿者の専門分野 | member.get('expertise') | No |
| memberInitials | コメント投稿者のイニシャル | extractInitials(memberName) | Yes |
| accentColor | サイトのアクセントカラー | settingsCache.get('accent_color') | No |
| fromEmail | 送信元アドレス | settingsHelpers.getMembersSupportAddress() | Yes |
| toEmail | 送信先アドレス | author.get('email') | Yes |
| staffUrl | スタッフ設定URL | /settings/staff/{slug}/email-notifications | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| イベント | CommentCreatedEvent | author.comment_notifications = true | 新規コメント投稿 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 通知設定OFF | 著者のcomment_notifications設定がfalse |
| 投稿なし | コメントに紐づく投稿が見つからない |
| 著者なし | 投稿に著者が設定されていない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[CommentCreatedEvent発火] --> B[投稿情報取得]
    B --> C[コメント投稿者情報取得]
    C --> D[投稿の全著者をループ]
    D --> E{comment_notifications有効?}
    E -->|No| F[スキップ、次の著者へ]
    E -->|Yes| G[テンプレートデータ構築]
    G --> H[new-comment.hbsレンダリング]
    H --> I[メール送信]
    I --> F
    F --> D
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| posts | 投稿情報取得 | withRelated: ['authors'] |
| members | コメント投稿者情報取得 | idで検索 |
| users | 著者情報取得 | postsのauthorsリレーション経由 |
| settings | サイト設定取得 | settingsCacheから取得 |
| comments | コメント情報 | イベントから取得 |

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

#### posts

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | 投稿識別 | comment.post_id |
| title | 投稿タイトル | - |

#### users（著者）

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| email | 送信先アドレス | - |
| comment_notifications | 通知有効/無効 | trueの場合のみ送信 |
| slug | スタッフ設定URL生成 | - |

#### members

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| name | コメント投稿者名 | - |
| expertise | 専門分野表示 | - |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | 送信ログ等への書き込みは行われない |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| PostNotFoundError | 投稿が見つからない | ログ出力、処理スキップ |
| MemberNotFoundError | コメント投稿者が見つからない | ログ出力、処理スキップ |
| MailError | メール送信失敗 | ログ出力（リトライなし） |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 設定なし |
| 1日あたり上限 | 設定なし |

### 配信時間帯

特定の配信時間帯制限はない。コメント投稿直後に即座に送信。

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

- コメント本文HTML（commentHtml）は三重中括弧 `{{{commentHtml}}}` でエスケープせずに出力（Handlebarsの仕様）
- コメント投稿者の個人情報（名前、専門分野）がメールに含まれる
- 著者のメールアドレスは投稿者には開示されない
- スタッフ設定URLは管理画面へのリンク（認証必要）

## 備考

- commentPermalinks labsフラグがONの場合、URLフラグメントが `#ghost-comments-{commentId}` になる（個別コメントへの直接リンク）
- labsフラグがOFFの場合は `#ghost-comments-root` となる
- 本番環境以外ではコメント本文がログに出力される（デバッグ用）
- i18n対応なし（固定英語テンプレート）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | new-comment.hbs | `ghost/core/core/server/services/comments/email-templates/new-comment.hbs` | テンプレート構造、変数名 |
| 1-2 | comments-service-emails.js | `ghost/core/core/server/services/comments/comments-service-emails.js` | templateData構築（行49-63） |

**読解のコツ**: new-comment.hbsはHandlebarsテンプレートで、変数は `{{変数名}}`、HTMLエスケープなしは `{{{変数名}}}` で展開される。

#### Step 2: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | comments-service-emails.js | `ghost/core/core/server/services/comments/comments-service-emails.js` | CommentsServiceEmailsクラス全体 |

**主要処理フロー**:
- **35-78行目**: notifyPostAuthors() - メイン送信処理
- **27-33行目**: getPostUrl() - コメントパーマリンク生成
- **39-42行目**: 著者ループとcomment_notificationsチェック
- **214-225行目**: sendMail() - 実際のメール送信

#### Step 3: レンダリング処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | comments-service-email-renderer.js | `ghost/core/core/server/services/comments/comments-service-email-renderer.js` | Handlebarsレンダリング |

**主要処理フロー**:
- **24-33行目**: renderEmailTemplate() - テンプレートレンダリング
- **8-17行目**: Handlebars 't' ヘルパー（i18n対応）
- **18-21行目**: Handlebars 'concat' ヘルパー

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

```
CommentCreatedEvent (Domain Event)
    |
    └─ Event Handler（イベント購読側）
           |
           └─ CommentsServiceEmails.notifyPostAuthors(comment)
                  |
                  ├─ models.Post.findOne({withRelated: ['authors']})
                  |
                  ├─ models.Member.findOne({id: comment.member_id})
                  |
                  ├─ for (author of post.authors)
                  |      |
                  |      ├─ author.comment_notifications チェック
                  |      |
                  |      ├─ getPostUrl(postId, commentId)
                  |      |      |
                  |      |      └─ urlService.getUrlByResourceId()
                  |      |
                  |      ├─ extractInitials(memberName)
                  |      |
                  |      ├─ CommentsServiceEmailRenderer.renderEmailTemplate('new-comment', data)
                  |      |      |
                  |      |      ├─ Handlebars.compile() - HTML生成
                  |      |      |
                  |      |      └─ new-comment.txt.js - テキスト生成
                  |      |
                  |      └─ sendMail({to, subject, html, text})
                  |             |
                  |             └─ mailer.send()
```

### データフロー図

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

CommentCreatedEvent ────▶ CommentsServiceEmails
  - comment                    |
                               ▼
postsテーブル ◀────────── 投稿情報取得
  - title                      |
  - authors                    ▼
                         著者ループ
                               |
usersテーブル ◀────────── 通知設定確認
  - comment_notifications      |
  - email                      ▼
                         templateData構築
                               |
membersテーブル ───────▶       |
  - name                       ▼
  - expertise            Handlebarsレンダリング
                               |
settingsテーブル ─────▶       |
  - title                      ▼
  - accent_color         メール送信 ─────────▶ 著者のメールボックス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| comments-service-emails.js | `ghost/core/core/server/services/comments/comments-service-emails.js` | サービス | メイン処理ロジック |
| comments-service-email-renderer.js | `ghost/core/core/server/services/comments/comments-service-email-renderer.js` | レンダラー | Handlebarsレンダリング |
| new-comment.hbs | `ghost/core/core/server/services/comments/email-templates/new-comment.hbs` | テンプレート | メールHTMLテンプレート |
| new-comment.txt.js | `ghost/core/core/server/services/comments/email-templates/new-comment.txt.js` | テンプレート | メールテキストテンプレート |
