# 通知設計書 32-やり直し通知

## 概要

本ドキュメントは、Actual Budget アプリケーションにおける「やり直し通知」の設計仕様を記述する。この通知は、ユーザーが取り消した操作を再実行（Redo）可能であることを知らせ、ワンタッチでやり直す機能を提供するものである。

### 本通知の処理概要

**業務上の目的・背景**：ユーザーがUndo（元に戻す）操作を行った後、やはり元の変更を適用したい場合に、即座に操作をやり直せる手段を提供する。これにより、誤ってUndoしてしまった場合のリカバリーが容易になり、ユーザー体験が向上する。モバイル環境ではキーボードショートカットが利用できないため、通知形式でRedo機能にアクセスできることが重要である。

**通知の送信タイミング**：Undo（元に戻す）操作が実行された直後、やり直しが可能な場合に表示される。主にモバイル版（狭い画面幅）でのみ表示され、デスクトップ版ではキーボードショートカット（Ctrl+Y / Cmd+Shift+Z）で同等の機能が利用可能なため表示されない。

**通知の受信者**：Undo操作を実行した現在のユーザーのみが対象。同一端末のアプリ内で表示される。

**通知内容の概要**：操作を取り消したことを示すメッセージと「Redo」ボタンが表示される。ボタンを押すと取り消した操作がやり直される。

**期待されるアクション**：ユーザーは通知を確認し、必要に応じて「Redo」ボタンを押して操作をやり直す。10秒間操作がなければ通知は自動的に消える。

## 通知種別

アプリ内通知（トースト通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（即時表示） |
| 優先度 | 中 |
| リトライ | 無 |

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

- Undo操作を実行したユーザーのローカル画面に表示
- `isNarrowWidth` が `true` の場合（モバイル/狭い画面）のみ表示
- デスクトップ版（広い画面）では表示されない

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| 通知タイプ | `message` |
| 表示位置 | 画面右下（固定位置） |
| タイムアウト | 10,000ms（10秒） |

### 本文テンプレート

```
{操作に応じたメッセージ}
[Redo ボタン]
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| message | 表示メッセージ | 呼び出し元から渡される | Yes |
| button.title | ボタンのラベル | 固定値 "Redo" | Yes |
| button.action | ボタン押下時のアクション | `redo` 関数 | Yes |
| timeout | 自動消去までの時間 | 固定値 10000 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | Undo操作後 | モバイル版でやり直し可能な場合 | showRedoNotification 呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `isNarrowWidth === false` | デスクトップ版では表示しない |
| undo が無効化されている場合 | `_undoEnabled === false` の場合は表示しない |
| やり直し可能な操作がない場合 | Redo履歴が空の場合は表示しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Undo 操作実行] --> B{モバイル版?}
    B -->|Yes| C{やり直し可能?}
    B -->|No| D[通知なし]
    C -->|Yes| E[showRedoNotification 呼び出し]
    C -->|No| D
    E --> F[addNotification dispatch]
    F --> G[Redux store に追加]
    G --> H[Notifications コンポーネントで表示]
    H --> I{10秒経過 or Redo押下?}
    I -->|10秒経過| J[自動消去]
    I -->|Redo押下| K[redo関数実行]
    K --> L[通知消去]
    J --> M[終了]
    L --> M
    D --> M
```

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

### 参照テーブル一覧

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

### Redo実行時の更新

Redoボタン押下時は、サーバー側の `redo` ハンドラーが呼び出され、`MESSAGE_HISTORY` から次の操作を再適用するメッセージが生成・適用される。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Redo履歴なし | やり直し可能な操作がない場合 | 何も起きない（エラー表示なし） |
| Redo無効 | `_undoEnabled === false` の場合 | Redoボタン押下しても何も起きない |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（即時表示）

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

- 通知はローカルのみで表示され、サーバーには送信されない
- Redo操作自体は認証済みユーザーのみが実行可能

## 備考

