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

## 概要

本ドキュメントは、GitLabのトピック一覧画面に関する設計書である。この画面はプロジェクトに付与されたトピック（タグ）を一覧表示し、トピックを通じてプロジェクトを探索するための機能を提供する。

### 本画面の処理概要

トピック一覧画面は、GitLabインスタンス内で定義されたプロジェクトトピックを一覧表示する。ユーザーはトピックを通じて関連するプロジェクトを効率的に発見することができる。

**業務上の目的・背景**：プロジェクトにはトピック（タグ）を付与することができ、これにより技術スタック、目的、チームなどでプロジェクトを分類・整理できる。トピック一覧画面は、これらのトピックを俯瞰し、関連するプロジェクトを探す際の入口となる。プロジェクト発見性の向上と、組織内のナレッジ管理に貢献する機能である。

**画面へのアクセス方法**：
- サイドバーの「Explore」メニューから「Topics」を選択
- 直接URL `/explore/projects/topics` にアクセス

**主要な操作・処理内容**：
1. トピック一覧の表示 - 組織内のトピックをページネーション付きで表示
2. トピック検索 - キーワードによるトピックの絞り込み
3. トピック詳細への遷移 - トピックを選択して関連プロジェクト一覧を表示
4. プロジェクト数の表示 - 各トピックに関連付けられたプロジェクト数を表示

**画面遷移**：
- 遷移元：ダッシュボード、サイドナビゲーション、ダイレクトURL
- 遷移先：トピック詳細画面（プロジェクト一覧）

**権限による表示制御**：
- 未ログインユーザー：公開トピックの閲覧が可能
- ログインユーザー：公開トピックおよび自身がアクセス可能なプロジェクトに関連するトピックの閲覧

## 関連機能

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

## 画面種別

一覧

## URL/ルーティング

- URL: `/explore/projects/topics`
- ルーティング: `config/routes/explore.rb` - `get :topics`
- コントローラ: `Explore::ProjectsController#topics`

## 入出力項目

| 項目名 | 入力/出力 | 必須 | データ型 | 説明 |
|--------|----------|------|----------|------|
| search | 入力 | - | String | トピック名の検索キーワード |
| page | 入力 | - | Integer | ページネーションのページ番号 |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| トピック名 | String | トピックの名前 |
| トピックアバター | Image | トピックのアイコン画像 |
| 説明 | Text | トピックの説明文 |
| プロジェクト数 | Integer | トピックに関連付けられたプロジェクト数 |

## イベント仕様

### 1-ページ読み込み

1. `Explore::ProjectsController#topics` が呼び出される
2. `load_project_counts` でユーザーのプロジェクト数を取得
3. `load_topics` で `Projects::TopicsFinder` を使用してトピック一覧を取得
4. ページネーション処理を適用
5. ビューをレンダリング

### 2-トピック検索

- フォームからsearchパラメータを送信
- `Projects::TopicsFinder` がsearchパラメータでフィルタリング
- 検索結果を表示

### 3-トピック選択

- 遷移先: `/explore/projects/topic/:topic_name`
- 選択したトピックに関連するプロジェクト一覧を表示

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

- 次/前ページのリンクをクリック
- `page` パラメータを更新してリロード

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ページ読み込み | topics | SELECT | トピック一覧の取得 |
| ページ読み込み | projects | SELECT | プロジェクト数のカウント |

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

#### topics

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | organization_idによるスコープ | 組織内のトピックのみ |

## メッセージ仕様

| 種別 | メッセージID | メッセージ内容 | 表示条件 |
|------|------------|--------------|---------|
| 情報 | Empty State | トピックが存在しません | トピックが0件かつ検索なしの場合 |
| 情報 | Empty Search | 検索結果が見つかりません | 検索結果が0件の場合 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| 組織が存在しない場合 | 空のトピック一覧を表示 |
| ページ番号が範囲外 | 空の結果を表示 |

## 備考

- トピックは組織（Organization）スコープでフィルタリングされる
- 空の状態ではEmptyStateコンポーネントが表示される
- ページネーションは `without_count` を使用

---

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

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

### 推奨読解順序

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

トピックのデータモデルとファインダーの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | topic.rb | `app/models/projects/topic.rb` | Topicモデルの構造、スコープ |
| 1-2 | topics_finder.rb | `app/finders/projects/topics_finder.rb` | トピック検索ロジック |

**読解のコツ**: TopicsFinderの検索条件とorganization_idによるスコープを確認する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | projects_controller.rb | `app/controllers/explore/projects_controller.rb` | topicsアクション |

**主要処理フロー**:
1. **86-89行目**: `topics` アクション - `load_project_counts` と `load_topics` を呼び出し
2. **132-137行目**: `load_topics` メソッド - TopicsFinderを使用してトピック取得
3. **139-149行目**: `load_topic` メソッド - 個別トピック取得

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | topics.html.haml | `app/views/explore/projects/topics.html.haml` | メインビュー |
| 3-2 | _list.html.haml | `app/views/shared/topics/_list.html.haml` | トピック一覧パーシャル |
| 3-3 | _topic.html.haml | `app/views/shared/topics/_topic.html.haml` | 個別トピック表示 |

**主要処理フロー**:
- **10-11行目（topics.html.haml）**: Empty Stateの条件分岐
- **12-14行目（topics.html.haml）**: ヘッダーとリストパーシャルの表示

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

```
Explore::ProjectsController#topics
    │
    ├─ load_project_counts
    │      ├─ ProjectsFinder (non_public)
    │      └─ ProjectsFinder (starred)
    │
    └─ load_topics
           └─ Projects::TopicsFinder.new
                  └─ #execute
                        ├─ filter_by_search
                        └─ filter_by_organization
```

### データフロー図

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

リクエスト ───▶ ProjectsController#topics ───▶ @topics
    │                     │
    ├─ search ───▶ TopicsFinder ───▶ フィルタリング結果
    │                     │
    └─ page ───▶ ページネーション ───▶ ページ分割結果
                          │
                          └─────────────────▶ HTML レスポンス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| projects_controller.rb | `app/controllers/explore/projects_controller.rb` | コントローラ | リクエストハンドリング |
| topics.html.haml | `app/views/explore/projects/topics.html.haml` | テンプレート | メインビュー |
| _list.html.haml | `app/views/shared/topics/_list.html.haml` | パーシャル | トピック一覧表示 |
| _topic.html.haml | `app/views/shared/topics/_topic.html.haml` | パーシャル | 個別トピック表示 |
| _head.html.haml | `app/views/explore/topics/_head.html.haml` | パーシャル | 検索フォームヘッダー |
| topics_finder.rb | `app/finders/projects/topics_finder.rb` | ファインダー | トピック検索ロジック |
| topic.rb | `app/models/projects/topic.rb` | モデル | Topicモデル定義 |
| explore.rb | `config/routes/explore.rb` | ルーティング | URLルーティング定義 |
