# 画面設計書 30-ファイルツリー

## 概要

本ドキュメントは、GitLabのファイルツリー画面に関する設計書である。この画面はリポジトリのディレクトリ構造とファイル一覧を表示し、ソースコードの閲覧やナビゲーションを提供する機能である。

### 本画面の処理概要

ファイルツリー画面は、指定されたブランチやタグ、コミットにおけるリポジトリの特定パスのディレクトリ構造を表示する。ファイルやディレクトリをクリックして階層を移動し、READMEの自動表示や最終コミット情報の表示も行う。

**業務上の目的・背景**：ソースコード管理においてリポジトリの構造を把握し、目的のファイルに効率的にアクセスすることは基本的な操作である。この画面により、開発者はリポジトリの全体像を把握し、必要なファイルを素早く見つけることができる。

**画面へのアクセス方法**：
- プロジェクト詳細画面からリポジトリセクションをクリック
- サイドバーの「Code」→「Repository」を選択
- 直接URL `/:namespace/:project/-/tree/:ref` にアクセス
- 直接URL `/:namespace/:project/-/tree/:ref/:path` にアクセス（サブディレクトリ）

**主要な操作・処理内容**：
1. ファイル・ディレクトリ一覧の表示 - 指定パスの内容を表示
2. ディレクトリナビゲーション - クリックでサブディレクトリへ移動
3. ファイル閲覧への遷移 - ファイルをクリックでblob画面へ
4. ブランチ/タグ切り替え - 別のrefを選択して表示
5. 新規ディレクトリ作成 - ディレクトリの作成

**画面遷移**：
- 遷移元：プロジェクト詳細画面、サイドバーナビゲーション、コミット画面
- 遷移先：ファイル詳細画面(blob)、サブディレクトリ、Web IDE、新規ファイル作成画面

**権限による表示制御**：
- `read_code`権限：ファイルツリーの閲覧
- `edit_tree`権限：新規ディレクトリ作成ボタンの表示
- 未ログインユーザー：デフォルトブランチ以外はログイン要求される場合あり

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | リポジトリ閲覧 | 主機能 | リポジトリのファイルツリー表示 |
| 17 | ファイル作成 | 補助機能 | 新規ファイル作成への遷移 |

## 画面種別

一覧

## URL/ルーティング

- URL: `/:namespace/:project/-/tree/:ref`
- URL: `/:namespace/:project/-/tree/:ref/*path`
- ルーティング: `config/routes/repository.rb` - `get '/tree/*id', to: 'tree#show', as: :tree`
- コントローラ: `Projects::TreeController#show`, `Projects::TreeController#create_dir`

## 入出力項目

| 項目名 | 入力/出力 | 必須 | データ型 | 説明 |
|--------|----------|------|----------|------|
| id | 入力 | 必須 | String | ref/path形式（ブランチ名+パス） |
| ref | 入力 | 必須 | String | ブランチ名/タグ名/コミットSHA |
| path | 入力 | - | String | ディレクトリパス（省略時はルート） |
| ref_type | 入力 | - | String | refs種別（heads/tags等） |
| branch_name | 入力 | - | String | 新規ディレクトリ作成時のブランチ名 |
| dir_name | 入力 | - | String | 作成するディレクトリ名 |
| commit_message | 入力 | - | String | コミットメッセージ |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| ref情報 | String | 現在表示中のブランチ/タグ/コミット |
| パンくずリスト | List | 現在のパス階層 |
| ファイル/ディレクトリ一覧 | List | エントリー一覧 |
| エントリー名 | String | ファイル/ディレクトリ名 |
| エントリータイプ | Enum | file/tree/submodule |
| 最終コミット情報 | Object | 各エントリーの最終更新コミット |
| 最終コミットメッセージ | String | コミットのサマリー |
| 最終コミット日時 | DateTime | コミット日時 |
| README内容 | HTML | README.mdの内容（存在する場合） |

