# 機能設計書 123-プロジェクトダッシュボード

## 概要

本ドキュメントは、GitLabにおけるプロジェクトダッシュボード機能の設計仕様を記述したものである。プロジェクトダッシュボードは、ユーザーが参加する全プロジェクトを一覧表示し、プロジェクトの検索・フィルタリング・ソート機能を提供するナビゲーション基盤である。

### 本機能の処理概要

**業務上の目的・背景**：開発者は複数のプロジェクトに並行して携わることが多く、迅速に目的のプロジェクトにアクセスする必要がある。プロジェクトダッシュボードは、参加プロジェクト・スタープロジェクト・個人プロジェクトなど様々な切り口でプロジェクトを整理・表示することで、効率的なプロジェクトナビゲーションを実現する。

**機能の利用シーン**：ナビゲーションメニューから「プロジェクト」を選択した際に表示される。日々の作業開始時にプロジェクトを選択する場面、特定のプロジェクトを検索する場面、プロジェクトのアクティビティをAtomフィードで購読する場面などで利用される。

**主要な処理内容**：
1. ユーザーがアクセス可能なプロジェクトの検索・フィルタリング
2. ソート設定（名前順、最終更新順等）の適用
3. 個人プロジェクト・非アクティブプロジェクトへのリダイレクト
4. プロジェクトイベントのAtomフィード生成
5. プロジェクト一覧のレンダリング

**関連システム・外部連携**：Atomフィード形式での出力により、外部RSSリーダーとの連携が可能。

**権限による制御**：ユーザーは自身がアクセス権を持つプロジェクトのみ表示される。非公開プロジェクトはメンバーのみに表示。Atomフィード用のセッションレス認証をサポート。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | プロジェクト一覧 | 主画面 | 参加プロジェクトの一覧表示 |
| 19 | プロジェクト探索 | 参照画面 | 公開プロジェクトの検索・探索 |

## 機能種別

データ取得・表示（READ操作）/ プロジェクト一覧表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| personal | String | No | 個人プロジェクトのみ表示（"true"） | "true"の場合リダイレクト |
| archived | String | No | アーカイブ状態フィルタ（"only"） | "only"の場合非アクティブへリダイレクト |
| sort | String | No | ソート順 | 許可されたソート順 |
| offset | Integer | No | イベント取得開始位置（Atom） | 0以上の整数 |

### 入力データソース

- セッション情報（current_user）
- ユーザーのソート設定（User preferences）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @projects | ActiveRecord::Relation<Project> | プロジェクト一覧 |
| @events | Array<Event> | プロジェクトイベント（Atom形式時） |
| @sort | String | 適用中のソート順 |

### 出力先

- HTML画面（プロジェクト一覧ビュー）
- Atomフィード（RSSリーダー向け）

## 処理フロー

### 処理シーケンス

