# 画面設計書 240-トピック一覧

## 概要

本ドキュメントは、GitLabの管理者向けトピック一覧画面の設計仕様を定義する。

### 本画面の処理概要

この画面では、管理者がシステム内のすべてのプロジェクトトピックを一覧表示し、検索・管理操作（作成、編集、削除、マージ）を行うことができる。

**業務上の目的・背景**：プロジェクトトピックはプロジェクトの分類・発見を容易にするためのタグ付け機能である。システム管理者がインスタンス内のトピックを整理・管理するための画面であり、重複トピックのマージ、不適切なトピックの削除、トピック情報の編集などを行う。トピックを適切に管理することで、ユーザーが関心のあるプロジェクトを発見しやすくなる。

**画面へのアクセス方法**：管理者エリア > 概要 > トピック、またはURL `/admin/topics` に直接アクセス。サイドナビゲーションの「Admin Area」→「Overview」→「Topics」からもアクセス可能。

**主要な操作・処理内容**：
1. トピックの一覧表示（名前、タイトル、説明、プロジェクト数）
2. トピック名による検索
3. 新規トピックの作成画面への遷移
4. 個別トピックの編集画面への遷移
5. トピックの削除
6. トピックのマージ（複数のトピックを1つに統合）

**画面遷移**：
- 遷移元：管理者ダッシュボード、サイドナビゲーション
- 遷移先：トピック新規作成画面、トピック編集画面、探索画面（トピックリンク）

**権限による表示制御**：管理者権限を持つユーザーのみがアクセス可能。すべての管理操作（作成、編集、削除、マージ）が可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 102 | グローバル検索 | 主機能 | トピック管理一覧の表示 |

## 画面種別

一覧

## URL/ルーティング

- URL: `/admin/topics`
- ルート名: `admin_topics_path`
- HTTPメソッド: GET
- コントローラ: `Admin::TopicsController#index`

## 入出力項目

| 項目名 | 種別 | 必須 | 説明 |
|--------|------|------|------|
| search | クエリパラメータ | 任意 | トピック名の検索文字列 |
| page | クエリパラメータ | 任意 | ページ番号 |

## 表示項目

### トピック一覧

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| アバター | Image | トピックのアバター画像 |
| タイトル/名前 | String | トピックのタイトルまたは名前（リンク） |
| 説明 | Text | トピックの説明文（最初の200文字、Markdown対応） |
| プロジェクト数 | Integer | このトピックを使用しているプロジェクトの数 |
| 編集ボタン | Button | 編集画面への遷移 |
| 削除ボタン | Button | トピックの削除 |

### 検索フォーム

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| 検索テキスト | String | トピック名での検索 |

## イベント仕様

### 1-新規トピック作成

「New topic」ボタンをクリックすると、トピック新規作成画面（`/admin/topics/new`）に遷移する。

### 2-トピック検索

検索フォームに文字列を入力してEnterまたは検索を実行すると、トピック名に一致するトピックのみが表示される。

### 3-トピック編集

編集アイコンをクリックすると、そのトピックの編集画面（`/admin/topics/:id/edit`）に遷移する。

### 4-トピック削除

削除アイコンをクリックすると確認ダイアログが表示され、確認後にトピックが削除される。

1. 削除アイコンをクリック
2. 確認ダイアログ「Are you sure you want to remove {topic_name}?」が表示
3. 確認後、`Admin::TopicsController#destroy`が呼び出される
4. 成功時：一覧画面を再表示し、成功メッセージを表示

### 5-トピックマージ

トピックマージ機能で、複数のトピックを1つのトピックに統合できる。

1. マージUIで元トピックと先トピックを選択
2. マージを実行
3. `Topics::MergeService`でマージ処理を実行
4. 成功時：一覧画面にリダイレクトし、成功メッセージを表示
5. 失敗時：エラーメッセージを返す

### 6-ページネーション

ページネーションコントロールで次ページ/前ページに移動可能。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | topics | SELECT | トピック一覧の取得 |
| トピック削除 | topics | DELETE | トピックの削除 |
| トピック削除 | project_topics | DELETE | 関連付けの削除 |
| トピックマージ | topics | DELETE | 元トピックの削除 |
| トピックマージ | project_topics | UPDATE | 関連付けの移行 |

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