## イベント仕様

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

1. `Projects::TreeController#show` が呼び出される
2. `require_non_empty_project` で空リポジトリチェック
3. `assign_ref_vars` でref/path情報を抽出
4. `set_is_ambiguous_ref` で曖昧なref名をチェック
5. `authorize_read_code!` で権限チェック
6. `@commit` が存在しない場合は404
7. ディレクトリが空でファイルが存在する場合はblob画面にリダイレクト
8. GraphQLクエリでファイルツリーとコミット情報を取得

### 2-ディレクトリナビゲーション

1. ディレクトリをクリック
2. `project_tree_path(@project, ref/new_path)` に遷移
3. 新しいパスでファイルツリーを表示

### 3-ファイル閲覧

1. ファイルをクリック
2. `project_blob_path(@project, ref/file_path)` に遷移
3. ファイル詳細画面を表示

### 4-新規ディレクトリ作成

1. `Projects::TreeController#create_dir` が呼び出される
2. `authorize_edit_tree!` で編集権限チェック
3. `Files::CreateDirService` でディレクトリ作成
4. 成功時：新しいディレクトリのtree画面にリダイレクト
5. 失敗時：元のtree画面を表示

### 5-ブランチ/タグ切り替え

1. refセレクターで別のブランチ/タグを選択
2. 選択したrefで同じパスのtree画面に遷移

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ページ読み込み | projects | SELECT | プロジェクト情報取得 |
| ディレクトリ作成 | - | - | Gitalyで直接Git操作 |

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

#### projects

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | id = :project_id | プロジェクト情報取得 |

## メッセージ仕様

| 種別 | メッセージID | メッセージ内容 | 表示条件 |
|------|------------|--------------|---------|
| 成功 | dir_created | The directory has been successfully created. | ディレクトリ作成成功時 |
| 情報 | repository | Repository | パンくずリスト |
| 情報 | files | Files | ページタイトル |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| コミットが存在しない | 404エラー |
| 空リポジトリ | 空リポジトリ画面を表示 |
| コード閲覧権限がない | アクセス拒否 |
| パスがファイルの場合 | blob画面にリダイレクト |
| パスが存在しない | ルートにリダイレクト |
| 曖昧なref名 | モーダルで確認を表示 |

## 備考

- ファイルツリーはGitalyを介してGitリポジトリから直接取得
- GraphQLを使用してファイル一覧と最終コミット情報を取得
- `repository_file_tree_browser` フィーチャーフラグでUIが切り替わる
- READMEファイルが存在する場合は自動的にレンダリング
- ページロード時に複数のGraphQLクエリが並行実行される
- インラインブレーム機能は `inline_blame` フィーチャーフラグで制御
- ファイルロック機能は有料プランでのみ利用可能

---

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

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

### 推奨読解順序

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

リポジトリのツリー構造に関連するモジュールを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | extracts_path.rb | `app/controllers/concerns/extracts_path.rb` | ref/pathの抽出ロジック |
| 1-2 | tree.rb | `lib/gitlab/git/tree.rb` | Gitツリーオブジェクト |

**読解のコツ**: `ExtractsPath` モジュールの `assign_ref_vars` メソッドで、URLからref（ブランチ/タグ）とpath（ディレクトリパス）をどのように分離するかを理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tree_controller.rb | `app/controllers/projects/tree_controller.rb` | show/create_dirアクション |

**主要処理フロー**:
1. **4-9行目**: インクルードモジュール（ExtractsPath, CreatesCommit等）
2. **11行目**: Gitalyキャッシュの設定
3. **13-18行目**: before_actionの設定
4. **20-24行目**: フィーチャーフラグのプッシュ
5. **29-48行目**: `show` アクション
6. **30行目**: コミット存在チェック
7. **32-37行目**: 認証要求判定（未ログイン+非デフォルトブランチ）
8. **41-47行目**: 空ディレクトリ時のリダイレクト処理
9. **50-59行目**: `create_dir` アクション
10. **68-70行目**: `tree` メソッド - ツリーオブジェクト取得

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.haml | `app/views/projects/tree/show.html.haml` | メインビュー |
| 3-2 | _files.html.haml | `app/views/projects/_files.html.haml` | ファイル一覧パーシャル |
| 3-3 | _tree_content.html.haml | `app/views/projects/_tree_content.html.haml` | ツリーコンテンツ |

