# 帳票設計書 1-StreamedResponse

## 概要

本ドキュメントは、Laravel FrameworkにおけるStreamedResponse（ストリーミングレスポンス）機能の設計仕様を定義する。ストリーミング形式でファイルをダウンロードするための帳票出力機能であり、大容量ファイルの出力に適している。

### 本帳票の処理概要

StreamedResponseは、HTTPレスポンスをストリーミング形式で出力する機能を提供する。従来のレスポンス方式ではファイル全体をメモリに読み込む必要があるが、StreamedResponseではデータをチャンク単位で逐次出力することで、メモリ使用量を大幅に削減できる。

**業務上の目的・背景**：大容量のCSVファイルやログファイル、レポートデータなどをユーザーにダウンロードさせる際に、サーバーのメモリ制限を超えることなく安定した出力を実現する必要がある。特に数十MB〜数GBに及ぶデータエクスポート処理において、従来のバッファリング方式ではメモリ不足エラーが発生するリスクがあり、ストリーミング出力によってこの問題を解決する。

**帳票の利用シーン**：
- 大量のデータベースレコードをCSV形式でエクスポートする場合
- ログファイルのリアルタイムダウンロード
- 動的に生成される大容量レポートの出力
- バッチ処理結果の即座ダウンロード

**主要な出力内容**：
1. HTTPストリーミングレスポンスヘッダーの設定
2. コールバック関数によるデータのチャンク出力
3. ジェネレータ対応による効率的なメモリ管理
4. Laravel Octane環境での最適化されたストリーミング

**帳票の出力タイミング**：ResponseFactory::stream()メソッドの呼び出し時、またはコントローラーからStreamedResponseインスタンスを返却した時点でストリーミング出力が開始される。

**帳票の利用者**：アプリケーション開発者、システム管理者、データ分析担当者

## 帳票種別

ストリーミングレスポンス / データエクスポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | 任意の画面 | 開発者定義 | Response::stream()呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | 任意（CSV / JSON / TXT等） |
| 用紙サイズ | - |
| 向き | - |
| ファイル名 | Content-Dispositionヘッダーで指定可能 |
| 出力方法 | HTTPストリーミングダウンロード |
| 文字コード | 開発者指定（デフォルトUTF-8） |

### ストリーミング固有設定

| 項目 | 内容 |
|-----|------|
| X-Accel-Buffering | ジェネレータ使用時は'no'に設定 |
| バッファリング | ob_flush() + flush()による即時出力 |
| Octane対応 | LARAVEL_OCTANE環境変数で判定 |

## 帳票レイアウト

### レイアウト概要

StreamedResponseはバイナリストリームとして出力されるため、固定のレイアウト構造は持たない。出力内容はコールバック関数内で開発者が定義する。

