# 画面設計書 39-予算分析レポート画面

## 概要

本ドキュメントは、Actual Budget アプリケーションの予算分析レポート画面の設計仕様を記述したものである。

### 本画面の処理概要

予算分析レポート画面は、予算額と実際の支出を比較分析し、予算のパフォーマンスを可視化する画面である。期間内の予算配分、実支出、超過支出の調整、累積残高を折れ線グラフまたは棒グラフで表示する。

**業務上の目的・背景**：予算管理において、「予算通りに支出できているか」「どの程度の残高があるか」を把握することは重要である。この画面では、選択期間における予算と実績の推移を視覚化し、予算のパフォーマンスを評価できる。カテゴリでフィルタリングすることで、特定の費目に絞った分析も可能。超過支出の調整（ロールオーバー設定のないカテゴリのリセット分）も考慮した正確な残高推移を確認できる。

**画面へのアクセス方法**：サイドバーの「レポート」メニューをクリック後、レポートダッシュボードから「予算分析」ウィジェットを選択、または直接 `/reports/budget-analysis/:id` URLにアクセスする。

**主要な操作・処理内容**：
1. 期間選択：分析対象の開始月と終了月を選択
2. グラフタイプ切り替え：折れ線グラフと棒グラフを切り替え
3. 残高表示切り替え：累積残高の表示/非表示を切り替え
4. カテゴリフィルタ：特定のカテゴリに絞って分析
5. サマリー確認：期間内の予算総額、支出総額、超過調整額、残高を確認
6. ウィジェット保存：設定をダッシュボードウィジェットとして保存

**画面遷移**：レポートダッシュボード画面（`/reports`）から遷移する。モバイル画面幅では戻るボタンでレポートダッシュボードへ戻る。

**権限による表示制御**：特に権限による制御はない。予算ファイルがロードされていることが前提条件となる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 33 | 収支レポート | 主機能 | 予算と実績の分析・表示 |

## 画面種別

詳細・分析画面

## URL/ルーティング

- `/reports/budget-analysis/:id` - ダッシュボードウィジェットID指定

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 説明 |
|--------|----------|---------|------|------|
| 開始月 | 入力 | string | Yes | 分析期間の開始月 |
| 終了月 | 入力 | string | Yes | 分析期間の終了月 |
| グラフタイプ | 入力 | string | Yes | 'Line' または 'Bar' |
| 残高表示 | 入力 | boolean | Yes | 残高を表示するか（デフォルトtrue） |
| フィルタ条件 | 入力 | RuleConditionEntity[] | No | カテゴリ等のフィルタ条件 |
| フィルタ演算子 | 入力 | string | No | 'and' または 'or' |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| 予算総額 | number | 期間内の予算配分合計 |
| 支出総額 | number | 期間内の実支出合計 |
| 超過支出調整額 | number | ロールオーバー未設定カテゴリの超過分リセット合計 |
| 残高 | number | 累積残高（期間最終値） |
| 予算分析グラフ | component | 予算と実績の推移グラフ |

## イベント仕様

### 1-期間変更

ヘッダーの期間選択を変更すると、`onChangeDates`関数が呼び出される。3ヶ月超の期間の場合は自動的に「簡潔表示」（月次集計）モードに切り替わる。

### 2-グラフタイプ切り替え

ヘッダー内のグラフアイコンボタンを押すと、`setGraphType`により折れ線グラフと棒グラフが切り替わる。現在が折れ線なら棒グラフに、棒グラフなら折れ線に切り替わる。

### 3-残高表示切り替え

「Show balance」/「Hide balance」ボタンを押すと、`setShowBalance`により残高の表示/非表示が切り替わる。非表示時はグラフおよびサマリーから残高が除外される。

### 4-フィルタ適用

Headerコンポーネントのフィルタ機能でカテゴリなどの条件を設定すると、`onApplyFilter`、`onUpdateFilter`、`onDeleteFilter`、`onConditionsOpChange`により状態が更新される。フィルタ対象から除外される項目：date, account, payee, notes, amount, cleared, reconciled, transfer。

