# 帳票設計書 1-Issue CSV Export

## 概要

本ドキュメントは、GitLabのプロジェクトにおけるIssue一覧をCSV形式でエクスポートする機能の帳票設計書である。

### 本帳票の処理概要

本帳票は、プロジェクト内のIssue情報を一括でCSVファイルとして出力し、外部ツールでの分析やバックアップ、レポート作成に活用するための機能を提供する。

**業務上の目的・背景**：プロジェクト管理において、Issue情報を外部のスプレッドシートツール（Excel、Google Sheets等）で分析したい場合や、定期的なレポート作成、監査目的でのデータ保存が必要な場合に、この機能が活用される。また、GitLab外部のステークホルダーへの進捗報告にも使用される。

**帳票の利用シーン**：プロジェクトマネージャーがスプリントレビュー用のレポートを作成する際、品質管理担当者がIssueの傾向分析を行う際、監査担当者がプロジェクト履歴のエビデンスを取得する際などに利用される。

**主要な出力内容**：
1. Issue基本情報（Title、Description、Issue ID、URL、State）
2. 担当者情報（Author、Author Username、Assignee、Assignee Username）
3. 日時情報（Created At、Updated At、Closed At、Due Date）
4. メタデータ（Confidential、Locked、Milestone、Weight、Labels）
5. 時間管理情報（Time Estimate、Time Spent）

**帳票の出力タイミング**：ユーザーがプロジェクトのIssue一覧画面から「Export as CSV」ボタンをクリックした際に非同期で処理が開始され、完了後にメールで送信される。

**帳票の利用者**：プロジェクトメンバー、プロジェクトマネージャー、品質管理担当者、監査担当者

## 帳票種別

一覧表（CSVエクスポート）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Project Issues | `/:namespace/:project/-/issues` | "Export as CSV"ボタン |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | CSV |
| 用紙サイズ | - |
| 向き | - |
| ファイル名 | issues_export.csv |
| 出力方法 | メール送付 |
| 文字コード | UTF-8 |

### CSV固有設定

| 項目 | 内容 |
|-----|------|
| ヘッダー行 | あり |
| 区切り文字 | カンマ |
| 囲み文字 | ダブルクォート |
| 最大ファイルサイズ | 15MB（Base64エンコード前） |

## 帳票レイアウト

### レイアウト概要

CSVファイルはヘッダー行と明細行で構成される。各行は20項目のカラムを持つ。