#### topics

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, title, description, avatar, total_projects_count | 検索条件、organization_id | |
| DELETE | - | id で特定 | |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| MSG001 | 成功 | Topic {topic_name} was successfully removed. | 削除成功時 |
| MSG002 | 成功 | Topic {source_topic} was successfully merged into topic {target_topic}. | マージ成功時 |
| MSG003 | エラー | {マージエラーメッセージ} | マージ失敗時 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| 管理者権限がない | 403アクセス拒否画面を表示 |
| トピックが存在しない | 404エラー（削除操作時） |
| マージ失敗 | 400エラーとエラーメッセージを返す |

## 備考

- トピックが0件で検索もされていない場合、空のステート画面が表示される
- 検索結果が0件の場合、検索結果が空の旨のメッセージが表示される
- トピック名のリンクは探索画面のトピック検索結果にリンクする
- トピックの説明はMarkdown形式で、最初の行のみが表示される（最大200文字）
- イベントトラッキング（`event_tracking: 'view_admin_topics_pageload'`）が設定されている
- トピックは現在の組織（`Current.organization`）に関連付けられている

---

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

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

### 推奨読解順序

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

トピックモデルの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | topic.rb | `app/models/projects/topic.rb` | トピックモデルの属性とスコープ |

**読解のコツ**: total_projects_countの計算方法とorganization_idの関係に注目。

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

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

**主要処理フロー**:
1. **11-15行目**: indexアクション - TopicsFinderでトピック取得、ページネーション
2. **43-49行目**: destroyアクション - トピックの削除
3. **51-61行目**: mergeアクション - Topics::MergeServiceでマージ
4. **65-67行目**: topicメソッド - organization_idでトピック検索

#### Step 3: ビューテンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.html.haml | `app/views/admin/topics/index.html.haml` | メインビュー |
| 3-2 | _topic.html.haml | `app/views/admin/topics/_topic.html.haml` | トピック行のパーシャル |

**主要処理フロー**:
- **7-8行目** (index): 空のステート表示条件
- **10-14行目** (index): ページヘッダーとアクションボタン
- **16-21行目** (index): 検索フォーム
- **26-28行目** (index): トピック一覧のレンダリング

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

```
Admin::TopicsController#index
    │
    ├─ Projects::TopicsFinder.new.execute
    │      │
    │      └─ search params, organization_id
    │
    ├─ .page(pagination_params[:page])
    │
    └─ render view
           │
           └─ index.html.haml
                  │
                  ├─ (empty state or list)
                  │
                  ├─ search form
                  │
                  └─ _topic.html.haml (partial, collection)

Admin::TopicsController#destroy
    │
    ├─ topic (find by id and organization_id)
    │
    └─ @topic.destroy!
           │
           └─ redirect_to admin_topics_path + notice

Admin::TopicsController#merge
    │
    ├─ source_topic / target_topic (find by id)
    │
    └─ Topics::MergeService.new.execute
           │
           └─ Success → redirect + flash[:toast]
              Failure → render json error
```

### データフロー図

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

search (query) ───▶ TopicsFinder.execute ───▶ @topics
page (query)            │
                        ▼
               .page(page).without_count
                        │
                        ▼
                index.html.haml
                        │
                        ▼
               _topic.html.haml (loop)
                        │
                        ▼
                 トピック一覧表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| topics_controller.rb | `app/controllers/admin/topics_controller.rb` | コントローラ | リクエスト処理 |
| index.html.haml | `app/views/admin/topics/index.html.haml` | ビュー | メインビュー |
| _topic.html.haml | `app/views/admin/topics/_topic.html.haml` | パーシャル | トピック行表示 |
| topic.rb | `app/models/projects/topic.rb` | モデル | トピックモデル |
| topics_finder.rb | `app/finders/projects/topics_finder.rb` | ファインダー | トピック検索 |
| merge_service.rb | `app/services/topics/merge_service.rb` | サービス | トピックマージ |
| admin.rb | `config/routes/admin.rb` | ルート | URLルーティング定義 |
