# 画面設計書 27-feedback

## 概要

本ドキュメントは、Bun CLIの`bun feedback`コマンドの画面設計書です。`bun feedback`コマンドは、ユーザーがBunチームに直接フィードバックを送信するための対話型コマンドです。

### 本画面の処理概要

`bun feedback`コマンドは、ユーザーからのフィードバック（バグ報告、機能要望、一般的なコメント等）を収集し、Bunチームに送信するためのコマンドです。テキストメッセージ、ファイル添付、パイプ入力に対応しています。

**業務上の目的・背景**：オープンソースプロジェクトの品質向上には、ユーザーからのフィードバックが不可欠です。`bun feedback`はGitHub Issueを作成するよりも手軽にフィードバックを送信でき、システム情報（OS、アーキテクチャ、Bunバージョン等）も自動収集することで、問題の診断を容易にします。

**画面へのアクセス方法**：ターミナルで`bun feedback [メッセージ] [ファイル...]`コマンドを実行します。

**主要な操作・処理内容**：
1. コマンドライン引数の解析（--email, --help）
2. メールアドレスの取得（引数/保存値/gitconfig/対話入力）
3. フィードバック内容の取得（引数/ファイル/標準入力/対話入力）
4. システム情報の収集（プラットフォーム、アーキテクチャ、Bunバージョン等）
5. FormDataの作成とHTTP POSTリクエスト送信
6. 送信結果の表示

**画面遷移**：エントリーポイントの`bun`コマンドから直接アクセス。送信完了後はシェルに戻ります。

**権限による表示制御**：特にロールベースの権限制御はありません。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | フィードバック送信 | 主機能 | ユーザーフィードバックのBunチームへの送信 |

## 画面種別

コマンドライン対話型 / フィードバック送信

## URL/ルーティング

- コマンド: `bun feedback [メッセージ...] [ファイル...]`
- エイリアス: なし

## 入出力項目

| 項目名 | 項目種別 | 型 | 必須 | 説明 |
|--------|----------|-----|------|------|
| message | 位置引数 | string | 条件付き | フィードバックメッセージ（テキスト） |
| files | 位置引数 | string[] | 任意 | 添付ファイルパス |
| --email, -e | オプション | string | 条件付き | 連絡先メールアドレス |
| --help, -h | フラグ | boolean | 任意 | ヘルプ表示 |
| (stdin) | パイプ入力 | string | 条件付き | パイプ経由のフィードバック |

## 表示項目

| 項目名 | 表示条件 | 説明 |
|--------|----------|------|
| メールプロンプト | 対話モードでメール未設定時 | `? Email: <default@example.com>` |
| フィードバックプロンプト | 対話モードでメッセージ未入力時 | `? Share your feedback with Bun's team` |
| 添付ファイル一覧 | ファイル添付時 | `+ file1.txt, file2.log` |
| 送信成功メッセージ | 送信成功時 | `Feedback sent.` |
| 送信ID | 送信成功時 | `ID: {uuid}` |
| Thank Youバナー | 送信成功時 | `THANK YOU!` |

## イベント仕様

### 1-メールアドレス取得

フィードバック送信者のメールアドレスを取得します。

- **トリガー**: コマンド実行時
- **取得優先順序**:
  1. `--email`オプションで指定されたメール
  2. `$BUN_INSTALL/feedback`ファイルに保存されたメール
  3. `git config user.email`から取得したメール
  4. 対話プロンプトでの入力
- **検証**: `@`と`.`を含むかチェック
- **永続化**: 新規入力時は`$BUN_INSTALL/feedback`に保存

### 2-フィードバック内容取得

フィードバックメッセージとファイルを取得します。

- **トリガー**: メールアドレス取得後
- **取得方法**:
  - 位置引数からテキストメッセージを取得
  - 位置引数のファイルパスを解決し、内容を読み込み
  - 標準入力（パイプ）からテキストを読み込み
  - 対話プロンプトでメッセージ入力（上記が空の場合）
- **ファイルサイズ制限**: 1ファイルあたり最大10MB

### 3-システム情報収集

送信に含めるシステム情報を自動収集します。

- **トリガー**: フィードバック内容取得後
- **収集項目**:
  - `platform`: プラットフォーム名（linux/darwin/win32）
  - `arch`: アーキテクチャ（x64/arm64）
  - `bunRevision`: Bunのgitリビジョン
  - `bunVersion`: Bunのバージョン
  - `bunBuild`: ビルド名
  - `hardwareConcurrency`: 利用可能CPU数
  - `availableMemory`: 利用可能メモリ
  - `totalMemory`: 総メモリ
  - `osVersion`: OSバージョン
  - `osRelease`: OSリリース
  - `docker`: Dockerコンテナ内かどうか
  - `localIPSupport`: ローカルIPサポート（IPv4/IPv6）
  - `remoteIPSupport`: リモートIPサポート（IPv4/IPv6）
  - `remoteFilesystem`: リモートファイルシステム上か
  - `projectId`: gitリポジトリの最古コミットSHA

