# 画面設計書 32-ファイル新規作成

## 概要

本ドキュメントは、GitLabのリポジトリに新規ファイルを作成する画面（ファイル新規作成画面）の設計を記述したものである。

### 本画面の処理概要

本画面は、Webブラウザ上からリポジトリに新しいファイルを追加するための画面である。ファイル名の指定、内容の入力、コミットメッセージの記述を行い、直接リポジトリにコミットを作成することができる。

**業務上の目的・背景**：開発者がローカル環境を使用せずに、簡単な設定ファイルの追加、READMEの作成、.gitignoreの追加などを行いたい場合がある。本画面は、Git CLIやローカルエディタを使用することなく、Webインターフェースから直接ファイルを作成・コミットできる機能を提供し、軽微な変更作業の効率化を実現する。

**画面へのアクセス方法**：
- ファイルツリー画面の「+」ボタンから「New file」を選択
- URL直接入力: `/{namespace}/{project}/-/new/{ref}/{path}`
- プロジェクト概要画面の「Add file」ドロップダウン

**主要な操作・処理内容**：
1. ファイルパス（ディレクトリ含む）の入力
2. ファイル内容の編集（Monaco Editor使用）
3. コミットメッセージの入力
4. ターゲットブランチの選択（既存または新規）
5. マージリクエスト作成オプションの選択
6. コミット実行

**画面遷移**：
- 遷移元: ファイルツリー画面、プロジェクト概要画面、空のリポジトリ画面
- 遷移先: 作成されたファイルの表示画面、マージリクエスト作成画面（オプション選択時）

**権限による表示制御**：
- プッシュ権限がない場合はアクセス不可
- 保護ブランチへの直接プッシュ権限がない場合は新規ブランチ作成が必須
- フォークして編集するオプションが権限に応じて表示

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | ファイル作成 | 主機能 | 新規ファイルの作成・コミット |
| 19 | ブランチ管理 | 補助機能 | 新規ブランチへのコミット |
| 28 | マージリクエスト作成 | 遷移先機能 | MR作成オプション選択時 |

## 画面種別

登録

## URL/ルーティング

```
GET  /{namespace}/{project}/-/new/{ref}/{*path}
POST /{namespace}/{project}/-/create/{ref}/{*path}
```

**ルート定義**: `config/routes/repository.rb`
```ruby
scope controller: :blob do
  get '/new/*id', action: :new, as: :new_blob
  post '/create/*id', action: :create, as: :create_blob
end
```

## 入出力項目

| 項目名 | 入出力 | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| namespace | 入力 | String | Yes | プロジェクトの名前空間 |
| project | 入力 | String | Yes | プロジェクト名 |
| ref | 入力 | String | Yes | ベースブランチ |
| path | 入力 | String | No | ベースディレクトリパス |
| file_name | 入力 | String | Yes | 新規ファイル名 |
| content | 入力 | Text | No | ファイル内容 |
| commit_message | 入力 | String | Yes | コミットメッセージ |
| branch_name | 入力 | String | Yes | ターゲットブランチ名 |
| start_new_mr | 入力 | Boolean | No | MR作成フラグ |
| encoding | 入力 | String | No | エンコーディング（text/base64） |

## 表示項目

| 項目名 | 説明 | データソース |
|--------|------|-------------|
| ベースブランチ名 | 作成元ブランチ | @ref |
| 現在のパス | ファイル作成先ディレクトリ | @path |
| ファイル名入力欄 | 新規ファイル名の入力 | 入力項目 |
| エディタ | ファイル内容編集領域 | Monaco Editor |
| コミットメッセージ欄 | コミットメッセージの入力 | 入力項目 |
| ブランチ名入力欄 | ターゲットブランチの指定 | 入力項目 |
| MRチェックボックス | マージリクエスト作成オプション | 入力項目 |

## イベント仕様

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

新規ファイル作成フォームを初期化する。

**処理フロー**:
1. URLからref、pathを抽出
2. リポジトリが空でないことを確認
3. 編集権限を確認
4. Monaco Editorを初期化
5. デフォルトのコミットメッセージを生成

### 2-ファイル名入力

ファイルパス（ディレクトリ含む）を入力する。

**処理**:
- `/`を含む場合、ディレクトリ階層として解釈
- ファイル拡張子に応じてシンタックスハイライトを更新

### 3-Commit changesボタン押下

ファイルを作成しコミットを実行する。

**処理フロー**:
1. 入力値のバリデーション
2. Files::CreateServiceを呼び出し
3. リポジトリにファイルを追加
4. コミットを作成
5. 成功時：作成されたファイル表示画面へリダイレクト
6. MRオプション選択時：MR作成画面へリダイレクト

### 4-Cancelボタン押下

ファイル作成をキャンセルする。

**遷移先**: 直前のページまたはファイルツリー画面

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| Commit changes | events | INSERT | ファイル作成イベントの記録 |
| Commit changes | push_event_payloads | INSERT | プッシュイベント詳細 |
| Commit changes | project_statistics | UPDATE | プロジェクト統計の更新 |

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

#### events

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | action | 5 (PUSHED) | プッシュアクション |
| INSERT | author_id | current_user.id | 実行ユーザー |
| INSERT | project_id | @project.id | 対象プロジェクト |
| INSERT | target_type | nil | - |

