# 機能設計書 68-Wiki閲覧

## 概要

本ドキュメントは、GitLabにおけるWiki閲覧機能の設計仕様を記載する。プロジェクトやグループに紐づくWikiドキュメントを閲覧・検索する機能であり、Markdown、AsciiDoc、RDocなど複数のマークアップ形式に対応している。

### 本機能の処理概要

Wiki閲覧機能は、Gitリポジトリとして管理されるWikiコンテンツをWeb UIから閲覧可能にする機能である。ページの一覧表示、個別ページの表示、ファイルの表示、履歴の閲覧、バージョン間の差分表示などを提供する。

**業務上の目的・背景**：プロジェクトのドキュメンテーションを効率的に管理・共有するためにWiki機能は重要である。本機能により、開発者やユーザーはプロジェクトに関連するドキュメントを簡単に参照でき、ナレッジの共有と蓄積が促進される。

**機能の利用シーン**：
- プロジェクトドキュメントの閲覧
- ページ一覧からの目的のページ検索
- サイドバーによるナビゲーション
- ページの履歴・バージョン確認
- 特定バージョンのページ表示
- 添付ファイルの表示・ダウンロード

**主要な処理内容**：
1. Wikiページ一覧の取得・表示
2. 個別ページの取得・マークアップレンダリング
3. サイドバー（_sidebar）の取得・表示
4. ページ履歴（コミット履歴）の取得
5. バージョン間の差分表示
6. ファイル（画像等）の配信

**関連システム・外部連携**：
- Gitaly（Wikiリポジトリ操作）
- Gitリポジトリ（Wikiストレージ）
- マークアップレンダラー（Markdown、AsciiDoc等）

**権限による制御**：
- `read_wiki`権限：Wiki閲覧
- `read_wiki_page`権限：個別ページ閲覧
- `create_wiki`権限：Wiki作成・編集（閲覧には不要）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | Wiki一覧 | 主機能 | ページ一覧表示 |
| - | Wikiページ表示 | 主機能 | 個別ページ表示 |
| - | Wiki履歴 | 副機能 | ページ履歴表示 |
| - | Wiki差分 | 副機能 | バージョン差分表示 |

## 機能種別

コンテンツ表示 / ドキュメント管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | String | No | ページスラッグ（URLパス） | - |
| version_id | String | No | 表示するバージョン（コミットSHA） | - |
| direction | String | No | ソート方向（asc/desc） | デフォルト: asc |
| page | Integer | No | ページ番号（ページネーション） | - |

### 入力データソース

- Wikiリポジトリ（Gitリポジトリ）
- URLパラメータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| title | String | ページタイトル |
| content | String | マークアップコンテンツ（レンダリング済み） |
| raw_content | String | 生のマークアップテキスト |
| format | Symbol | マークアップ形式（markdown, asciidoc等） |
| slug | String | URLスラッグ |
| path | String | ファイルパス |
| version | Object | バージョン情報（コミット） |
| historical | Boolean | 過去バージョンかどうか |

### 出力先

- Web UI（HTMLレンダリング）
- Raw形式（プレーンテキスト）
- ファイルダウンロード

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ 権限チェック（authorize_read_wiki!）
   └─ Wikiインスタンス取得

2. ページ検索
   └─ スラッグによるページ検索
   └─ バージョン指定時は特定コミットから取得
   └─ リダイレクト処理（.gitlab/redirects.yml）

3. コンテンツ取得
   └─ Gitalyからブロブ取得
   └─ フォーマット判定（拡張子から）
   └─ Front Matterパース

4. レンダリング
   └─ マークアップ→HTML変換
   └─ サイドバー読み込み

