# 画面設計書 33-支出レポート画面

## 概要

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

### 本画面の処理概要

支出レポート画面は、月別の支出パターンを分析・比較するための画面である。特定の月の累積支出を、過去の月や予算、平均値と比較し、日別の支出推移をグラフで可視化する。

**業務上の目的・背景**：月々の支出管理において、「今月はいつもより使いすぎているか」「予算と比べてどうか」を把握することは重要である。この画面では、選択した月の日別累積支出を、比較対象（別の月、予算額、過去3ヶ月の平均）と並べて表示することで、支出ペースを直感的に把握できる。月の途中でも「このペースで月末を迎えると予算オーバーになるか」を予測し、適切な支出調整を促す。

**画面へのアクセス方法**：サイドバーの「レポート」メニューをクリック後、レポートダッシュボードから「支出」カードを選択、または直接 `/reports/spending` URLにアクセスする。ダッシュボードウィジェットとして追加されている場合は、ウィジェットIDを含むURL `/reports/spending/:id` でアクセスする。

**主要な操作・処理内容**：
1. 比較月の選択：分析対象とする月をドロップダウンから選択
2. 比較先の選択：比較対象となる月をドロップダウンから選択（single-monthモード時）
3. レポートモードの切替：単月比較、予算比較、平均比較の3モードを切り替え
4. Live/Static切替：ライブ（現在月追従）またはスタティック（固定月）の切り替え
5. フィルタ適用：カテゴリなどの条件でデータをフィルタリング（日付フィルタは除外）
6. ウィジェット保存：ダッシュボードウィジェットとして現在の設定を保存

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

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 34 | カテゴリ別支出 | 主機能 | カテゴリ別支出の詳細分析 |

## 画面種別

詳細・分析画面

## URL/ルーティング

- `/reports/spending` - 基本URL
- `/reports/spending/:id` - ダッシュボードウィジェットID指定時

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 説明 |
|--------|----------|---------|------|------|
| 比較月 | 入力 | string | Yes | 分析対象月（YYYY-MM形式） |
| 比較先月 | 入力 | string | Conditional | 比較対象月（single-monthモード時必須） |
| レポートモード | 入力 | string | Yes | 'single-month', 'budget', 'average' |
| Live/Static | 入力 | boolean | Yes | ライブモードの有効/無効 |
| フィルタ条件 | 入力 | array | No | RuleConditionEntity配列（日付除く） |
| フィルタ演算子 | 入力 | string | No | 'and' または 'or' |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| 比較月の支出額 | number | 選択月の累積支出額（MTD含む） |
| 比較先の支出額 | number | 比較対象の累積支出額（モードにより予算/平均/他月） |
| 予算額 | number | 選択月の予算合計額（該当する場合） |
| 平均支出額 | number | 過去3ヶ月の平均累積支出額（該当する場合） |
| 支出推移グラフ | chart | 日別（1-28日）の累積支出推移を示す折れ線グラフ |
| 凡例 | component | 比較月と比較先の色分け表示 |

## イベント仕様

### 1-比較月変更

ドロップダウンから比較月を変更すると、`setCompare`により状態が更新され、スプレッドシートが再計算される。グラフの緑色ラインが更新される。

### 2-比較先月変更

single-monthモードでドロップダウンから比較先月を変更すると、`setCompareTo`により状態が更新される。グラフの灰色ラインが更新される。

### 3-レポートモード切替

モードボタン（Single month / Budgeted / Average）を押下すると、`setReportMode`により状態が切り替わる。比較先ドロップダウンの選択肢も変更される。

### 4-Live/Static切替

Live/Staticボタン押下で、`setIsLive`により状態が切り替わる。Liveモードでは比較月が自動的に現在月に追従する。

### 5-フィルタ適用

フィルタボタンからフィルタ条件を追加（日付フィルタは除外）すると、`onApplyFilter`が呼び出され、スプレッドシートが再計算される。

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

「Save」ボタン押下時、`onSaveWidget`関数が実行され、compare、compareTo、isLive、reportMode、フィルタ条件がウィジェットのメタデータとして保存される。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ウィジェット保存 | dashboard_widgets | UPDATE | ウィジェットのmeta情報を更新 |
| データ取得 | transactions | SELECT | 取引データを取得して支出を計算 |
| 予算データ取得 | budgets | SELECT | 予算データを取得（budgetモード時） |

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

#### dashboard_widgets

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

## メッセージ仕様

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

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| ウィジェットが存在しない | 「Save」ボタンが表示されない |
| データがない | グラフが空の状態で表示される |
| 平均データが不足 | 平均ラインが表示されない場合がある |

## 備考

