# 機能設計書 125-コントリビューションアナリティクス

## 概要

本ドキュメントは、GitLabにおけるコントリビューションアナリティクス機能の設計仕様を記述したものである。本機能は、リポジトリへのコミット統計を可視化し、開発チームの貢献度やコミットパターンを分析するためのダッシュボードを提供する。

### 本機能の処理概要

**業務上の目的・背景**：ソフトウェア開発プロジェクトにおいて、チームの開発活動を定量的に把握することは、プロジェクト管理やリソース配分の最適化に不可欠である。コントリビューションアナリティクスは、コミット履歴を分析し、コントリビューター数、コミット頻度、言語構成比などの統計情報を提供することで、プロジェクトの健全性評価や開発傾向の把握を支援する。

**機能の利用シーン**：プロジェクトのAnalyticsメニューから「Repository analytics」を選択した際に表示される。プロジェクトの開発活動を振り返る場面、チームの貢献度を評価する場面、コードベースの言語構成を確認する場面などで利用される。

**主要な処理内容**：
1. リポジトリからコミット履歴の取得
2. コミット統計の集計（曜日別、時間帯別、月別）
3. コントリビューター数の算出
4. プログラミング言語構成比の取得
5. コードカバレッジ情報の取得（Daily Build Group Report Results）
6. グラフ・チャートの生成

**関連システム・外部連携**：Gitalyサービスを介してGitリポジトリにアクセス。CI/CDパイプラインのカバレッジ結果との連携。Snowplowへの分析イベント送信（p_analytics_repo）。

**権限による制御**：リポジトリグラフの閲覧権限（authorize_read_repository_graphs!）が必要。プロジェクトへの読み取りアクセス権が前提。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 45 | 貢献者グラフ | 主画面 | リポジトリ貢献者統計の表示 |

## 機能種別

データ取得・分析（READ操作）/ 統計グラフ表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ref | String | No | 分析対象ブランチ/タグ | リポジトリに存在するref |
| namespace_id | String | Yes | プロジェクトの名前空間 | 有効な名前空間 |
| project_id | String | Yes | プロジェクトID | 有効なプロジェクト |

### 入力データソース

- Gitリポジトリ（コミット履歴）
- repository_languages テーブル（言語構成）
- ci_daily_build_group_report_results テーブル（カバレッジ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @commits | Array<Commit> | コミットオブジェクト配列 |
| @commits_graph | Gitlab::Graphs::Commits | コミット統計グラフデータ |
| @commits_per_week_days | Hash | 曜日別コミット数 |
| @commits_per_time | Hash | 時間帯別コミット数（0-23時） |
| @commits_per_month | Hash | 日別コミット数（1-31日） |
| @languages | Array<Hash> | 言語構成（value, label, color, highlight） |
| @daily_coverage_options | Hash | カバレッジグラフ設定 |

### 出力先

- HTML画面（チャートダッシュボード）
- JSON API（コミットログデータ）

## 処理フロー

### 処理シーケンス

```
1. 認証・権限チェック
   └─ require_non_empty_project
   └─ authorize_read_repository_graphs!
2. ref変数の設定
   └─ assign_ref_vars
3. chartsアクション実行
   └─ get_commits: コミット取得・統計計算
   └─ get_languages: 言語構成取得
   └─ get_daily_coverage_options: カバレッジ設定取得
4. 分析イベント追跡
   └─ track_event (p_analytics_repo)
5. レスポンス生成
   └─ HTML/JSON形式で返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{非空リポジトリ?}
    B -->|No| C[リダイレクト]
    B -->|Yes| D{権限チェック}
    D -->|No| E[403 Forbidden]
    D -->|Yes| F[ref変数設定]
    F --> G[コミット取得]
    G --> H{コミット数確認}
    H -->|MAX_COMMITS超過| I[制限適用]
    H -->|制限内| J[統計計算]
    I --> J
    J --> K[言語構成取得]
    K --> L[カバレッジ設定取得]
    L --> M[イベント追跡]
    M --> N[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-125-01 | コミット数制限 | showアクションではMAX_COMMITS=6000件まで取得 | showアクション |
| BR-125-02 | チャート用制限 | chartsアクションではcommits_limit=2000件まで取得 | chartsアクション |
| BR-125-03 | マージコミット除外 | skip_merges: trueでマージコミットを除外 | 常時 |
| BR-125-04 | カバレッジ期間 | 過去90日間のカバレッジデータを表示 | カバレッジ表示時 |

### 計算ロジック

**曜日別コミット数**:
```ruby
commits_per_week_days = {}
Date::DAYNAMES.each { |day| commits_per_week_days[day] = 0 }
commits.each { |c| commits_per_week_days[c.committed_date.strftime('%A')] += 1 }
```

**時間帯別コミット数**:
```ruby
commits_per_time = {}
(0..23).each { |hour| commits_per_time[hour] = 0 }
commits.each { |c| commits_per_time[c.committed_date.strftime('%k').to_i] += 1 }
```

**コミット/日平均**:
```ruby
commit_per_day = (commits.size.to_f / (duration + 1)).round(1)
# duration = end_date - start_date
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 言語取得 | repository_languages | SELECT | プロジェクトの言語構成 |
| カバレッジ取得 | ci_daily_build_group_report_results | SELECT | 日次カバレッジ結果 |

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

