# 通知設計書 36-Redux Action エラー

## 概要

本ドキュメントは、Actual Budget アプリケーションにおける「Redux Action エラー」通知の設計仕様を記述する。この通知は、Redux の非同期アクション（async thunk）が失敗（reject）した際に自動的に表示されるエラー通知である。

### 本通知の処理概要

**業務上の目的・背景**：アプリケーション内で発生する様々な非同期処理（データ取得、更新、同期など）がエラーで失敗した場合、ユーザーに即座にフィードバックを提供する。これにより、ユーザーは問題の発生を認識し、適切な対処（再試行、サポートへの連絡など）を行うことができる。

**通知の送信タイミング**：Redux Toolkit の `createAsyncThunk` で作成された非同期アクションが rejected 状態になった時に自動的に発行される。`isRejected` matcher を使用してミドルウェアレベルでキャッチされる。

**通知の受信者**：エラーが発生したユーザー本人。

**通知内容の概要**：エラーメッセージがエラータイプの通知として表示される。メッセージはアクションの `error.message` から取得されるか、デフォルトメッセージが使用される。

**期待されるアクション**：ユーザーはエラー内容を確認し、必要に応じて操作を再試行するか、問題が解決しない場合はサポートに連絡する。

## 通知種別

アプリ内通知（トースト通知 - エラータイプ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（アクション reject 時に即時） |
| 優先度 | 高 |
| リトライ | 無（通知自体のリトライはなし） |

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

- `isRejected` matcher にマッチするすべての rejected アクションで発行
- 通知 ID はアクションの `type` から生成（重複防止）

## 通知テンプレート

### アプリ内通知の場合

| 項目 | 内容 |
|-----|------|
| 通知タイプ | `error` |
| 通知ID | `action.type`（アクションのタイプ名） |
| 表示位置 | 画面右下（固定位置） |
| タイムアウト | デフォルト（6500ms） |

### 本文テンプレート

```
Message: {error.message || 'An unexpected error occurred.'}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | 通知タイプ | 固定値 `error` | Yes |
| id | 通知ID | `action.type` | Yes |
| message | エラーメッセージ | `action.error.message` またはデフォルト | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Redux ミドルウェア | isRejected アクション | すべての rejected async thunk | store.ts のリスナーミドルウェア |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 同一IDの通知が既に表示中 | action.type で重複チェック |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[async thunk 実行] --> B{処理結果}
    B -->|成功| C[fulfilled アクション]
    B -->|失敗| D[rejected アクション]
    D --> E[isRejected matcher]
    E --> F[notifyOnRejectedActionsMiddleware]
    F --> G[console.error でログ出力]
    G --> H[addNotification dispatch]
    H --> I[Redux store に追加]
    I --> J[Notifications コンポーネントで表示]
    J --> K{6.5秒経過 or 閉じる}
    K --> L[通知消去]
    C --> M[終了]
    L --> M
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| - | - | 通知表示自体ではDB参照なし |

### ログ出力

エラー発生時は `console.error(action.error)` でコンソールにエラー詳細が出力される。

## エラー処理

### エラーケース一覧

この通知自体がエラー処理の仕組みであるため、通知発行に失敗するケースは想定しない。

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（同一ID重複防止あり） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

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

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

- エラーメッセージにはセンシティブな情報が含まれないよう注意が必要
- スタックトレースはコンソールにのみ出力され、ユーザーには表示されない

## 備考

- この通知は Redux Toolkit の `createListenerMiddleware` を使用して実装されている
- すべての `createAsyncThunk` で作成されたアクションの reject をキャッチする
- 開発者向けのデバッグ情報は `console.error` で出力される
- 通知 ID にアクションの type を使用することで、同一エラーの重複表示を防止

---

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

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

### 推奨読解順序

#### Step 1: ミドルウェアの設定を理解する

Redux store の設定とミドルウェアの構成を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | store.ts | `packages/desktop-client/src/redux/store.ts` | createListenerMiddleware の設定（68-84行目） |

**主要処理フロー**:
1. **68行目**: `createListenerMiddleware` でミドルウェアを作成
2. **69行目**: `startListening` でリスナーを登録
3. **70行目**: `isRejected` matcher で rejected アクションをキャッチ
4. **71-72行目**: `console.error` でエラーをログ出力
5. **73-80行目**: `addNotification` で通知を dispatch

**読解のコツ**: Redux Toolkit の `createListenerMiddleware` と `isRejected` matcher を理解していると読みやすい。

#### Step 2: isRejected matcher を理解する

Redux Toolkit の `isRejected` の動作を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | store.ts | `packages/desktop-client/src/redux/store.ts` | import 文（5-6行目） |

**読解のコツ**: `isRejected` は `createAsyncThunk` で作成されたすべてのアクションの rejected 状態をマッチする。

#### Step 3: async thunk の例を理解する

rejected になる可能性のある async thunk の実装例を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | appSlice.ts | `packages/desktop-client/src/app/appSlice.ts` | createAppAsyncThunk の例（45-51行目など） |
| 3-2 | budgetfilesSlice.ts | `packages/desktop-client/src/budgetfiles/budgetfilesSlice.ts` | 様々な async thunk |

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

```
任意の async thunk (例: sync, loadBudget, etc.)
    │
    ├─ 実行
    │      │
    │      └─ (エラー発生)
    │             │
    │             └─ rejected action
    │
Redux Store
    │
    ├─ notifyOnRejectedActionsMiddleware
    │      │
    │      ├─ isRejected(action) === true
    │      │
    │      ├─ console.error(action.error)
    │      │
    │      └─ dispatch(addNotification({
    │             id: action.type,
    │             type: 'error',
    │             message: action.error.message
    │         }))
    │
    └─ notificationsSlice
           │
           └─ state.notifications 更新
                  │
                  └─ Notifications.tsx 再レンダリング
```

### データフロー図

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

async thunk reject ────────▶ Redux middleware ───────────────▶ 通知表示
                                   │
                                   ├─▶ isRejected matcher
                                   │
                                   ├─▶ console.error(action.error)
                                   │
                                   └─▶ addNotification dispatch
                                          │
                                          └─▶ Redux store 更新
                                                 │
                                                 └─▶ Notifications 表示

action.error.message ──────▶ 通知メッセージ ──────────────────▶ ユーザー確認
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| store.ts | `packages/desktop-client/src/redux/store.ts` | ソース | Redux store 設定、ミドルウェア定義 |
| notificationsSlice.ts | `packages/desktop-client/src/notifications/notificationsSlice.ts` | ソース | 通知の Redux slice 定義 |
| Notifications.tsx | `packages/desktop-client/src/components/Notifications.tsx` | ソース | 通知表示コンポーネント |
| appSlice.ts | `packages/desktop-client/src/app/appSlice.ts` | ソース | async thunk の例 |
| budgetfilesSlice.ts | `packages/desktop-client/src/budgetfiles/budgetfilesSlice.ts` | ソース | async thunk の例 |