- 支出は28日間で表示される（月による日数差を吸収するため）
- 平均は過去3ヶ月の累積支出から計算される
- 現在月の場合、当日までの累積支出が表示される（MTD: Month to Date）
- 日付フィルタはフィルタ対象から除外されている
- プライバシーフィルタが有効な場合、金額表示がマスクされる

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.ts | `loot-core/types/models` | `SpendingWidget`型の定義を確認 |
| 1-2 | spending-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/spending-spreadsheet.ts` | 支出データの集計ロジック、intervalData構造を理解 |

**読解のコツ**: `intervalData`配列（28要素）の構造と、compare/compareTo/budget/averageの各プロパティを確認する。

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

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

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

**主要処理フロー**:
1. **52-64行**: `Spending`関数 - ウィジェットデータの取得
2. **70-659行**: `SpendingInternal`関数 - メインのレンダリングロジック
3. **91-99行**: レポートモードと比較月の初期化
4. **140-149行**: getGraphData（スプレッドシートパラメータ）の生成
5. **151行**: `useReport`フック呼び出し

#### Step 3: データ取得層を理解する

スプレッドシート計算とデータ取得の流れを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | spending-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/spending-spreadsheet.ts` | `createSpendingSpreadsheet`関数の実装。28日分の累積支出計算 |
| 3-2 | reportRanges.ts | `packages/desktop-client/src/components/reports/reportRanges.ts` | `calculateSpendingReportTimeRange`関数 |

**主要処理フロー**:
- compare月とcompareTo月の取引データをクエリ
- 各日の累積支出を計算し、intervalData配列として返却
- 予算モードでは予算データも取得
- 平均モードでは過去3ヶ月のデータから平均を計算

#### Step 4: UIコンポーネントを理解する

グラフ表示とコントロールUIの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SpendingGraph.tsx | `packages/desktop-client/src/components/reports/graphs/SpendingGraph.tsx` | Rechartsを使用した支出推移グラフのレンダリング |
| 4-2 | ModeButton.tsx | `packages/desktop-client/src/components/reports/ModeButton.tsx` | レポートモード切替ボタン |
| 4-3 | LegendItem.tsx | `packages/desktop-client/src/components/reports/LegendItem.tsx` | 凡例表示コンポーネント |

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

```
Spending (エントリーポイント)
    │
    ├─ useWidget (ウィジェットデータ取得)
    │      └─ send('dashboard-get-widget')
    │
    └─ SpendingInternal (メインコンポーネント)
           │
           ├─ useRuleConditionFilters (フィルタ管理)
           │
           ├─ createSpendingSpreadsheet (データ計算)
           │      └─ useReport (データ取得フック)
           │
           ├─ SpaceBetween (コントロールUI)
           │      ├─ Button (Live/Static切替)
           │      ├─ Select (compare月選択)
           │      ├─ Select (compareTo月選択)
           │      └─ ModeButton (モード切替)
           │
           ├─ LegendItem (凡例)
           │
           ├─ AlignedText (サマリー表示)
           │
           └─ SpendingGraph (グラフ描画)
                  └─ Recharts (グラフライブラリ)
```

### データフロー図

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

URLパラメータ ─────────▶ useWidget ─────────────────▶ ウィジェットメタデータ
                              │
compare月選択 ────────▶ state (compare)
                              │
compareTo月選択 ──────▶ state (compareTo)
                              │
モード選択 ────────────▶ state (reportMode)
    │                         │
    │   single-month ─────────┼──▶ compareTo月と比較
    │   budget ───────────────┼──▶ 予算額と比較
    │   average ──────────────┼──▶ 過去3ヶ月平均と比較
                              │
Live/Static ───────────▶ state (isLive)
                              │
フィルタ(日付除く) ────▶ useRuleConditionFilters
                              │
                              ▼
                  createSpendingSpreadsheet
                              │
                              ▼
                        useReport
                              │
                              ▼
取引/予算データ(DB) ──▶ データ集計処理 ─────────────▶ intervalData[28]
                                                        compare
                                                        compareTo
                                                        budget
                                                        average
                              │
                              ▼
                      SpendingGraph
                              │
                              ▼
                        画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Spending.tsx | `packages/desktop-client/src/components/reports/reports/Spending.tsx` | ソース | メインコンポーネント |
| spending-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/spending-spreadsheet.ts` | ソース | データ集計ロジック |
| SpendingGraph.tsx | `packages/desktop-client/src/components/reports/graphs/SpendingGraph.tsx` | ソース | グラフ描画コンポーネント |
| ModeButton.tsx | `packages/desktop-client/src/components/reports/ModeButton.tsx` | ソース | モード切替ボタン |
| LegendItem.tsx | `packages/desktop-client/src/components/reports/LegendItem.tsx` | ソース | 凡例コンポーネント |
| FilterButton.tsx | `packages/desktop-client/src/components/filters/FiltersMenu.tsx` | ソース | フィルタボタン |
| AppliedFilters.tsx | `packages/desktop-client/src/components/filters/AppliedFilters.tsx` | ソース | 適用済みフィルタ表示 |
| reportRanges.ts | `packages/desktop-client/src/components/reports/reportRanges.ts` | ソース | 期間計算ユーティリティ |
| useReport.ts | `packages/desktop-client/src/components/reports/useReport.ts` | ソース | レポートデータ取得フック |