### 5-ウィジェット名変更

ヘッダーのタイトルをクリックして編集すると、`onSaveWidgetName`関数が実行され、ウィジェット名が更新される。

### 6-ウィジェット保存

「Save widget」ボタン押下時、`onSaveWidget`関数が実行され、フィルタ条件、期間、グラフタイプ、残高表示設定がウィジェットのメタデータとして保存される。

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

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ウィジェット保存 | dashboard_widgets | UPDATE | ウィジェットのmeta情報を更新 |
| データ取得 | transactions, budget | SELECT | 予算と取引データを取得して分析 |
| 最古取引取得 | transactions | SELECT | 最古の取引日を取得 |
| 最新取引取得 | transactions | SELECT | 最新の取引日を取得 |

### テーブル別更新項目詳細

#### dashboard_widgets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | meta | JSON（conditions, conditionsOp, timeFrame, graphType, showBalance, name） | ウィジェット保存時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| MSG_WIDGET_SAVED | 成功 | Dashboard widget successfully saved. | ウィジェット保存成功時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| ウィジェットが存在しない | 保存時にエラーをスロー（throw new Error） |
| データがない | ローディング表示を継続 |
| 月データがない | ローディング表示を継続 |

## 備考

- デフォルト期間は過去6ヶ月
- 3ヶ月超の期間選択時は自動的に月次集計表示（isConcise=true）
- グラフには4つの系列を表示：Budgeted（予算）、Spent（支出）、Overspending Adjustment（超過調整）、Balance（残高）
- 残高は前月からの繰り越しを考慮した累積値
- 超過支出調整はロールオーバー設定のないカテゴリで発生
- フィルタはカテゴリのみ選択可能（date, account, payee等は除外）
- ツールチップでグラフタイプ切り替えボタンの説明を表示
- 画面下部にチャートの見方の説明を表示
- プライバシーフィルタにより金額表示をマスク可能
- 週の開始曜日設定（firstDayOfWeekIdx）に対応

---

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

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

### 推奨読解順序

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

まず、予算分析レポートで使用されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.ts | `loot-core/types/models` | `BudgetAnalysisWidget`, `RuleConditionEntity`, `TimeFrame`型の定義を確認 |
| 1-2 | budget-analysis-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/budget-analysis-spreadsheet.ts` | 返却データの構造（intervalData, totalBudgeted, totalSpent, totalOverspendingAdjustment） |

**読解のコツ**: intervalData配列に含まれる各期間のbudgeted, spent, overspendingAdjustment, balanceの計算方法を理解する。

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

処理の起点となるメインコンポーネントを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | BudgetAnalysis.tsx | `packages/desktop-client/src/components/reports/reports/BudgetAnalysis.tsx` | `BudgetAnalysis`関数コンポーネントがエントリーポイント |

**主要処理フロー**:
1. **50-62行**: `BudgetAnalysis`関数 - useWidgetでウィジェットデータ取得
2. **68-508行**: `BudgetAnalysisInternal`関数 - メインのレンダリングロジック
3. **74-84行**: useRuleConditionFiltersでフィルタ管理
4. **86-104行**: 状態の初期化
5. **117-178行**: 最古/最新取引日の取得と期間初期化
6. **183-192行**: createBudgetAnalysisSpreadsheetでパラメータ生成
7. **194行**: useReportフック呼び出し

#### Step 3: グラフ表示を理解する

グラフ描画の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BudgetAnalysisGraph.tsx | `packages/desktop-client/src/components/reports/graphs/BudgetAnalysisGraph.tsx` | グラフ描画 |

#### Step 4: ヘッダーとフィルタを理解する

ヘッダーコンポーネントとフィルタ機能を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Header.tsx | `packages/desktop-client/src/components/reports/Header.tsx` | 期間選択とフィルタUI |

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

```
BudgetAnalysis (エントリーポイント)
    │
    ├─ useWidget (ウィジェットデータ取得)
    │
    └─ BudgetAnalysisInternal (メインコンポーネント)
           │
           ├─ useLocale (ロケール取得)
           │
           ├─ useFormat (書式設定)
           │
           ├─ useRuleConditionFilters (フィルタ管理)
           │      ├─ conditions
           │      ├─ conditionsOp
           │      ├─ onApply
           │      ├─ onDelete
           │      ├─ onUpdate
           │      └─ onConditionsOpChange
           │
           ├─ useSyncedPref('firstDayOfWeekIdx')
           │
           ├─ send('get-earliest-transaction')
           │
           ├─ send('get-latest-transaction')
           │
           ├─ calculateTimeRange
           │
           ├─ createBudgetAnalysisSpreadsheet (計算パラメータ)
           │      └─ useReport (データ取得フック)
           │
           ├─ Header (期間選択・フィルタUI)
           │      ├─ グラフタイプ切り替えボタン
           │      ├─ フィルタ設定
           │      └─ 期間選択
           │
           ├─ サマリー表示
           │      ├─ AlignedText (Budgeted)
           │      ├─ AlignedText (Spent)
           │      ├─ AlignedText (Overspending adj)
           │      └─ AlignedText (Ending balance)
           │
           ├─ BudgetAnalysisGraph (グラフ表示)
           │
           └─ 説明パネル（Paragraph）