### 4-フィードバック送信

収集した情報をHTTP POSTで送信します。

- **トリガー**: システム情報収集後
- **処理内容**:
  - FormDataを構築
  - `https://bun.report/v1/feedback`（またはBUN_FEEDBACK_URL）にPOST
  - UUIDv7でトラッキングIDを生成

### 5-対話入力処理

TTY環境での対話入力を処理します。

- **トリガー**: TTY環境で対話入力が必要な場合
- **処理内容**:
  - メール入力: プレースホルダ付きの単一行入力
  - メッセージ入力: 複数行入力（Enterで送信、Shift+Enterで改行）
  - Ctrl+Cでキャンセル（終了コード130）

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

本コマンドはデータベースを使用しません。ファイルシステムへの書き込み（メール保存）とHTTPリクエストを行います。

### 操作別ファイル影響一覧

| 操作（イベント） | 対象ファイル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| メール永続化 | `$BUN_INSTALL/feedback` | CREATE/UPDATE | メールアドレスの保存 |

## メッセージ仕様

| メッセージ種別 | メッセージ内容 | 表示条件 |
|--------------|---------------|----------|
| 成功 | `Feedback sent.` | 送信成功時 |
| 情報 | `ID: {uuid}` | 送信成功時 |
| 情報 | `THANK YOU!` | 送信成功時 |
| プロンプト | `? Email:` | メール入力時 |
| プロンプト | `? Share your feedback with Bun's team` | メッセージ入力時 |
| ヒント | `(Enter to send, Shift+Enter for a newline)` | メッセージ入力時 |
| エラー | `Please provide a valid email address containing "@" and "."` | 無効なメール時 |
| エラー | `Unable to determine email automatically. Pass --email <address>.` | 非TTYでメール不明時 |
| エラー | `No feedback provided. Supply text, file paths, or pipe input.` | フィードバックが空の場合 |
| エラー | `Failed to send feedback ({status} {statusText}).` | HTTP送信エラー時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| 無効なメールアドレス | エラーメッセージを表示し再入力を促す（対話）または終了コード1で終了（非対話） |
| フィードバック内容が空 | エラーメッセージを表示し終了コード1で終了 |
| HTTP送信エラー | エラーメッセージとステータスを表示し終了コード1で終了 |
| ファイル読み込みエラー | ファイルをスキップしテキストとして処理 |
| Ctrl+C | 終了コード130で終了 |

## 備考

- 環境変数`BUN_FEEDBACK_URL`でフィードバック送信先URLをカスタマイズ可能
- ファイルは1ファイルあたり最大10MBまで（超過分は切り捨て）
- Dockerコンテナ内かどうかは`/.dockerenv`の存在で判定
- リモートファイルシステム（NFS/CIFS/FUSE）上で作業中かどうかも収集
- gitリポジトリの最古コミットSHAを「プロジェクトID」として送信

---

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

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

### 推奨読解順序

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

まず、feedbackコマンドで使用される主要なデータ構造を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | feedback.ts | `src/js/eval/feedback.ts` | ParsedArgs型（83-87行目）でCLI引数構造を定義 |
| 1-2 | feedback.ts | `src/js/eval/feedback.ts` | PositionalContent型（431-434行目）でファイル添付構造を定義 |
| 1-3 | feedback.ts | `src/js/eval/feedback.ts` | TerminalIO型（32-36行目）で対話入力構造を定義 |
| 1-4 | feedback.ts | `src/js/eval/feedback.ts` | IPSupport列挙型（25-30行目）でネットワーク情報を定義 |

**読解のコツ**: TypeScriptで書かれたスクリプトで、Node.js APIとBun固有APIの両方を使用しています。

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

処理の起点となるファイル・関数を特定します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cli.zig | `src/cli.zig` | feedbackはヘルプテキストで参照（192行目） |
| 2-2 | feedback.ts | `src/js/eval/feedback.ts` | main()関数（547-751行目）がメイン処理 |
| 2-3 | feedback.ts | `src/js/eval/feedback.ts` | parseCliArgs()関数（89-118行目）で引数解析 |

**主要処理フロー**:
1. **547-556行目**: 引数解析とヘルプ表示
2. **558-591行目**: メールアドレス取得（複数ソースからの優先順序）
3. **600-625行目**: フィードバック内容取得
4. **629-724行目**: システム情報収集とFormData構築
5. **726-738行目**: HTTP POST送信
6. **740-747行目**: 成功メッセージ表示

#### Step 3: メールアドレス取得処理