```
┌─────────────────────────────────────┐
│         ヘッダー行（1行目）           │
├─────────────────────────────────────┤
│         明細行（2行目以降）           │
│         （Issue毎に1行）             │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Title | Issueのタイトル | issues.title | 文字列 |
| 2 | Description | Issueの説明 | issues.description | 文字列 |
| 3 | Issue ID | Issue IID | issues.iid | 数値 |
| 4 | URL | IssueのURL | GitlabRoutingHelper | URL文字列 |
| 5 | State | Issueの状態 | issues.state_id | Open/Closed |
| 6 | Author | 作成者名 | users.name | 文字列 |
| 7 | Author Username | 作成者ユーザー名 | users.username | 文字列 |
| 8 | Assignee | 担当者名 | assignees.name | カンマ区切り文字列 |
| 9 | Assignee Username | 担当者ユーザー名 | assignees.username | カンマ区切り文字列 |
| 10 | Confidential | 機密フラグ | issues.confidential | Yes/No |
| 11 | Locked | ディスカッションロック | issues.discussion_locked | Yes/No |
| 12 | Due Date | 期限日 | issues.due_date | 日付（CSV形式） |
| 13 | Created At (UTC) | 作成日時 | issues.created_at | 日時（CSV形式） |
| 14 | Updated At (UTC) | 更新日時 | issues.updated_at | 日時（CSV形式） |
| 15 | Closed At (UTC) | クローズ日時 | issues.closed_at | 日時（CSV形式） |
| 16 | Milestone | マイルストーン名 | milestones.title | 文字列 |
| 17 | Weight | 重み | issues.weight | 数値 |
| 18 | Labels | ラベル一覧 | labels.title | カンマ区切り文字列 |
| 19 | Time Estimate | 見積時間 | issues.time_estimate | 秒数 |
| 20 | Time Spent | 作業時間 | timelogs.time_spent合計 | 秒数 |

### 明細部

各Issueごとに1行を出力。出力順はリクエスト時のフィルタ条件に基づく。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| プロジェクト | 対象プロジェクト | Yes |
| フィルタ条件 | Issue一覧画面のフィルタ条件を継承 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | リクエスト時の指定 | 画面のソート順を継承 |

### 改ページ条件

CSVのため改ページなし

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| issues | Issue基本情報 | 主テーブル |
| users (author) | 作成者情報 | issues.author_id = users.id |
| issue_assignees | 担当者関連 | issues.id = issue_assignees.issue_id |
| users (assignees) | 担当者情報 | issue_assignees.user_id = users.id |
| milestones | マイルストーン情報 | issues.milestone_id = milestones.id |
| label_links | ラベル関連 | issues.id = label_links.target_id |
| labels | ラベル情報 | label_links.label_id = labels.id |
| timelogs | 時間記録 | issues.id = timelogs.issue_id |
| work_item_types | Work Item種別 | issues.work_item_type_id = work_item_types.id |
| projects | プロジェクト情報 | issues.project_id = projects.id |
| namespaces | ネームスペース情報 | projects.namespace_id = namespaces.id |
| routes | ルート情報 | namespaces.id = routes.source_id |

### テーブル別参照項目詳細

#### issues

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| title | Title | - | - |
| description | Description | - | - |
| iid | Issue ID | - | プロジェクト内の連番 |
| confidential | Confidential | - | Boolean→Yes/No変換 |
| discussion_locked | Locked | - | Boolean→Yes/No変換 |
| due_date | Due Date | - | 日付形式変換 |
| created_at | Created At (UTC) | - | 日時形式変換 |
| updated_at | Updated At (UTC) | - | 日時形式変換 |
| closed_at | Closed At (UTC) | - | 日時形式変換 |
| weight | Weight | - | EE機能 |
| time_estimate | Time Estimate | - | 秒数 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| Time Spent | SUM(timelogs.time_spent) | - | 関連タイムログの合計 |
| Labels | labels.sort.join(',') | - | ソート済みラベルのカンマ区切り結合 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Export as CSVボタンクリック] --> B[export_csvアクション呼び出し]
    B --> C[IssuableExportCsvWorker.perform_async]
    C --> D[非同期ワーカー起動]
    D --> E[Issues::ExportCsvService.new]
    E --> F[IssuesFinder で対象Issue取得]
    F --> G[csv_builder.render でCSV生成]
    G --> H[CsvBuilder バッチ処理]
    H --> I{ファイルサイズ確認}
    I -->|15MB以下| J[Notify.issues_csv_email]
    I -->|15MB超過| K[処理中断]
    J --> L[メール送信]
    L --> M[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| データなし | 対象Issueが0件 | - | 空のCSVが送信される |
| ファイルサイズ超過 | 15MB超過 | 処理が途中で打ち切られる | フィルタ条件を絞る |
| 権限エラー | プロジェクトへのアクセス権がない | 認証エラー画面 | 権限を確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数千〜数万件 |
| 目標出力時間 | 非同期処理のため制限なし |
| 同時出力数上限 | Sidekiqワーカーの並列数に依存 |

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

- 認証済みユーザーのみがエクスポート可能（`authenticate_user!`）
- プロジェクトへの読み取り権限が必要
- 機密Issue（confidential）も出力対象となるため、アクセス権限のあるユーザーのみに送信
- メールは登録済みメールアドレスにのみ送信

## 備考

- 本機能はEE版で`Issues::ExportCsvService.prepend_mod_with`によって拡張される可能性がある
- Feature Flagの`export_csv_preload_in_batches`によりプリロード方式が切り替わる

---

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

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

### 推奨読解順序

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

CSV出力のカラム定義とデータ取得方法を理解することが最初のステップ。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | export_csv_service.rb | `app/services/issues/export_csv_service.rb` | header_to_value_hashでCSVカラム定義を確認（31-53行目） |

**読解のコツ**: `header_to_value_hash`のHashは、キーがCSVヘッダー名、値が取得方法（文字列の場合はメソッド名、ラムダの場合は動的計算）を示す。

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

ユーザー操作からの処理開始点を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | issues_controller.rb | `app/controllers/projects/issues_controller.rb` | export_csvアクション（272-279行目） |

**主要処理フロー**:
1. **272行目**: `export_csv`アクション定義
2. **273行目**: `IssuableExportCsvWorker.perform_async`で非同期処理をキュー
3. **275-278行目**: リダイレクトとフラッシュメッセージ表示

#### Step 3: 非同期ワーカーを理解する

Sidekiqワーカーの処理フローを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | issuable_export_csv_worker.rb | `app/workers/issuable_export_csv_worker.rb` | ワーカーのperformメソッド |

#### Step 4: CSV生成サービスを理解する

CSVデータ生成の詳細ロジックを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | base_service.rb | `app/services/export_csv/base_service.rb` | csv_builderの生成とrender呼び出し（14-16行目） |
| 4-2 | export_csv_service.rb | `app/services/issues/export_csv_service.rb` | Issue固有のカラム定義とプリロード設定 |

**主要処理フロー**:
- **14-16行目**: `csv_data`メソッドでCSVBuilder経由のレンダリング
- **31-54行目**: `header_to_value_hash`でカラム定義

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

```
Projects::IssuesController#export_csv
    │
    ├─ IssuableExportCsvWorker.perform_async
    │      │
    │      └─ Issues::ExportCsvService.new
    │             │
    │             ├─ ExportCsv::BaseService (継承)
    │             │      └─ CsvBuilder.new
    │             │             └─ render (CSV生成)
    │             │
    │             └─ email
    │                    └─ Notify.issues_csv_email
```

### データフロー図

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

Issue一覧画面 ───▶ IssuesController ───▶ IssuableExportCsvWorker
    │                                          │
    │                                          ▼
    │                                 Issues::ExportCsvService
    │                                          │
    │                                          ▼
    │                                    CsvBuilder.render
    │                                          │
    │                                          ▼
    └──────────────────────────────────▶ Notify.issues_csv_email
                                               │
                                               ▼
                                          ユーザーメール
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| export_csv_service.rb | `app/services/issues/export_csv_service.rb` | ソース | Issue CSV生成サービス |
| base_service.rb | `app/services/export_csv/base_service.rb` | ソース | CSV生成基底クラス |
| issues_controller.rb | `app/controllers/projects/issues_controller.rb` | ソース | コントローラー |
| issuable_export_csv_worker.rb | `app/workers/issuable_export_csv_worker.rb` | ソース | 非同期ワーカー |
| csv_builder.rb | `lib/csv_builder.rb` | ソース | CSV構築ユーティリティ |
| notify.rb | `app/mailers/notify.rb` | ソース | メール送信 |
