# 画面設計書 249-スパムログ一覧

## 概要

本ドキュメントは、GitLab管理者がスパム判定されたコンテンツのログを一覧表示し管理する画面の設計書です。

### 本画面の処理概要

スパムログ一覧画面は、GitLabのスパム検出システム（Akismet等）によってスパムと判定されたコンテンツのログを一覧表示し、管理者が確認・対応を行うための画面です。

**業務上の目的・背景**：GitLabはスパム対策としてAkismetなどの外部サービスと連携し、ユーザーが作成するIssue、コメントなどのコンテンツをスパム判定しています。スパムと判定されたコンテンツはこの画面でログとして記録され、管理者は誤検知（false positive）を確認してハム（非スパム）として報告したり、悪意のあるユーザーをブロック・削除したりできます。

**画面へのアクセス方法**：
1. 管理者としてGitLabにログイン
2. 左サイドメニューから「Admin Area」をクリック
3. 「Spam logs」をクリック

**主要な操作・処理内容**：
1. スパムログの一覧表示
2. ログのハム（非スパム）としての報告
3. ユーザーのブロック
4. ユーザーへの信頼付与
5. ログの削除
6. ユーザーの削除

**画面遷移**：
- 遷移元：管理者ダッシュボード
- 遷移先：ユーザー詳細画面（リンク経由）

**権限による表示制御**：管理者権限を持つユーザーのみがこの画面にアクセス可能です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 139 | 監査イベント | 主機能 | スパムログ一覧表示・管理 |

## 画面種別

一覧

## URL/ルーティング

- URL: `/admin/spam_logs`
- HTTP メソッド: GET
- ルート名: `admin_spam_logs`

## 入出力項目

本画面は一覧表示のため、入力項目はページネーションのみです。

| 項目名 | 項目ID | 型 | 必須 | 備考 |
|--------|--------|-----|------|------|
| ページ | page | Integer | - | ページ番号 |

## 表示項目

| 項目名 | 表示形式 | 備考 |
|--------|----------|------|
| ページタイトル | テキスト | "Spam logs" |
| Date | 日時 | 作成日時（time_ago_with_tooltip） |
| User | リンク | ユーザー名、登録日、ソースIP |
| Type | テキスト | noteable_type（Issue等） |
| Details | テキスト | タイトルと説明（truncate） |
| Actions | ドロップダウン | 各種アクション |

### 一覧テーブル

| カラム名 | 説明 |
|---------|------|
| Date | スパム検出日時 |
| User | 対象ユーザー情報（名前、登録日、ソースIP、モデレーションステータス、APIフラグ、reCAPTCHAフラグ） |
| Type | スパム検出対象の種類 |
| Details | スパムコンテンツのタイトル・説明 |
| Actions | ハム報告、ブロック、信頼付与、ログ削除、ユーザー削除 |

## イベント仕様

### 1-ハムとして報告（Submit as ham）

**トリガー**: アクションメニューから「Submit as ham」選択

**処理フロー**:
1. POSTリクエスト送信（`/admin/spam_logs/:id/mark_as_ham`）
2. `Admin::SpamLogsController#mark_as_ham`呼び出し
3. `Spam::HamService.new(spam_log).execute`
4. Akismet APIにハム報告
5. submitted_as_hamフラグ更新
6. 成功/失敗メッセージ表示

### 2-ユーザーブロック

**トリガー**: アクションメニューから「Block user」選択

**処理フロー**:
1. 確認ダイアログ
2. PUTリクエスト送信（`/admin/users/:id/block`）
3. ユーザーブロック
4. 画面更新

### 3-ユーザー信頼付与

**トリガー**: アクションメニューから「Trust user」選択

**処理フロー**:
1. 確認ダイアログ
2. PUTリクエスト送信（`/admin/users/:id/trust`）
3. ユーザー信頼付与
4. 画面更新

### 4-ログ削除

**トリガー**: アクションメニューから「Remove log」選択

**処理フロー**:
1. DELETEリクエスト送信（Ajax）
2. `Admin::SpamLogsController#destroy`呼び出し
3. ログ削除
4. テーブル行削除（JS）

### 5-ユーザー削除

**トリガー**: アクションメニューから「Remove user」選択

**処理フロー**:
1. 確認ダイアログ
2. DELETEリクエスト送信
3. `spam_log.remove_user`呼び出し
4. ユーザー非同期削除
5. 一覧画面へリダイレクト

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| Submit as ham | spam_logs | UPDATE | submitted_as_ham更新 |
| Block user | users | UPDATE | state更新 |
| Trust user | users | UPDATE | 信頼フラグ更新 |
| Remove log | spam_logs | DELETE | ログ削除 |
| Remove user | users | DELETE | ユーザー削除 |

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