**主要処理フロー**:
- **1-6行目（show.html.haml）**: GraphQLスタートアップクエリの設定
- **8-9行目（show.html.haml）**: フィーチャーフラグでレイアウト切り替え
- **11行目（show.html.haml）**: ページタイトル設定
- **15行目（show.html.haml）**: last_pushパーシャル
- **17行目（show.html.haml）**: filesパーシャル
- **14-22行目（_files.html.haml）**: フィーチャーフラグでUIパターン切り替え
- **1-3行目（_tree_content.html.haml）**: Vue.jsヘッダーアプリ
- **14行目（_tree_content.html.haml）**: 最終コミット情報
- **19行目（_tree_content.html.haml）**: Vue.jsツリーリスト

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

```
Projects::TreeController#show
    │
    ├─ require_non_empty_project
    │
    ├─ assign_ref_vars (ExtractsPath)
    │      │
    │      ├─ ref_names (ブランチ・タグ一覧取得)
    │      │
    │      └─ extract_ref (URLからref/path分離)
    │
    ├─ set_is_ambiguous_ref
    │      └─ 同名のブランチ・タグが存在するか確認
    │
    ├─ authorize_read_code!
    │
    ├─ @commit = @repo.commit(@ref)
    │      └─ render_404 if @commit.nil?
    │
    ├─ require_auth? (未ログイン+非デフォルトブランチ)
    │
    └─ tree.entries (ディレクトリ内容取得)
           │
           ├─ @repository.blob_at → redirect_to blob
           │
           └─ redirect_to_tree_root_for_missing_path (パス不在時)

Projects::TreeController#create_dir
    │
    ├─ authorize_edit_tree!
    │
    ├─ assign_dir_vars
    │
    └─ create_commit (CreatesCommit)
           └─ Files::CreateDirService
                  └─ Gitaly::Repository#create_dir
```

### データフロー図

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

リクエスト ───▶ TreeController#show ───▶ Vue.jsアプリ
    │                     │
    ├─ ref (ブランチ等)    ├─ ExtractsPath
    │                     │      └─ ref/path分離
    ├─ path (ディレクトリ)  │
    │                     ├─ Gitaly
    └─ ref_type           │      └─ tree取得
                         │
                         ├─ GraphQL起動クエリ
                         │      ├─ path_last_commit
                         │      ├─ permissions
                         │      └─ files
                         │
                         └─────────────────▶ HTML + Vue.js
                                                │
                                                ├─ ファイル一覧
                                                ├─ 最終コミット情報
                                                └─ README表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| tree_controller.rb | `app/controllers/projects/tree_controller.rb` | コントローラ | リクエストハンドリング |
| show.html.haml | `app/views/projects/tree/show.html.haml` | テンプレート | メインビュー |
| _files.html.haml | `app/views/projects/_files.html.haml` | パーシャル | ファイル一覧コンテナ |
| _tree_content.html.haml | `app/views/projects/_tree_content.html.haml` | パーシャル | ツリーコンテンツ |
| extracts_path.rb | `app/controllers/concerns/extracts_path.rb` | Concern | ref/path抽出 |
| creates_commit.rb | `app/controllers/concerns/creates_commit.rb` | Concern | コミット作成 |
| create_dir_service.rb | `app/services/files/create_dir_service.rb` | サービス | ディレクトリ作成 |
| repository.rb | `config/routes/repository.rb` | ルーティング | URL定義 |
