# 通知設計書 7-HTTPステータスコードエラー

## 概要

本ドキュメントは、InvenTreeモバイルアプリケーションにおける「HTTPステータスコードエラー」通知の設計仕様を定義する。サーバーから400番台・500番台のHTTPステータスコードが返された際に表示されるエラー通知の仕様を記載する。

### 本通知の処理概要

この通知は、InvenTreeサーバーへのHTTPリクエストに対して、エラーを示すHTTPステータスコード（400番台のクライアントエラー、500番台のサーバーエラー）が返された際にユーザーに通知する機能である。

**業務上の目的・背景**：HTTPステータスコードは、リクエストの処理結果を示す標準的な方法である。エラーコードを適切にユーザーに伝えることで、問題の原因を特定し、適切な対処（入力データの修正、権限の確認、管理者への連絡など）が可能になる。各ステータスコードに対応したメッセージを表示することで、技術的な知識がなくても問題を理解できる。

**通知の送信タイミング**：`showStatusCodeError()`関数が呼び出された際にトリガーされる。これは主に以下の場面で発生する：
- `_checkServer()`でのサーバー応答確認時
- `completeRequest()`でのレスポンス処理時
- `downloadFile()`でのファイルダウンロード時
- `fetchToken()`での認証トークン取得時

**通知の受信者**：アプリケーションを操作している現在のユーザー。画面上にスナックバーとして表示され、タップすると詳細ダイアログが開く。

**通知内容の概要**：HTTPステータスコードに対応した人間可読なメッセージ（例：「400 Bad Request」「401 Unauthorized」など）がスナックバーに表示される。詳細ボタンをタップすると、URL、ステータスコード、レスポンスデータを含む詳細情報が表示される。

**期待されるアクション**：ステータスコードに応じた対処を行う：
- 400: 入力データを確認し、修正して再送信
- 401: 認証情報（ユーザー名/パスワード）を確認
- 403: アクセス権限を確認、管理者に問い合わせ
- 404: URLやリソースの存在を確認
- 429: 時間をおいて再試行
- 500番台: サーバー管理者に連絡

## 通知種別

アプリ内通知（スナックバー + 詳細ダイアログ + 音声）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無し（UI通知のため） |

### 送信先決定ロジック

現在アプリケーションを操作しているユーザーに対して、画面下部にスナックバー形式で表示する。`showStatusCodeError`関数経由で`showServerError`が呼び出され、詳細ダイアログへのアクセスも提供される。

## 通知テンプレート

### スナックバー通知の場合

| 項目 | 内容 |
|-----|------|
| 表示位置 | 画面下部 |
| 背景色 | Colors.deepOrange（エラー時） |
| 表示時間 | 10秒（アクションボタンあり） |
| 形式 | テキスト + 詳細ボタン |

### 本文テンプレート

```
[ステータスコードに対応したメッセージ]  [詳細ボタン]
```

### ステータスコード別メッセージ

| ステータスコード | メッセージ（L10()キー） |
|-----------------|----------------------|
| 400 | response400 - Bad Request |
| 401 | response401 - Unauthorized |
| 403 | response403 - Forbidden |
| 404 | response404 - Not Found |
| 405 | response405 - Method Not Allowed |
| 429 | response429 - Too Many Requests |
| 500 | response500 - Internal Server Error |
| 501 | response501 - Not Implemented |
| 502 | response502 - Bad Gateway |
| 503 | response503 - Service Unavailable |
| 504 | response504 - Gateway Timeout |
| 505 | response505 - HTTP Version Not Supported |
| その他 | responseInvalid - Invalid Response : {code} |

### 詳細ダイアログ

| 項目 | 内容 |
|-----|------|
| ダイアログタイプ | SimpleDialog |
| アイコン | TablerIcons.server |
| タイトル | ステータスコード対応メッセージ |
| 本文 | URL + ステータスコード + レスポンス詳細 |

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| statusCodeToString(status) | ステータスコード対応メッセージ | dialogs.dart | Yes |
| url | リクエストURL | API通信処理から | Yes |
| status | HTTPステータスコード | HTTPレスポンス | Yes |
| details | レスポンス詳細 | response.data.toString() | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API通信 | サーバー応答確認 | statusCode != 200 | _checkServerで期待外のステータス |
| API通信 | リクエスト完了 | statusCode >= 500 | サーバーエラー |
| API通信 | リクエスト完了 | statusCode != expectedStatusCode | 期待外のステータス |
| API通信 | トークン取得 | statusCode != 200 | fetchTokenで認証失敗 |
| ファイル転送 | ダウンロード完了 | statusCode != 200 | ダウンロードエラー |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| コンテキストなし | `hasContext()`が`false`を返す場合 |
| 特定のステータス | 502/503/504は一部処理でSentryレポートを抑止 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[HTTPレスポンス受信] --> B{statusCode確認}
    B -->|200番台| C[正常処理続行]
    B -->|400番台| D[showStatusCodeError呼び出し]
    B -->|500番台| E[showStatusCodeError呼び出し]
    D --> F[statusCodeToString変換]
    E --> F
    F --> G[showServerError呼び出し]
    G --> H[音声再生]
    H --> I[スナックバー表示]
    I --> J{ユーザーが詳細タップ?}
    J -->|Yes| K[showErrorDialog表示]
    J -->|No| L[10秒後自動消去]
    K --> M[終了]
    L --> M
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| settings | 音声設定確認 | Sembast NoSQL DB |

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