```
1. 認証チェック
   └─ Atomアクセス時はセッションレス認証
2. パラメータチェックとリダイレクト
   └─ personal=true → 個人プロジェクトページへ
   └─ archived=only → 非アクティブプロジェクトページへ
3. ソート設定の取得・適用
   └─ ユーザー設定からデフォルトソート取得
4. プロジェクト一覧取得（HTML）
   └─ レンダリング
5. イベント一覧取得（Atom）
   └─ EventCollectionでイベント集約
   └─ XMLレイアウトでレンダリング
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{personal=true?}
    B -->|Yes| C[個人プロジェクトページへリダイレクト]
    B -->|No| D{archived=only?}
    D -->|Yes| E[非アクティブページへリダイレクト]
    D -->|No| F[ソート設定取得]
    F --> G{リクエスト形式?}
    G -->|HTML| H[プロジェクト一覧レンダリング]
    G -->|Atom| I[イベント取得]
    I --> J[Atomフィード生成]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-123-01 | 個人プロジェクトリダイレクト | personal=trueの場合、personal_dashboard_projects_pathへリダイレクト | personalパラメータがtrue |
| BR-123-02 | アーカイブリダイレクト | archived=onlyの場合、inactive_dashboard_projects_pathへリダイレクト | archivedパラメータがonly |
| BR-123-03 | デフォルトソート | ソート未指定時は名前順（sort_value_name） | sortパラメータなし |
| BR-123-04 | 非公開プロジェクト除外 | Atomフィード取得時はnon_public: trueで公開プロジェクトのみ | Atomリクエスト時 |
| BR-123-05 | 削除予定除外 | not_aimed_for_deletionで削除予定プロジェクトを除外 | Atomリクエスト時 |

### 計算ロジック

なし（データ取得・フィルタリングのみ）

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| プロジェクト一覧取得 | projects | SELECT | プロジェクト情報取得 |
| イベント取得 | events | SELECT | プロジェクトイベント取得 |
| ルート取得 | routes | SELECT | プロジェクトパス情報取得 |

### テーブル別操作詳細

#### projects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, path, namespace_id, visibility_level | アクセス権限あり AND 削除予定なし | N+1防止のwith_route |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | Atom未認証アクセス | ログイン要求 |
| - | 空リスト | アクセス可能なプロジェクトがない | 空の一覧を表示（エラーではない） |

### リトライ仕様

データベースタイムアウト時は標準的なRailsリトライ機構に従う。

## トランザクション仕様

読み取り専用のため、明示的なトランザクション管理は不要。

## パフォーマンス要件

- urgency: low
- with_routeスコープによるN+1クエリ防止
- RendersProjectsList concernによる効率的レンダリング

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

- セッションレス認証（Atom用）
- クロスプロジェクトアクセスチェックスキップ
- 可視性レベルに基づくフィルタリング

## 備考

- ParamsBackwardCompatibility concernで旧パラメータ形式をサポート
- RendersMemberAccess concernでメンバーアクセスレベル表示
- SortingPreference concernでユーザーソート設定を永続化

---

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

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

### 推奨読解順序

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

プロジェクトモデルとイベントの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Project | `app/models/project.rb` | プロジェクトの基本属性と関連 |
| 1-2 | Event | `app/models/event.rb` | イベントの種類とプロジェクトとの関連 |

**読解のコツ**: ProjectはNamespaceに属し、namespace_idで所属グループ/ユーザーを参照する。

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

コントローラーの処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Dashboard::ProjectsController | `app/controllers/dashboard/projects_controller.rb` | indexアクションの処理フロー |

**主要処理フロー**:
1. **11行目**: セッションレス認証（RSS用）
2. **19-32行目**: indexアクション - リダイレクト判定とレスポンス分岐
3. **36-46行目**: load_eventsメソッド - Atomフィード用イベント取得
4. **56-59行目**: ソート設定の適用

#### Step 3: プロジェクト検索処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ProjectsFinder | `app/finders/projects_finder.rb` | プロジェクト検索のメインロジック |

**主要処理フロー**:
- **54-72行目**: executeメソッド - フィルタ適用とソート
- **85-110行目**: filter_projectsメソッド - 各種フィルタの適用順序
- **285-291行目**: sortメソッド - ソート処理

#### Step 4: イベント取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | EventCollection | `app/services/event_collection.rb` | プロジェクトイベントの集約 |

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

```
Dashboard::ProjectsController#index
    │
    ├─ (HTML) respond_to :html
    │      └─ render 'dashboard/projects/index'
    │
    └─ (Atom) respond_to :atom
           └─ load_events
                  │
                  ├─ ProjectsFinder.new(params, current_user).execute
                  │
                  └─ EventCollection.new(projects, options)
                         │
                         └─ Events::RenderService.new(current_user).execute(@events)
```

### データフロー図

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

current_user ───────────▶ Dashboard::ProjectsController ────▶ HTML View
                               │
params ────────────────────────┤
                               │
                         ┌─────┴─────┐
                         │           │
                       (HTML)      (Atom)
                         │           │
                 RendersProjectsList │
                         │           │
                         │     ProjectsFinder
                         │           │
                         │     EventCollection
                         │           │
                         │     Events::RenderService
                         │           │
                         ▼           ▼
                    HTML View    Atom Feed
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Dashboard::ProjectsController | `app/controllers/dashboard/projects_controller.rb` | コントローラー | エントリーポイント |
| Dashboard::ApplicationController | `app/controllers/dashboard/application_controller.rb` | 基底コントローラー | 認証・共通処理 |
| ProjectsFinder | `app/finders/projects_finder.rb` | ファインダー | プロジェクト検索ロジック |
| EventCollection | `app/services/event_collection.rb` | サービス | イベント集約 |
| Events::RenderService | `app/services/events/render_service.rb` | サービス | イベントレンダリング |
| ParamsBackwardCompatibility | `app/controllers/concerns/params_backward_compatibility.rb` | Concern | 旧パラメータ対応 |
| RendersMemberAccess | `app/controllers/concerns/renders_member_access.rb` | Concern | メンバーアクセス表示 |
| RendersProjectsList | `app/controllers/concerns/renders_projects_list.rb` | Concern | プロジェクト一覧表示 |
| SortingHelper | `app/helpers/sorting_helper.rb` | ヘルパー | ソートUI |
| SortingPreference | `app/controllers/concerns/sorting_preference.rb` | Concern | ソート設定永続化 |
| FiltersEvents | `app/controllers/concerns/filters_events.rb` | Concern | イベントフィルタ |