#### spam_logs

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | submitted_as_ham | true | ハム報告成功時 |
| DELETE | - | id = 指定ID | ログ削除時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG001 | 成功 | Spam log successfully submitted as ham. | ハム報告成功時 |
| MSG002 | エラー | Error with Akismet. Please check the logs for more info. | Akismetエラー時 |
| MSG003 | 成功 | User {username} was successfully removed. | ユーザー削除成功時 |
| MSG004 | 空状態 | There are no spam logs | ログが0件の場合 |
| MSG005 | 確認 | User will be blocked! Are you sure? | ブロック確認時 |
| MSG006 | 確認 | User {user_name} will be removed! Are you sure? | 削除確認時 |

## 例外処理

| 例外条件 | 処理内容 | 表示メッセージ |
|----------|----------|---------------|
| 権限不足 | 403エラー画面へリダイレクト | アクセスが拒否されました |
| Akismetエラー | フラッシュメッセージ表示 | Akismetエラーメッセージ |

## 備考

- Akismetが有効な場合のみ「Submit as ham」オプションが表示される
- ユーザーがすでにブロック済みの場合は「Already blocked」と表示
- ユーザーがすでに信頼済みの場合は「Untrust user」オプションが表示
- reCAPTCHA検証済みの場合はバッジ表示
- API経由のスパムの場合はバッジ表示
- ログ削除はAjaxで行われ、ページリロードなしでテーブル行が削除される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | spam_log.rb | `app/models/spam_log.rb` | SpamLogモデル定義 |

**読解のコツ**:
- `remove_user`メソッドでユーザー削除処理確認
- `text`メソッドでタイトル・説明の結合
- `verify_recaptcha!`クラスメソッド

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | spam_logs_controller.rb | `app/controllers/admin/spam_logs_controller.rb` | index/destroy/mark_as_hamアクション |

**主要処理フロー**:
1. **7-11行目**: `index`アクション - SpamLogをpreloadして取得
2. **14-26行目**: `destroy`アクション - ログ削除またはユーザー削除
3. **28-36行目**: `mark_as_ham`アクション - HamService呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ham_service.rb | `app/services/spam/ham_service.rb` | ハム報告ロジック |

**主要処理フロー**:
- **18-23行目**: `execute`メソッド - Akismet API呼び出し、フラグ更新

#### Step 4: ビュー層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.html.haml | `app/views/admin/spam_logs/index.html.haml` | 一覧画面レイアウト |
| 4-2 | _spam_log.html.haml | `app/views/admin/spam_logs/_spam_log.html.haml` | 各行のレンダリング |

**主要処理フロー**:
- **16行目**: `render @spam_logs`でパーシャル呼び出し
- パーシャルでアクションドロップダウン生成

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

```
ブラウザ (GET /admin/spam_logs)
    │
    └─ Admin::SpamLogsController#index
           ├─ SpamLog.preload(user: [:trusted_with_spam_attribute])
           │      └─ order(id: :desc)
           │      └─ page(pagination_params[:page])
           │
           └─ View: admin/spam_logs/index.html.haml
                  └─ render @spam_logs (パーシャル)

ブラウザ (POST /admin/spam_logs/:id/mark_as_ham)
    │
    └─ Admin::SpamLogsController#mark_as_ham
           └─ Spam::HamService.new(spam_log).execute
                  └─ akismet.submit_ham
                  └─ spam_log.update_attribute(:submitted_as_ham, true)
```

### データフロー図

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

ページパラメータ ────▶ SpamLogsController#index ──────▶ 一覧HTML
                              │
                              ├─ SpamLog.preload
                              └─ Pagination

Submit as ham ────────▶ SpamLogsController#mark_as_ham ▶ 一覧画面
                              │                            (フラッシュ)
                              └─ Spam::HamService
                                     └─ Akismet API
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| spam_logs_controller.rb | `app/controllers/admin/spam_logs_controller.rb` | コントローラ | リクエスト処理 |
| spam_log.rb | `app/models/spam_log.rb` | モデル | データ定義 |
| ham_service.rb | `app/services/spam/ham_service.rb` | サービス | ハム報告 |
| index.html.haml | `app/views/admin/spam_logs/index.html.haml` | ビュー | 一覧画面 |
| _spam_log.html.haml | `app/views/admin/spam_logs/_spam_log.html.haml` | パーシャル | 各行表示 |
| admin.rb | `config/routes/admin.rb` | 設定 | ルーティング |