#### settings

| 参照項目（キー名） | 用途 | 取得条件 |
|-------------------|------|---------|
| INV_SOUNDS_SERVER | サーバーエラー音有効/無効 | デフォルト: true |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | 通知表示のみで更新なし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 400番台エラー | クライアント側の問題 | ユーザーに入力/権限の確認を促す |
| 500番台エラー | サーバー側の問題 | サーバー管理者への連絡を促す |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0回 |
| リトライ間隔 | - |
| リトライ対象エラー | - |

HTTPエラーの多くは設定/入力の修正が必要なため、自動リトライは行わない。

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（エラー発生時に即座に表示）

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

- エラー詳細にはURL情報とレスポンスデータが含まれる
- 401/403エラー時は認証/権限情報が不正確であることを示すが、詳細は漏洩しない
- ユーザーのデバイス上でのみ表示され、外部への送信は行わない
- 特定のエラーはSentryにレポートされる（デバッグ目的）

## 備考

- `statusCodeToString()`関数で、ステータスコードを人間可読なメッセージに変換
- 認知されていないステータスコードは「Invalid Response : {code}」形式で表示
- 500番台エラーの一部（502/503/504）はSentryへのレポートが抑止される（一般的なサーバー問題のため）
- レスポンスデータがJSONでない場合も、toString()で文字列化して表示

---

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

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

### 推奨読解順序

#### Step 1: ステータスコード変換を理解する

まず、ステータスコードをメッセージに変換する関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dialogs.dart | `lib/widget/dialogs.dart` | statusCodeToString関数 |

**読解のコツ**: `statusCodeToString()`は`switch`文で各ステータスコードに対応するL10()メッセージを返す。

#### Step 2: 通知関数を理解する

showStatusCodeError関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dialogs.dart | `lib/widget/dialogs.dart` | showStatusCodeError関数 |

**主要処理フロー**:
1. **行253-267**: `showStatusCodeError()`関数
2. **行258**: `statusCodeToString(status)`呼び出し
3. **行259-264**: 詳細情報の構築
4. **行266**: `showServerError()`呼び出し
5. **行272-300**: `statusCodeToString()`関数 - ステータスコードのマッピング

#### Step 3: 呼び出し元を理解する

showStatusCodeErrorが呼び出される箇所を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | api.dart | `lib/api.dart` | _checkServer、completeRequest、downloadFile、fetchToken |

**主要処理フロー**:
1. **行480-485**: `_checkServer()`でのステータスコードエラー通知
2. **行1337-1338**: `completeRequest()`での500番台エラー通知
3. **行1365-1370**: `completeRequest()`での期待外ステータス通知
4. **行966-967**: `downloadFile()`でのステータスコードエラー通知
5. **行597-608**: `fetchToken()`でのステータスコードエラー通知

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

```
[各種API通信]
    |
    +-- HTTPレスポンス受信
    |       |
    |       +-- statusCode確認
    |               |
    |               +-- [400/500番台]
    |
    +-- showStatusCodeError() [dialogs.dart:253]
            |
            +-- statusCodeToString() [dialogs.dart:272]
            |       |
            |       +-- L10().response400 / response401 / ...
            |
            +-- showServerError() [dialogs.dart:207]
                    |
                    +-- playAudioFile() [helpers.dart:92]
                    +-- showSnackIcon() [snacks.dart:11]
```

### データフロー図

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

HTTPレスポンス       showStatusCodeError()          スナックバー表示
     |          --->       |                   --> [ステータス対応メッセージ]
     v                     v                        [詳細ボタン]
statusCode          statusCodeToString()
                          |
                          v
                    switch(status)
                    400 -> L10().response400
                    401 -> L10().response401
                    ...
                          |
                          v
                    showServerError()
                          |
                          v
                    音声再生 + スナックバー
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dialogs.dart | `lib/widget/dialogs.dart` | ソース | ステータスコードエラー通知、メッセージ変換 |
| api.dart | `lib/api.dart` | ソース | HTTP通信、showStatusCodeError呼び出し |
| snacks.dart | `lib/widget/snacks.dart` | ソース | スナックバー通知の表示 |
| helpers.dart | `lib/helpers.dart` | ソース | 音声再生・共通ヘルパー関数 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応（response400等） |