- デスクトップ版ではキーボードショートカット（Ctrl+Y / Cmd+Shift+Z）でRedo機能を利用可能
- Undo/Redo操作は100msのスロットリングが適用されている
- RedoはUndo操作後にのみ有効で、新しい操作を行うとRedo履歴はクリアされる

---

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

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

### 推奨読解順序

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

通知オブジェクトの構造と状態管理を理解する（元に戻す通知と共通）。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | notificationsSlice.ts | `packages/desktop-client/src/notifications/notificationsSlice.ts` | Notification 型定義（9-26行目） |

**読解のコツ**: Redux Toolkit の createSlice パターンを理解していると読みやすい。

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

Redo通知を発行するフックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | useUndo.ts | `packages/desktop-client/src/hooks/useUndo.ts` | showRedoNotification 関数（50-71行目）、isNarrowWidth 条件分岐（52-54行目） |

**主要処理フロー**:
1. **20行目**: timeout 定数（10000ms = 10秒）を定義
2. **52-54行目**: モバイル版でない場合は早期リターン
3. **56-69行目**: `addNotification` を dispatch して通知を表示
4. **61行目**: ボタンタイトルは 'Redo'
5. **62行目**: ボタンアクションは `redo` 関数

#### Step 3: Redo実行処理を理解する

Redoボタン押下時の実際の処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts (undo) | `packages/desktop-client/src/undo/index.ts` | redo 関数（35-39行目）、スロットリング処理（17行目） |
| 3-2 | undo.ts (server) | `packages/loot-core/src/server/undo.ts` | redo 関数（205-236行目）、カーソル操作 |

**主要処理フロー**:
- **17行目（クライアント）**: 100msのスロットリングでredo関数をラップ
- **35-39行目（クライアント）**: `_undoEnabled` チェック後、サーバーへ 'redo' メッセージ送信
- **205-236行目（サーバー）**: カーソルを進め、メッセージを再適用
- **238-270行目（サーバー）**: `redoResurrections` で tombstone=1 のレコードを復活

#### Step 4: 通知表示コンポーネントを理解する

通知がどのように画面に表示されるかを理解する（元に戻す通知と共通）。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Notifications.tsx | `packages/desktop-client/src/components/Notifications.tsx` | Notification コンポーネント（100-367行目） |

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

```
Undo操作後の画面
    │
    ├─ useUndo() フック
    │      │
    │      ├─ showRedoNotification()
    │      │      └─ dispatch(addNotification())
    │      │             └─ Redux store 更新
    │      │                    └─ Notifications.tsx 再レンダリング
    │      │
    │      └─ redo() (ボタン押下時)
    │             └─ send('redo') → サーバー
    │                    └─ redo() (server/undo.ts)
    │                           └─ applyUndoAction()
    │                                  └─ connection.send('undo-event')
    │
    └─ Notifications コンポーネント
           └─ Notification コンポーネント
                  └─ ButtonWithLoading (Redo ボタン)
```

### データフロー図

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

Undo操作完了 ─────────▶ showRedoNotification() ───▶ 通知表示（Redux store）
                              │
                              └─▶ isNarrowWidth チェック
                                      │
                                      ├─ true ───▶ 通知表示
                                      └─ false ──▶ 何もしない

Redo ボタン押下 ───────▶ redo() ────────────────▶ サーバー redo 処理
                              │                          │
                              └─ スロットリング           └─ undo-event 発火
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notificationsSlice.ts | `packages/desktop-client/src/notifications/notificationsSlice.ts` | ソース | 通知の Redux slice 定義 |
| useUndo.ts | `packages/desktop-client/src/hooks/useUndo.ts` | ソース | Redo通知表示フック |
| index.ts | `packages/desktop-client/src/undo/index.ts` | ソース | クライアント側 undo/redo 関数 |
| undo.ts | `packages/loot-core/src/server/undo.ts` | ソース | サーバー側 undo/redo ロジック |
| Notifications.tsx | `packages/desktop-client/src/components/Notifications.tsx` | ソース | 通知表示コンポーネント |