5. レスポンス返却
   └─ HTML表示
   └─ または生コンテンツ返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{read_wiki権限?}
    B -->|No| C[403 Forbidden]
    B -->|Yes| D[Wikiインスタンス取得]
    D --> E{ページ存在?}
    E -->|Yes| F[コンテンツ取得]
    E -->|No| G{ファイル存在?}
    G -->|Yes| H[ファイル送信]
    G -->|No| I{リダイレクト存在?}
    I -->|Yes| J[リダイレクト処理]
    I -->|No| K{作成フォーム表示?}
    K -->|Yes| L[編集フォーム表示]
    K -->|No| M{Wiki存在?}
    M -->|Yes| N[404表示]
    M -->|No| O[空Wiki表示]
    F --> P[マークアップレンダリング]
    P --> Q[HTML表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | サポートマークアップ | Markdown, RDoc, AsciiDoc, Org, Textile, Creole, reStructuredText, MediaWiki, Pod, Plain Textの10種類 | ページ作成・表示時 |
| BR-02 | ユーザー作成可能形式 | Markdown, RDoc, AsciiDoc, Orgの4種類のみユーザーが作成可能 | ページ作成時 |
| BR-03 | ホームページ | "home"がデフォルトのホームページスラッグ | Wiki初回アクセス時 |
| BR-04 | サイドバー | "_sidebar"がサイドバーページ | 全ページ表示時 |
| BR-05 | テンプレートディレクトリ | "templates/"配下はテンプレートとして扱う | ページ一覧時 |
| BR-06 | リダイレクト設定 | ".gitlab/redirects.yml"でリダイレクト定義 | ページ移動後 |
| BR-07 | 予約スラッグ | pages, templates, new, git_access, - は予約語 | ページ作成時 |
| BR-08 | タイトル最大バイト数 | 255バイト | ページ作成・更新時 |
| BR-09 | ディレクトリ名最大バイト数 | 255バイト | ページ作成・更新時 |

### 計算ロジック

- ページソート: タイトル順（path順）でソート
- Front Matter: YAMLフォーマットのメタデータ抽出
- フィンガープリント: `file_path:start_line:end_line`形式

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ページ閲覧 | - | - | DBアクセスなし（Git操作のみ） |
| メタ情報取得 | wiki_page_meta | SELECT | ページメタデータ取得 |
| 購読状態確認 | wiki_page_subscriptions | SELECT | 通知設定確認 |

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

#### wiki_page_meta

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id | slugで検索 | ページメタ情報 |
| SELECT | title | - | 正規化されたタイトル |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------
| 403 | Forbidden | read_wiki権限なし | 権限確認 |
| 404 | Not Found | ページが存在しない | 作成フォームまたは404表示 |
| - | Git Timeout | Gitaly操作タイムアウト | git_error画面表示 |
| - | NoRepository | Wikiリポジトリなし | empty画面表示 |
| - | Encoding Error | UTF-8以外のエンコーディング | 警告表示（編集不可） |

### リトライ仕様

Gitalyタイムアウト時はユーザーにエラー画面を表示し、手動でリトライを促す。

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

- Wiki閲覧はDBトランザクションを使用しない
- Git操作のみで完結

## パフォーマンス要件

- ページ一覧は件数制限なし（ページネーションで対応）
- コンテンツサイズ上限: `Gitlab::CurrentSettings.wiki_page_max_content_bytes`
- ブロブサイズ上限: `Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE`

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

- read_wiki権限による閲覧制御
- UTF-8以外のエンコーディングは表示のみ（編集不可）
- Content Security Policyでdiagrams.net埋め込み制御

## 備考

- Wikiはプロジェクト・グループの両方に紐付け可能
- feature_category: `wiki`
- Gitalyを使用したGit操作

---

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

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

### 推奨読解順序

#### Step 1: データモデルを理解する

Wikiの基本構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | wiki.rb | `app/models/wiki.rb` | Wikiモデルの基本構造 |
| 1-2 | wiki_page.rb | `app/models/wiki_page.rb` | Wikiページモデル |

**読解のコツ**:
- **wiki.rb 13-68行目**: MARKUPS定義 - サポートするマークアップ形式一覧
- **wiki.rb 70行目**: VALID_USER_MARKUPS - ユーザーが作成可能な形式
- **wiki.rb 78-86行目**: 定数定義（HOMEPAGE, SIDEBAR, TEMPLATES_DIR等）
- **wiki.rb 206-247行目**: list_pages - ページ一覧取得
- **wiki.rb 256-284行目**: find_page - ページ検索
- **wiki_page.rb 15-21行目**: RESERVED_SLUGS - 予約スラッグ
- **wiki_page.rb 140-152行目**: slug, human_title定義
- **wiki_page.rb 216-228行目**: versions - コミット履歴取得
- **wiki_page.rb 464-482行目**: validate_path_limits - パスバリデーション

#### Step 2: コントローラー層を理解する

Webリクエスト処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | wiki_actions.rb | `app/controllers/concerns/wiki_actions.rb` | Wiki共通アクション |

**主要処理フロー**:
- **13行目**: RESCUE_GIT_TIMEOUTS_IN - タイムアウト対象アクション
- **28-29行目**: before_action - 権限チェック
- **86-100行目**: pages - ページ一覧
- **122-147行目**: show - 個別ページ表示
- **149-184行目**: handle_redirection - リダイレクト処理
- **260-274行目**: history - 履歴表示
- **277-287行目**: diff - 差分表示
- **361-364行目**: load_sidebar - サイドバー読み込み
- **449-468行目**: find_redirection - リダイレクト検索

#### Step 3: ポリシー層を理解する

権限制御を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | wiki_policy.rb | `app/policies/wiki_policy.rb` | Wikiポリシー |
| 3-2 | wiki_page_policy.rb | `app/policies/wiki_page_policy.rb` | ページポリシー |

**主要処理フロー**:
- **wiki_policy.rb 5行目**: コンテナ（Project/Group）に委譲
- **wiki_page_policy.rb 10-15行目**: read_wiki権限による制御
- **wiki_page_policy.rb 22-24行目**: reporter/planner以上の権限

#### Step 4: GraphQL APIを理解する

GraphQL経由のアクセスを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | wiki_page_resolver.rb | `app/graphql/resolvers/wikis/wiki_page_resolver.rb` | ページリゾルバー |
| 4-2 | wiki_page_type.rb | `app/graphql/types/wikis/wiki_page_type.rb` | ページタイプ定義 |

**主要処理フロー**:
- **wiki_page_resolver.rb 12-20行目**: 引数定義（slug, project_id, namespace_id）
- **wiki_page_resolver.rb 22-37行目**: resolve - ページ取得
- **wiki_page_type.rb 13行目**: authorize :read_wiki
- **wiki_page_type.rb 17-25行目**: フィールド定義

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

```
HTTP Request
    │
    ├─ WikiActions#show / #pages / #history / #diff
    │      └─ authorize_read_wiki!
    │      └─ wiki (Wiki.for_container)
    │             └─ Wiki#find_page / #list_pages
    │                    └─ Gitaly RPC
    │                           └─ repository.blob_at
    │                           └─ repository.search_files_by_regexp
    │
    └─ GraphQL API
           └─ WikiPageResolver#resolve
                  └─ Wiki.for_container
                         └─ Wiki#find_page
                                └─ WikiPage.new
```

### データフロー図

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

URL Parameters ────▶ WikiActions (Controller) ────────▶ HTML View
(id, version_id)           │                              (shared/wikis/*)
                           │
                           ▼
                    Wiki Model
                           │
                           ▼
                    Gitaly RPC ─────────────────────▶ WikiPage
                    (blob_at, search)                 (title, content, format)
                           │
                           ▼
                    Markup Renderer ────────────────▶ Rendered HTML
                    (Markdown, AsciiDoc等)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| wiki.rb | `app/models/wiki.rb` | モデル | Wikiモデル |
| wiki_page.rb | `app/models/wiki_page.rb` | モデル | Wikiページモデル |
| wiki_directory.rb | `app/models/wiki_directory.rb` | モデル | ディレクトリ構造 |
| wiki_actions.rb | `app/controllers/concerns/wiki_actions.rb` | Concern | Wiki共通アクション |
| wikis_controller.rb | `app/controllers/projects/wikis_controller.rb` | コントローラー | プロジェクトWiki |
| wiki_policy.rb | `app/policies/wiki_policy.rb` | ポリシー | Wikiポリシー |
| wiki_page_policy.rb | `app/policies/wiki_page_policy.rb` | ポリシー | ページポリシー |
| wiki_helper.rb | `app/helpers/wiki_helper.rb` | ヘルパー | Wikiビューヘルパー |
| wiki_page_resolver.rb | `app/graphql/resolvers/wikis/wiki_page_resolver.rb` | GraphQL | ページリゾルバー |
| wiki_page_type.rb | `app/graphql/types/wikis/wiki_page_type.rb` | GraphQL | ページタイプ |
| project_wiki.rb | `app/models/project_wiki.rb` | モデル | プロジェクトWiki |
| has_wiki.rb | `app/models/concerns/has_wiki.rb` | Concern | Wiki所有Concern |