```
┌─────────────────────────────────────┐
│          HTTPヘッダー部              │
├─────────────────────────────────────┤
│          ストリームデータ             │
│       （チャンク単位で逐次出力）       │
│                                     │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Content-Type | MIMEタイプ | 開発者指定 | text/csv等 |
| 2 | Content-Disposition | ファイル名指定 | 開発者指定 | attachment; filename="xxx" |
| 3 | X-Accel-Buffering | バッファリング制御 | 自動設定 | no |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | ストリームデータ | 出力データ本体 | コールバック関数 | バイナリ/テキスト | - |

### フッター部

フッター部は特に定義されない。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| callback | ストリーム出力を行うコールバック関数またはジェネレータ | Yes |
| status | HTTPステータスコード | No（デフォルト: 200） |
| headers | 追加HTTPヘッダー | No |

### ソート順

開発者がコールバック関数内で制御する。

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | - | - |

### 改ページ条件

ストリーミングレスポンスには改ページの概念は適用されない。

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

### 参照テーブル一覧

StreamedResponse自体はデータベースを参照しない。コールバック関数内で開発者が任意のテーブルを参照可能。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| - | - | - |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| - | - | - | コールバック内で開発者が定義 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[stream()メソッド呼び出し] --> B{コールバックはジェネレータ?}
    B -->|Yes| C{Octane環境?}
    B -->|No| D[通常のStreamedResponse生成]
    C -->|Yes| E[X-Accel-Buffering:no設定]
    C -->|No| F[ジェネレータラッパー生成]
    E --> G[StreamedResponse返却]
    F --> H[チャンク出力ループ]
    H --> I[ob_flush/flush実行]
    I --> G
    D --> G
    G --> J[クライアントへストリーミング]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| メモリ不足 | 大量データ一括処理 | PHP Fatal error: Allowed memory size exhausted | ジェネレータを使用する |
| 出力バッファエラー | ob_get_level()が0の場合 | - | バッファリング設定を確認 |
| タイムアウト | 長時間処理 | Maximum execution time exceeded | set_time_limit()で調整 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 制限なし（ストリーミングのため） |
| 目標出力時間 | データ量に依存（即時開始） |
| 同時出力数上限 | サーバーリソースに依存 |

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

- 出力データに個人情報が含まれる場合は、認証・認可を適切に実装すること
- Content-Dispositionヘッダーのファイル名にユーザー入力を使用する場合は、パストラバーサル対策が必要
- 大量データ出力時は、DDoS対策としてレート制限を検討すること

## 備考

- Laravel Octane環境では、ジェネレータ使用時に自動的にX-Accel-Bufferingヘッダーが設定される
- Symfony\Component\HttpFoundation\StreamedResponseを継承・利用している

---

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

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

### 推奨読解順序

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

StreamedResponseはSymfony HttpFoundationコンポーネントのクラスを使用しているため、まずSymfonyのStreamedResponseの基本構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | StreamedResponse.php | `vendor/symfony/http-foundation/StreamedResponse.php` | StreamedResponseの基本実装を理解する |

**読解のコツ**: Symfonyのコンポーネントとして提供されているため、Laravelの実装はこれをラップする形になっている。

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

処理の起点となるResponseFactoryのstream()メソッドを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ResponseFactory.php | `src/Illuminate/Routing/ResponseFactory.php` | stream()メソッドの実装を確認 |

**主要処理フロー**:
1. **行194-213**: stream()メソッドの実装
2. **行196**: コールバックがジェネレータかどうかをReflectionFunctionで判定
3. **行197-200**: Octane環境でのジェネレータ処理
4. **行203-209**: 通常環境でのジェネレータラッパー処理
5. **行212**: 通常のStreamedResponse生成

#### Step 3: コントラクトインターフェースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ResponseFactory.php | `src/Illuminate/Contracts/Routing/ResponseFactory.php` | stream()メソッドのインターフェース定義 |

**主要処理フロー**:
- **行60-68**: stream()メソッドのインターフェース定義

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

```
ResponseFactory::stream()
    │
    ├─ ReflectionFunction::isGenerator()
    │      └─ ジェネレータ判定
    │
    ├─ [Octane環境] StreamedResponse::setCallback()
    │
    └─ [通常環境] new StreamedResponse()
           ├─ foreach ($callback() as $chunk)
           │      └─ echo $chunk
           ├─ ob_flush()
           └─ flush()
```

### データフロー図

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

コールバック関数 ───▶ ResponseFactory     ───▶ HTTPレスポンス
または                  ::stream()              (ストリーミング)
ジェネレータ                │
                           ▼
                     StreamedResponse
                           │
                           ▼
                     チャンク出力ループ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ResponseFactory.php | `src/Illuminate/Routing/ResponseFactory.php` | ソース | ストリームレスポンス生成の実装 |
| ResponseFactory.php | `src/Illuminate/Contracts/Routing/ResponseFactory.php` | ソース | インターフェース定義 |
| Response.php | `src/Illuminate/Support/Facades/Response.php` | ソース | Facadeクラス |
| StreamedResponse.php | `vendor/symfony/http-foundation/StreamedResponse.php` | ソース | Symfony基底クラス |