```

### データフロー図

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

URLパラメータ ─────────▶ useWidget ─────────────────▶ ウィジェットメタデータ
                              │
                              ├──▶ meta.conditions
                              ├──▶ meta.conditionsOp
                              ├──▶ meta.timeFrame
                              ├──▶ meta.graphType
                              └──▶ meta.showBalance

useRuleConditionFilters ──▶ フィルタ状態
                              │
send('get-earliest-transaction')
send('get-latest-transaction')
                              │
                              ▼
                    calculateTimeRange
                              │
                              ├──▶ start
                              └──▶ end
                              │
                              ▼
                    calculateIsConcise
                              │
                              └──▶ isConcise (3ヶ月超ならtrue)
                              │
                              ▼
                    createBudgetAnalysisSpreadsheet
                              │
                              ├──▶ conditions
                              ├──▶ conditionsOp
                              ├──▶ startDate
                              └──▶ endDate
                              │
                              ▼
                        useReport
                              │
                              ▼
予算/取引データ(DB) ──▶ 予算分析計算 ──────────────▶ BudgetAnalysisData
                                                        │ intervalData[]
                                                        │   - budgeted
                                                        │   - spent
                                                        │   - overspendingAdjustment
                                                        │   - balance
                                                        │ totalBudgeted
                                                        │ totalSpent
                                                        │ totalOverspendingAdjustment
                              │
                              ▼
                    BudgetAnalysisGraph
                              │
                              ▼
                        画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BudgetAnalysis.tsx | `packages/desktop-client/src/components/reports/reports/BudgetAnalysis.tsx` | ソース | メインコンポーネント |
| budget-analysis-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/budget-analysis-spreadsheet.ts` | ソース | 計算ロジック |
| BudgetAnalysisGraph.tsx | `packages/desktop-client/src/components/reports/graphs/BudgetAnalysisGraph.tsx` | ソース | グラフ描画 |
| Header.tsx | `packages/desktop-client/src/components/reports/Header.tsx` | ソース | 期間選択・フィルタヘッダー |
| Change.tsx | `packages/desktop-client/src/components/reports/Change.tsx` | ソース | 変動値表示コンポーネント |
| PrivacyFilter.tsx | `packages/desktop-client/src/components/PrivacyFilter.tsx` | ソース | プライバシーフィルタ |
| FinancialText.tsx | `packages/desktop-client/src/components/FinancialText.tsx` | ソース | 金額表示 |
| AlignedText.tsx | `@actual-app/components/aligned-text` | ソース | 左右揃えテキスト |