#### push_event_payloads

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | event_id | 作成されたevent.id | 関連イベント |
| INSERT | commit_count | 1 | コミット数 |
| INSERT | action | 1 (CREATED) | ファイル作成 |
| INSERT | ref_type | 1 (BRANCH) | ブランチ参照 |
| INSERT | ref | @branch_name | ブランチ名 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 発生条件 |
|-------------|------|---------------|----------|
| M001 | 成功 | "The file has been successfully created." | ファイル作成成功 |
| M002 | エラー | "You must provide a file path" | ファイルパス未入力 |
| M003 | エラー | "A file with this name already exists" | 同名ファイルが既存 |
| M004 | エラー | "Your changes could not be committed..." | コミット失敗 |
| M005 | エラー | "You can not push to this branch" | 保護ブランチへのプッシュ不可 |

## 例外処理

| 例外 | 発生条件 | 処理内容 |
|------|---------|---------|
| 403 Forbidden | 編集権限なし | アクセス拒否画面表示 |
| PreReceiveError | pre-receiveフック失敗 | エラーメッセージ表示 |
| InvalidPathError | 不正なファイルパス | バリデーションエラー表示 |
| LockFileError | ファイルがロック中 | ロック解除を促すメッセージ |

## 備考

- Monaco Editorを使用してリッチな編集体験を提供
- ファイルアップロード（ドラッグ＆ドロップ）にも対応
- テンプレートファイル（.gitlab-ci.yml等）の選択機能あり
- LFSが有効な場合、大きなファイルは自動的にLFSで管理

---

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

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

### 推奨読解順序

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

ファイル作成で使用されるパラメータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | blob_controller.rb | `app/controllers/projects/blob_controller.rb` | editor_variablesメソッドで設定されるパラメータ |
| 1-2 | base_service.rb | `app/services/files/base_service.rb` | ファイル操作の基底クラスと共通パラメータ |

**読解のコツ**: `editor_variables`メソッド（255-269行目）で、フォームから送信されるパラメータがどのように@commit_paramsに変換されるかを確認する。

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

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

**主要処理フロー**:
1. **57-59行目**: `def new` - フォーム表示、リポジトリが空でない場合commitを取得
2. **61-68行目**: `def create` - ファイル作成処理
3. **62行目**: `create_commit` - 共通のコミット作成メソッド呼び出し
4. **63行目**: `Files::CreateService` - 実際のファイル作成サービス

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | new.html.haml | `app/views/projects/blob/new.html.haml` | 新規作成フォーム全体構造 |
| 3-2 | _editor.html.haml | `app/views/projects/blob/_editor.html.haml` | エディタパーシャル |

**主要処理フロー**:
- **5行目**: `edit_blob_app_data` - フロントエンドアプリ用データ
- **16行目**: `form_tag` - フォーム送信先（create_blob_path）
- **17行目**: `render 'projects/blob/editor'` - エディタ描画

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | create_service.rb | `app/services/files/create_service.rb` | ファイル作成サービス |
| 4-2 | base_service.rb | `app/services/files/base_service.rb` | 共通バリデーション |

**主要処理フロー**:
- **5-11行目**: `create_commit!` - LFS変換とコミット作成
- **15-18行目**: `validate!` - ファイルパスの必須チェック
- **22-32行目**: `create_transformed_commit` - リポジトリへのファイル追加

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

```
Projects::BlobController#create
    │
    ├─ authorize_edit_tree!
    │
    ├─ editor_variables
    │      └─ fetch_file_path
    │
    └─ create_commit(Files::CreateService, ...)
           │
           ├─ Files::CreateService#execute
           │      ├─ validate!
           │      ├─ Lfs::FileTransformer#new_file
           │      └─ create_transformed_commit
           │             └─ repository.create_file
           │                    └─ Gitlab::Git::Repository#create_file
           │
           └─ success_path / failure_path
```

### データフロー図

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

Form Parameters ───▶ BlobController#create ───▶ Redirect / Render
  - file_name         │
  - content           ├─▶ Files::CreateService
  - commit_message    │      │
  - branch_name       │      ├─▶ Lfs::FileTransformer
                      │      │
                      │      └─▶ Repository#create_file
                      │             │
                      │             └─▶ Git Repository
                      │
                      └─▶ Event Recording
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| blob_controller.rb | `app/controllers/projects/blob_controller.rb` | コントローラー | リクエスト処理 |
| new.html.haml | `app/views/projects/blob/new.html.haml` | テンプレート | フォームビュー |
| _editor.html.haml | `app/views/projects/blob/_editor.html.haml` | パーシャル | エディタ部品 |
| create_service.rb | `app/services/files/create_service.rb` | サービス | ファイル作成ロジック |
| base_service.rb | `app/services/files/base_service.rb` | サービス | 共通処理 |
| creates_commit.rb | `app/controllers/concerns/creates_commit.rb` | Concern | コミット作成共通処理 |
| file_transformer.rb | `app/services/lfs/file_transformer.rb` | サービス | LFS変換 |
| repository.rb | `config/routes/repository.rb` | ルーティング | URL定義 |
