# 画面設計書 47-スパムフィルター設定

## 概要

本ドキュメントは、Ghost管理画面の「スパムフィルター設定」画面の設計仕様を定義する。この画面は迷惑メールドメインをブロックすることで、スパム登録を防止する機能を提供する。

### 本画面の処理概要

この画面では、メンバー登録時にスパムとして認識したいメールドメインをブロックリストに追加できる。指定されたドメインからのメールアドレスでは登録ができなくなる。

**業務上の目的・背景**：オープンなメンバーシップサイトでは、スパムボットや悪意のあるユーザーからの不正登録が問題になることがある。特定のドメインを事前にブロックすることで、サイト運営者の管理負担を軽減し、健全なコミュニティを維持することができる。

**画面へのアクセス方法**：管理画面のサイドバーから「Settings」→「Membership」セクション→「Spam filters」カードにアクセスする。URLは`/ghost/#/settings`でnavid: `spam-filters`となる。

**主要な操作・処理内容**：
1. ブロックするメールドメインの入力
2. 1行につき1ドメインを入力（改行区切り）
3. 不正なフォーマットの自動除外
4. 設定の保存

**画面遷移**：設定画面のMembershipセクションに直接表示される。編集後は「Save」ボタンで保存、「Cancel」で変更を破棄できる。

**権限による表示制御**：Administrator以上のロールを持つユーザーのみがスパムフィルター設定にアクセスできる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 35 | 一般設定 | 主機能 | スパム防止フィルターの設定 |

## 画面種別

設定画面（インライン編集型）

## URL/ルーティング

- 画面URL: `/ghost/#/settings` (navid: `spam-filters`)

## 入出力項目

| 項目名 | 種別 | データ型 | 必須 | 説明 |
|--------|------|---------|------|------|
| Blocked email domains | 入力 | string (multiline) | - | ブロックするメールドメイン（改行区切り） |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| TextArea | string | ブロックドメイン入力エリア |

## イベント仕様

### 1-ドメイン入力

TextAreaにドメインを入力すると：

1. 入力値をスペース、カンマ、改行で分割
2. 各ドメインを正規化（小文字化、@以降のドメイン部分のみ抽出）
3. ドットを含まないドメインを除外
4. `blocked_email_domains`設定をJSON配列形式で更新
5. 編集モードを開始

### 2-保存

「Save」ボタンをクリックすると：

1. `handleSave`で設定をAPIに送信
2. 成功時は編集モードを終了

### 3-キャンセル

「Cancel」ボタンをクリックすると：

1. `handleCancel`で変更を破棄
2. 設定を元の値に戻す

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| スパムフィルター保存 | settings | UPDATE | blocked_email_domains更新 |

### テーブル別更新項目詳細

#### settings

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | key='blocked_email_domains' | JSON配列 | ブロックドメインリスト |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|-----------|----------|
| ヒント | Prevent unwanted signups by blocking email domains. Add one domain per line, e.g., spam.xyz to block signups from email addresses like hello@spam.xyz. | 常時表示 |

## 例外処理

| 状態 | 処理内容 |
|------|----------|
| 無効なドメイン | 自動的に除外（ドットを含まないものなど） |
| 保存エラー | エラートーストを表示 |

## 備考

- ドメインの入力方法は柔軟で、スペース・カンマ・改行のいずれでも区切れる
- 完全なメールアドレスを入力しても、@以降のドメイン部分のみが使用される
- ドット（.）を含まない文字列は有効なドメインとして認識されない
- JSON配列形式で内部保存される（例：`["spam.xyz", "junk.com"]`）
- 編集ボタンは非表示（hideEditButton=true）で、直接編集モードで操作

---

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

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

### 推奨読解順序

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

まず、スパムフィルター設定に関連する設定値を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | spam-filters.tsx | `apps/admin-x-settings/src/components/settings/advanced/spam-filters.tsx` | 設定値の取得と初期化（24-26行目） |

**読解のコツ**: `blocked_email_domains`はJSON文字列として保存され、表示時は改行区切りのテキストに変換される。

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

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | spam-filters.tsx | `apps/admin-x-settings/src/components/settings/advanced/spam-filters.tsx` | SpamFiltersコンポーネントの構造（7-82行目） |

**主要処理フロー**:
1. **8-22行目**: `useSettingGroup`でローカル設定を管理
2. **24-26行目**: 現在のブロックドメインをJSONからパースしテキスト化
3. **28-42行目**: `updateBlockedEmailDomainsSetting`で入力処理と正規化

#### Step 3: 入力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | spam-filters.tsx | `apps/admin-x-settings/src/components/settings/advanced/spam-filters.tsx` | ドメイン正規化ロジック（28-42行目） |

**主要処理フロー**:
- **30行目**: 入力値の取得
- **31行目**: ローカルステートの更新（表示用）
- **33-35行目**: 入力値の正規化
  - スペース/カンマ/改行で分割
  - trim()で空白除去
  - 小文字化
  - @以降のドメイン部分のみ抽出
  - ドットを含むものだけフィルタ
- **37行目**: JSON配列として設定を更新

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

```
SpamFilters (spam-filters.tsx)
    │
    ├─ useSettingGroup()
    │      ├─ localSettings
    │      │      └─ blocked_email_domains (JSON string)
    │      │
    │      ├─ updateSetting(key, value)
    │      ├─ handleSave()
    │      │      └─ PUT /settings/
    │      ├─ handleCancel()
    │      └─ handleEditingChange()
    │
    ├─ useState(blockedEmailDomains)
    │      └─ 表示用テキスト（改行区切り）
    │
    └─ Form UI
           └─ TextArea
                  └─ onChange: updateBlockedEmailDomainsSetting()
                         │
                         ├─ 入力値の分割・正規化
                         └─ JSON.stringify() → updateSetting()
```

### データフロー図

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

                    ┌─────────────────┐
Settings DB ────────┤JSON.parse()     │
(JSON string)       │                 │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │join('\n')       │───────► TextArea表示
                    │(改行区切りテキスト)│
                    └─────────────────┘

                    ┌─────────────────┐
ユーザー入力 ───────┤split(/[\s,]+/)  │
(テキスト)         │                  │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │正規化処理        │
                    │- trim()         │
                    │- toLowerCase()  │
                    │- split('@').pop()│
                    │- filter(.)      │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
handleSave() ───────┤JSON.stringify() │
                    │updateSetting()  │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │PUT /settings/   │───────► Settings DB
                    └─────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| spam-filters.tsx | `apps/admin-x-settings/src/components/settings/advanced/spam-filters.tsx` | ソース | メイン設定コンポーネント |
| settings.ts | `apps/admin-x-framework/src/api/settings.ts` | ソース | 設定API定義 |
| use-setting-group.ts | `apps/admin-x-settings/src/hooks/use-setting-group.ts` | ソース | 設定グループ管理フック |
| top-level-group.tsx | `apps/admin-x-settings/src/components/top-level-group.tsx` | ソース | 設定グループUIコンポーネント |
