# 画面設計書 283-Wiki編集

## 概要

本ドキュメントは、GitLabのWikiページ編集画面の設計を記載したものである。

### 本画面の処理概要

**業務上の目的・背景**：Wikiはプロジェクトやグループに関するドキュメントを作成・管理するための機能である。Wiki編集画面は、ユーザーが既存のWikiページを更新したり、新規ページを作成したりするために必要な画面であり、ドキュメントの作成・更新、ナレッジの蓄積・改善といった業務ニーズに対応する。Markdown、AsciiDoc等の複数のマークアップ形式をサポートする。

**画面へのアクセス方法**：Wiki表示画面から「Edit」ボタンをクリックするか、直接URLで `/:namespace/:project/-/wikis/:page_slug/edit` にアクセスする。新規作成の場合は `/:namespace/:project/-/wikis/new` または存在しないページURLにアクセス後、作成フォームが表示される。Wiki作成権限を持つユーザーのみがアクセス可能。

**主要な操作・処理内容**：
1. Wikiページのタイトルを入力・編集する
2. ページ本文をエディタで編集する（Markdown/AsciiDoc/その他）
3. マークアップ形式を選択する
4. プレビュー機能でレンダリング結果を確認する
5. コミットメッセージを入力する
6. テンプレートを選択して適用する
7. 変更を保存してWikiページを作成・更新する
8. 編集をキャンセルしてWiki表示画面に戻る

**画面遷移**：
- 遷移元：Wiki表示画面、Wiki一覧画面、サイドバーの「New page」ボタン
- 遷移先：Wiki表示画面（保存成功時）、Wiki表示画面（キャンセル時）

**権限による表示制御**：
- 作成権限（create_wiki）を持つユーザーのみがアクセス可能
- アーカイブされたプロジェクト/グループでは編集不可
- 非UTF-8エンコーディングのページは編集不可（Gitリポジトリ経由でのみ編集可能）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 69 | Wikiページ作成・編集 | 主機能 | Wikiページの作成・更新処理 |

## 画面種別

登録 / 編集

## URL/ルーティング

| メソッド | パス | コントローラー#アクション | 説明 |
|----------|------|---------------------------|------|
| GET | `/:namespace/:project/-/wikis/:id/edit` | `projects/wikis#edit` | 編集画面表示 |
| GET | `/:namespace/:project/-/wikis/new` | `projects/wikis#new` | 新規作成（リダイレクト） |
| POST | `/:namespace/:project/-/wikis` | `projects/wikis#create` | 新規ページ作成 |
| PUT | `/:namespace/:project/-/wikis/:id` | `projects/wikis#update` | ページ更新 |

## 入出力項目

| 項目名 | 項目ID | データ型 | 必須 | 最大長 | 説明 |
|--------|--------|----------|------|--------|------|
| タイトル | title | String | Yes | 255バイト/ディレクトリ名、245バイト/ファイル名 | ページタイトル（パス含む） |
| コンテンツ | content | String | Yes | 設定による | ページ本文 |
| フォーマット | format | String | Yes | - | マークアップ形式 |
| コミットメッセージ | message | String | No | - | 変更のコミットメッセージ |
| 最終コミットSHA | last_commit_sha | String | No | - | 楽観的ロック用（編集時） |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| ページタイトル入力欄 | タイトルの入力フィールド |
| フォーマット選択 | Markdown/AsciiDoc等の選択ドロップダウン |
| エディタ | 本文編集エリア |
| プレビュータブ | レンダリング結果のプレビュー |
| テンプレート選択 | 利用可能なテンプレート一覧 |
| コミットメッセージ入力欄 | 変更理由の入力フィールド |
| 保存ボタン | 変更を保存するボタン |
| キャンセルボタン | 編集をキャンセルするボタン/リンク |

## イベント仕様

### 1-保存ボタン押下（新規作成）

**トリガー**：「Create page」ボタンをクリック（新規ページ作成時）