#### repository_languages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | project_id, programming_language_id, share | project_id = @project.id | Projects::RepositoryLanguagesService経由 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | Not Found | 空リポジトリへのアクセス | プロジェクトトップへリダイレクト |
| 403 | Forbidden | 権限不足 | アクセス拒否画面表示 |

### リトライ仕様

Gitalyタイムアウト時は標準的なリトライ機構に従う。

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

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

## パフォーマンス要件

- urgency: low
- コミット取得は最大6000件に制限
- 言語取得は非同期で実行可能（RepositoryLanguagesService）

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

- リポジトリ読み取り権限の確認
- 非公開リポジトリはメンバーのみアクセス可能
- Gitリポジトリへの直接アクセスはGitaly経由

## 備考

- commits/languagesアクションはchartsへリダイレクト（レガシー対応）
- ciアクションはcharts_project_pipelines_pathへリダイレクト
- EE版で追加の分析機能が提供される可能性あり

---

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

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

### 推奨読解順序

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

コミット統計の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Gitlab::Graphs::Commits | `lib/gitlab/graphs/commits.rb` | コミット統計グラフの構造 |

**読解のコツ**:
- **9-13行目**: インスタンス変数（commits_per_week_days等）の定義
- **26-47行目**: collect_dataメソッドでの統計計算ロジック

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Projects::GraphsController | `app/controllers/projects/graphs_controller.rb` | charts/showアクションの処理フロー |

**主要処理フロー**:
1. **7-10行目**: before_actionでの前提条件チェック
2. **24行目**: MAX_COMMITS = 6000の定義
3. **26-44行目**: showアクション - HTML/JSON分岐とコミットログ取得
4. **54-58行目**: chartsアクション - 統計データ取得
5. **70-77行目**: get_commitsメソッド - コミット取得と統計計算
6. **79-84行目**: get_languagesメソッド - 言語構成取得

#### Step 3: 言語取得処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Projects::RepositoryLanguagesService | `app/services/projects/repository_languages_service.rb` | 言語構成取得ロジック |

#### Step 4: カバレッジ取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | get_daily_coverage_options | `app/controllers/projects/graphs_controller.rb` (86-109行目) | カバレッジオプション設定 |
| 4-2 | Ci::DailyBuildGroupReportResultsFinder | `app/finders/ci/daily_build_group_report_results_finder.rb` | カバレッジデータ検索 |

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

```
Projects::GraphsController
    │
    ├─ show (action)
    │      └─ @project.repository.commits(ref, limit: MAX_COMMITS)
    │
    └─ charts (action)
           │
           ├─ get_commits
           │      ├─ repository.commits(ref, limit: 2000)
           │      └─ Gitlab::Graphs::Commits.new(@commits)
           │             ├─ commits_per_week_days
           │             ├─ commits_per_time
           │             └─ commits_per_month
           │
           ├─ get_languages
           │      └─ Projects::RepositoryLanguagesService.new(@project).execute
           │
           └─ get_daily_coverage_options
                  └─ Ci::DailyBuildGroupReportResultsFinder (参照用パス生成のみ)
```

### データフロー図

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

Git Repository ─────────▶ Projects::GraphsController ───────▶ HTML View
                               │
ref parameter ─────────────────┤
                               │
                         ┌─────┴─────┐
                         │           │
                   repository    database
                         │           │
                    commits    repository_languages
                         │           │
               Gitlab::Graphs::Commits  │
                         │           │
                   ┌─────┴─────┐     │
                   │     │     │     │
              per_week per_time per_month
                   │     │     │     │
                   └─────┼─────┘     │
                         │           │
                         ▼           ▼
                    @commits_graph  @languages
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Projects::GraphsController | `app/controllers/projects/graphs_controller.rb` | コントローラー | エントリーポイント |
| Gitlab::Graphs::Commits | `lib/gitlab/graphs/commits.rb` | ライブラリ | コミット統計計算 |
| Projects::RepositoryLanguagesService | `app/services/projects/repository_languages_service.rb` | サービス | 言語構成取得 |
| Ci::DailyBuildGroupReportResultsFinder | `app/finders/ci/daily_build_group_report_results_finder.rb` | ファインダー | カバレッジデータ検索 |
| ExtractsPath | `app/controllers/concerns/extracts_path.rb` | Concern | ref変数抽出 |
| ProductAnalyticsTracking | `app/controllers/concerns/product_analytics_tracking.rb` | Concern | 分析イベント追跡 |
| RepositoryLanguage | `app/models/repository_language.rb` | モデル | 言語構成データ |