メールアドレス取得の優先順序を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | feedback.ts | `src/js/eval/feedback.ts` | readEmailFromBunInstall()関数（135-148行目） |
| 3-2 | feedback.ts | `src/js/eval/feedback.ts` | readEmailFromGitConfig()関数（163-173行目） |
| 3-3 | feedback.ts | `src/js/eval/feedback.ts` | promptForEmail()関数（175-191行目） |
| 3-4 | feedback.ts | `src/js/eval/feedback.ts` | persistEmailToBunInstall()関数（150-161行目） |

#### Step 4: 対話入力処理

TTY環境での対話入力を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | feedback.ts | `src/js/eval/feedback.ts` | openTerminal()関数（38-70行目）でTTY取得 |
| 4-2 | feedback.ts | `src/js/eval/feedback.ts` | promptForEmailInteractive()関数（193-301行目） |
| 4-3 | feedback.ts | `src/js/eval/feedback.ts` | promptForBody()関数（303-408行目） |

#### Step 5: システム情報収集

自動収集されるシステム情報を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | feedback.ts | `src/js/eval/feedback.ts` | FormData構築（632-724行目）で各種情報をappend |
| 5-2 | feedback.ts | `src/js/eval/feedback.ts` | getIPSupport()関数（506-531行目）でネットワーク判定 |
| 5-3 | feedback.ts | `src/js/eval/feedback.ts` | getOldestGitSha()関数（533-545行目）でプロジェクトID取得 |

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

```
bun feedback [args...]
    │
    ├─ main()
    │      │
    │      ├─ parseCliArgs() [引数解析]
    │      │
    │      ├─ openTerminal() [TTY取得]
    │      │
    │      ├─ [メールアドレス取得]
    │      │      ├─ readEmailFromBunInstall()
    │      │      ├─ readEmailFromGitConfig()
    │      │      └─ promptForEmail()
    │      │             └─ promptForEmailInteractive()
    │      │
    │      ├─ persistEmailToBunInstall() [メール保存]
    │      │
    │      ├─ [フィードバック内容取得]
    │      │      ├─ readFromStdin()
    │      │      ├─ readFromPositionals()
    │      │      │      └─ resolveFileCandidate()
    │      │      └─ promptForBody() [対話入力]
    │      │
    │      ├─ [システム情報収集]
    │      │      ├─ getOldestGitSha()
    │      │      ├─ getIPSupport()
    │      │      └─ os.networkInterfaces()
    │      │
    │      └─ fetch(endpoint, { method: "POST", body: form })
    │
    └─ [エラー時]
           └─ logError() + process.exit(1)
```

### データフロー図

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

コマンドライン引数     ───▶ parseCliArgs()              ───▶ ParsedArgs
(--email, positionals)

$BUN_INSTALL/feedback  ───▶ readEmailFromBunInstall()   ───▶ 保存メール
git config user.email  ───▶ readEmailFromGitConfig()    ───▶ gitメール
対話入力              ───▶ promptForEmailInteractive()  ───▶ 入力メール

位置引数 + ファイル   ───▶ readFromPositionals()        ───▶ PositionalContent
                           resolveFileCandidate()           (messageParts, files)
標準入力              ───▶ readFromStdin()              ───▶ stdinContent
対話入力              ───▶ promptForBody()              ───▶ interactiveBody

システム情報          ───▶ FormData構築                 ───▶ FormData
+ フィードバック

FormData              ───▶ fetch() POST                 ───▶ HTTPレスポンス
                           https://bun.report/v1/feedback
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| feedback.ts | `src/js/eval/feedback.ts` | ソース | feedbackコマンドのメイン実装（TypeScript） |
| cli.zig | `src/cli.zig` | ソース | CLIコマンドルーター、ヘルプテキスト |

### 収集されるシステム情報一覧

| フィールド名 | 説明 | 取得元 |
|-------------|------|--------|
| email | 連絡先メールアドレス | ユーザー入力/git/保存値 |
| message | フィードバックメッセージ | 引数/ファイル/対話入力 |
| files[] | 添付ファイル（Blob） | 位置引数のファイルパス |
| platform | プラットフォーム | process.platform |
| arch | アーキテクチャ | process.arch |
| bunRevision | Bunのgitリビジョン | Bun.revision |
| bunVersion | Bunのバージョン | Bun.version |
| bunBuild | ビルド名 | process.release.sourceUrl |
| hardwareConcurrency | CPU数 | navigator.hardwareConcurrency |
| availableMemory | 利用可能メモリ | process.availableMemory() |
| totalMemory | 総メモリ | os.totalmem() |
| osVersion | OSバージョン | os.version() |
| osRelease | OSリリース | os.release() |
| id | トラッキングID | Bun.randomUUIDv7() |
| docker | Docker内か | /.dockerenv存在チェック |
| localIPSupport | ローカルIP | os.networkInterfaces() |
| remoteIPSupport | リモートIP | os.networkInterfaces() |
| remoteFilesystem | リモートFS上か | fsp.statfs() |
| projectId | プロジェクトID | git rev-list --max-parents=0 HEAD |