**処理フロー**：
1. フォームバリデーションを実行
2. WikiPages::CreateService を呼び出し
3. Gitリポジトリに新規ファイルをコミット
4. 成功時：Wiki表示画面へリダイレクト
5. 失敗時：エラーメッセージを表示、編集画面を再表示

### 2-保存ボタン押下（更新）

**トリガー**：「Save changes」ボタンをクリック（既存ページ編集時）

**処理フロー**：
1. フォームバリデーションを実行
2. 楽観的ロックチェック（last_commit_sha）
3. WikiPages::UpdateService を呼び出し
4. Gitリポジトリにファイル変更をコミット
5. 成功時：Wiki表示画面へリダイレクト
6. 失敗時：エラーメッセージを表示

### 3-プレビュータブ選択

**トリガー**：「Preview」タブをクリック

**処理フロー**：
1. `/preview_markdown` エンドポイントにPOSTリクエスト
2. レンダリングされたHTMLを取得
3. プレビューエリアに表示

### 4-テンプレート選択

**トリガー**：テンプレートドロップダウンからテンプレートを選択

**処理フロー**：
1. 選択されたテンプレートの内容を取得
2. エディタにテンプレート内容を挿入

### 5-キャンセルボタン押下

**トリガー**：「Cancel」ボタンまたはリンクをクリック

**処理フロー**：
1. 変更を破棄
2. Wiki表示画面へ遷移（既存ページの場合）またはWiki一覧へ遷移（新規の場合）

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 新規作成 | wiki_page_meta | INSERT | ページメタ情報の作成（必要時） |
| 更新 | wiki_page_meta | UPDATE | ページメタ情報の更新（必要時） |
| 新規作成/更新 | events | INSERT | アクティビティイベントの記録 |

### 備考

WikiコンテンツはGitリポジトリに格納されるため、主なデータ書き込みはGitalyを介したGitコミット操作となる。

### Gitリポジトリへの書き込み

| 操作 | Git操作 | 備考 |
|-----|---------|------|
| 新規作成 | ファイル追加 + コミット | ファイルパス: `{slug}.{format拡張子}` |
| 更新 | ファイル更新 + コミット | |
| タイトル変更 | ファイル名変更 + コミット | |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG001 | 成功 | Wiki page was successfully created. | 新規作成成功時 |
| MSG002 | 成功 | Wiki page was successfully updated. | 更新成功時 |
| MSG003 | 成功 | Sidebar was successfully created. | サイドバー作成時 |
| MSG004 | 成功 | Sidebar was successfully updated. | サイドバー更新時 |
| MSG005 | エラー | Title can't be blank | タイトル未入力時 |
| MSG006 | エラー | exceeds the limit of X bytes | タイトル長超過時 |
| MSG007 | エラー | 'X' is a reserved name | 予約語使用時 |
| MSG008 | エラー | is too long (X). The maximum size is Y. | コンテンツサイズ超過時 |
| MSG009 | エラー | There is already a page with the same title in that path. | 同名ページ存在時（リネーム時） |
| MSG010 | エラー | Someone edited the page the same time you did. | 楽観的ロック違反時 |

## 例外処理

| 例外条件 | 画面表示・動作 |
|----------|---------------|
| ページが存在しない（編集時） | 404エラーまたは作成フォームを表示 |
| 編集権限がない | 403 Forbiddenエラー |
| バリデーションエラー | フォーム上にエラーメッセージを表示 |
| 楽観的ロック違反 | 競合エラーメッセージを表示、ページへのリンクを提供 |
| 非UTF-8エンコーディング | 編集画面にリダイレクト、警告表示 |
| Gitタイムアウト | Git error画面を表示 |
| サイドバー作成（title = _sidebar） | Wiki一覧へリダイレクト |

## 備考

- 予約語：pages, templates, new, git_access, - はトップレベルのページタイトルとして使用不可
- テンプレート：`templates/` ディレクトリ配下のページがテンプレートとして利用可能
- サイドバー：タイトル `_sidebar` でサイドバーを作成・編集可能
- Front Matter：YAMLフォーマットでページメタデータを指定可能
- 最大コンテンツサイズ：`Gitlab::CurrentSettings.wiki_page_max_content_bytes` で設定

---

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

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

### 推奨読解順序

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

WikiPageモデルとバリデーションを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | wiki_page.rb | `app/models/wiki_page.rb` | バリデーション、create/updateメソッド |

**読解のコツ**: `validate` メソッドでバリデーションルール、`RESERVED_SLUGS` で予約語を確認する。

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

コントローラーとConcernの処理フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | wiki_actions.rb | `app/controllers/concerns/wiki_actions.rb` | edit, create, updateアクション |
| 2-2 | edit.html.haml | `app/views/shared/wikis/edit.html.haml` | ビューテンプレートの構造 |

**主要処理フロー**:
1. **行74-83**: `new` アクションでランダムUUIDページへリダイレクト
2. **行216-219**: `edit` アクションでテンプレート一覧を取得
3. **行222-240**: `update` アクションで更新処理
4. **行244-257**: `create` アクションで作成処理

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

作成・更新のビジネスロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create_service.rb | `app/services/wiki_pages/create_service.rb` | 作成ビジネスロジック |
| 3-2 | update_service.rb | `app/services/wiki_pages/update_service.rb` | 更新ビジネスロジック |

#### Step 4: フロントエンドを理解する

Vue.jsコンポーネントとエディタ実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | edit.html.haml | `app/views/shared/wikis/edit.html.haml` | Vue.jsマウントポイント |

**主要データ属性**（行7-18）:
- `page_info`: ページ情報JSON
- `is_page_template`: テンプレートフラグ
- `format_options`: 利用可能なマークアップ形式
- `templates`: テンプレート一覧

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

```
WikiActions#edit/create/update (Concern)
    │
    ├─ before_action :authorize_create_wiki!
    │
    ├─ edit
    │      ├─ @templates = templates_list
    │      └─ render 'shared/wikis/edit'
    │             └─ #js-vue-wiki-edit-app (Vue.js)
    │
    ├─ create
    │      └─ WikiPages::CreateService.new.execute
    │             ├─ WikiPage#create
    │             │      └─ wiki.create_page (Git操作)
    │             └─ handle_action_success
    │
    └─ update
           ├─ 楽観的ロックチェック
           └─ WikiPages::UpdateService.new.execute
                  ├─ WikiPage#update
                  │      └─ wiki.update_page (Git操作)
                  └─ handle_action_success
```

### データフロー図

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

フォーム入力データ ───▶ WikiActions#create/update
(title, content,          │
format, message)          ▼
                    WikiPages::CreateService
                    WikiPages::UpdateService
                          │
                          ▼
                    WikiPage#create/update
                          │
                          ▼
                    wiki.create_page / wiki.update_page
                          │
                          ▼
                    Gitaly (Git操作) ───▶ Wiki表示画面
                          │
                          ▼
                    events (DB) ───▶ アクティビティログ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| edit.html.haml | `app/views/shared/wikis/edit.html.haml` | テンプレート | 編集画面のビュー |
| wiki_actions.rb | `app/controllers/concerns/wiki_actions.rb` | Concern | Wiki関連アクション |
| wiki_page.rb | `app/models/wiki_page.rb` | モデル | WikiPageモデル |
| create_service.rb | `app/services/wiki_pages/create_service.rb` | サービス | 作成ビジネスロジック |
| update_service.rb | `app/services/wiki_pages/update_service.rb` | サービス | 更新ビジネスロジック |
| front_matter_parser.rb | `lib/gitlab/wiki_pages/front_matter_parser.rb` | ライブラリ | Front Matter解析 |
| wikis_helper.rb | `app/helpers/wikis_helper.rb` | ヘルパー | Wikiヘルパーメソッド |
