# 画面設計書 34-カスタムレポート画面

## 概要

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

### 本画面の処理概要

カスタムレポート画面は、ユーザーが自由にカスタマイズできる高度なレポート作成・分析画面である。グラフの種類、期間、グループ化方法、表示オプションなど多数のパラメータを設定し、独自のレポートを作成・保存できる。

**業務上の目的・背景**：標準レポートでは対応しきれない多様な分析ニーズに対応するため、高度なカスタマイズ機能を提供する。ユーザーは期間、グラフタイプ、グループ化軸（カテゴリ/支払先/口座/期間など）、残高タイプ（支出/収入/純額/債務）を自由に組み合わせ、独自の視点でデータを分析できる。作成したレポート設定は保存して再利用でき、定期的な分析作業を効率化する。

**画面へのアクセス方法**：サイドバーの「レポート」メニューをクリック後、レポートダッシュボードから「カスタムレポート」を選択、または直接 `/reports/custom` URLにアクセスする。保存済みレポートを開く場合は `/reports/custom/:id` でアクセスする。

**主要な操作・処理内容**：
1. 期間設定：開始日/終了日の選択、ライブ/スタティックモード切替、日付範囲プリセット
2. グラフタイプ選択：棒グラフ、折れ線グラフ、円グラフ、積み上げグラフ、エリアグラフ、テーブルなど
3. グループ化設定：カテゴリ、支払先、口座、期間（日/週/月/年）でデータをグループ化
4. 残高タイプ設定：支出、収入、純額、債務から選択
5. 表示オプション：空データ表示、予算外口座表示、非表示カテゴリ表示、未分類表示など
6. カテゴリフィルタ：分析対象カテゴリの選択
7. レポート保存：現在の設定を名前付きで保存
8. レポート読み込み：保存済みレポートの選択・適用

**画面遷移**：レポートダッシュボード画面（`/reports`）から遷移する。保存時に新規レポートIDが発行されると `/reports/custom/:id` に遷移する。

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 36 | カスタムレポート保存 | 主機能 | カスタマイズ可能なレポートの作成・編集 |
| 33 | 収支レポート | 補助機能 | 収支データの取得・表示 |
| 37 | レポートスナップショット | 補助機能 | レポートのスナップショット保存 |

## 画面種別

登録・編集・分析画面

## URL/ルーティング

- `/reports/custom` - 新規レポート作成
- `/reports/custom/:id` - 保存済みレポート編集

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 説明 |
|--------|----------|---------|------|------|
| 開始日 | 入力 | string | Yes | 表示期間の開始日 |
| 終了日 | 入力 | string | Yes | 表示期間の終了日 |
| 日付範囲タイプ | 入力 | string | Yes | プリセット日付範囲の種類 |
| スタティックモード | 入力 | boolean | Yes | 日付固定の有無 |
| レポートモード | 入力 | string | Yes | 'total' または 'time' |
| グラフタイプ | 入力 | string | Yes | BarGraph, LineGraph, DonutGraph等 |
| グループ化軸 | 入力 | string | Yes | Category, Payee, Account, Interval等 |
| 残高タイプ | 入力 | string | Yes | Payment, Deposit, Net, Debt |
| ソート順 | 入力 | string | Yes | asc または desc |
| 表示間隔 | 入力 | string | Yes | Daily, Weekly, Monthly, Yearly |
| showEmpty | 入力 | boolean | No | 空データの表示 |
| showOffBudget | 入力 | boolean | No | 予算外口座の表示 |
| showHiddenCategories | 入力 | boolean | No | 非表示カテゴリの表示 |
| showUncategorized | 入力 | boolean | No | 未分類の表示 |
| includeCurrentInterval | 入力 | boolean | No | 現在期間の含有 |
| trimIntervals | 入力 | boolean | No | 期間のトリミング |
| フィルタ条件 | 入力 | array | No | RuleConditionEntity配列 |
| フィルタ演算子 | 入力 | string | No | 'and' または 'or' |
| 選択カテゴリ | 入力 | array | No | 対象カテゴリID配列 |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| レポート名 | string | 保存済みレポートの名前（未保存の場合は「Unsaved report」） |
| 合計金額 | number | 選択した残高タイプの合計額 |
| グラフ | chart | 選択したグラフタイプで描画されたデータ |
| 凡例 | component | グラフの凡例（オプション） |
| サマリー | component | 期間サマリー（オプション） |
| サイドバー | component | 設定パネル |
| ツールバー | component | グラフタイプ切替、表示オプション、保存ボタン |

## イベント仕様

### 1-期間設定変更

サイドバーの期間設定を変更すると、`onChangeDates`関数が呼び出され、`startDate`, `endDate`状態が更新される。`onReportChange({ type: 'modify' })`により保存状態が「modified」に変更される。

### 2-グラフタイプ変更

サイドバーまたはツールバーからグラフタイプを変更すると、`setGraphType`により状態が更新される。グラフタイプによっては無効なオプションが自動調整される（`defaultModeItems`, `defaultItems`）。

### 3-グループ化設定変更

サイドバーからグループ化軸を変更すると、`setGroupBy`により状態が更新される。グラフタイプとの整合性が自動チェックされる。

### 4-レポート保存

ツールバーの保存ボタン押下時、レポート設定がサーバーに保存される。新規保存時はレポートIDが発行され、URLが遷移する。`savedStatus`が「saved」に更新される。

### 5-レポートリロード

ツールバーからリロードを選択すると、`onReportChange({ type: 'reload' })`により保存済み設定が復元される。

### 6-レポートリセット

ツールバーからリセットを選択すると、`onReportChange({ type: 'reset' })`によりデフォルト設定に戻る。

### 7-表示オプション切替

凡例表示、サマリー表示、ラベル表示をツールバーから切替。`useLocalPref`を使用してローカル設定として保存される。

### 8-フィルタ適用

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

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| レポート保存（新規） | custom_reports | INSERT | 新規レポート設定を保存 |
| レポート保存（更新） | custom_reports | UPDATE | 既存レポート設定を更新 |
| データ取得 | transactions | SELECT | 取引データを取得してグラフ用データを計算 |
| カテゴリ取得 | categories | SELECT | カテゴリ一覧を取得 |
| 支払先取得 | payees | SELECT | 支払先一覧を取得 |
| 口座取得 | accounts | SELECT | 口座一覧を取得 |

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

#### custom_reports

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | 全設定項目 | CustomReportEntity構造体 | レポート保存時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| MSG_FILTER_WARNING | 警告 | This report is configured to use a non-existing filter value (i.e. category/account/payee). | フィルタに無効な値が含まれる場合 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| フィルタに無効な値が含まれる | 警告メッセージを表示 |
| 複雑なカテゴリ条件 | カテゴリセレクターが無効化される |
| データがない | グラフが空の状態またはローディング表示 |

## 備考

- セッションストレージを使用して編集中の設定を一時保存
- グラフタイプによって有効なオプションが異なる（disabledList参照）
- 複雑なカテゴリフィルタ条件はカテゴリセレクターと相互排他
- プライバシーフィルタが有効な場合、金額表示がマスクされる
- モバイル画面幅ではサイドバーが非表示

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.ts | `loot-core/types/models` | `CustomReportEntity`, `DataEntity`型の定義を確認 |
| 1-2 | ReportOptions.ts | `packages/desktop-client/src/components/reports/ReportOptions.ts` | レポートオプションの定義、defaultReport |

**読解のコツ**: `CustomReportEntity`の全プロパティを確認し、各設定項目の意味を把握する。

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

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

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

**主要処理フロー**:
1. **120-129行**: `CustomReport`関数 - URLパラメータからレポートIDを取得
2. **135-1012行**: `CustomReportInner`関数 - メインのレンダリングロジック
3. **170-176行**: セッションストレージからの設定復元
4. **443-475行**: getGroupData（グループ化スプレッドシート）
5. **477-520行**: getGraphData（グラフ用スプレッドシート）
6. **521-522行**: useReportフック呼び出し

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | custom-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/custom-spreadsheet.ts` | グラフデータの集計ロジック |
| 3-2 | grouped-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/grouped-spreadsheet.ts` | グループ化データの集計ロジック |
| 3-3 | disabledList.ts | `packages/desktop-client/src/components/reports/disabledList.ts` | グラフタイプごとの無効オプション定義 |

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

サイドバー、ツールバー、グラフの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ReportSidebar.tsx | `packages/desktop-client/src/components/reports/ReportSidebar.tsx` | 設定パネルの実装 |
| 4-2 | ReportTopbar.tsx | `packages/desktop-client/src/components/reports/ReportTopbar.tsx` | ツールバーの実装 |
| 4-3 | ChooseGraph.tsx | `packages/desktop-client/src/components/reports/ChooseGraph.tsx` | グラフタイプに応じたグラフ選択・描画 |

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

```
CustomReport (エントリーポイント)
    │
    ├─ useCustomReport (保存済みレポートデータ取得)
    │
    └─ CustomReportInner (メインコンポーネント)
           │
           ├─ useCategories, usePayees, useAccounts (マスタデータ)
           │
           ├─ useRuleConditionFilters (フィルタ管理)
           │
           ├─ useSelectedCategories (カテゴリ選択状態)
           │
           ├─ createGroupedSpreadsheet / createCustomSpreadsheet
           │      └─ useReport (データ取得フック)
           │
           ├─ ReportSidebar (設定サイドバー)
           │      ├─ 期間設定コントロール
           │      ├─ グラフタイプ選択
           │      ├─ グループ化設定
           │      ├─ 表示オプション
           │      └─ カテゴリセレクター
           │
           ├─ ReportTopbar (ツールバー)
           │      ├─ 保存/リロード/リセット
           │      └─ 表示切替（凡例/サマリー/ラベル）
           │
           ├─ ChooseGraph (グラフ描画)
           │      └─ 各種グラフコンポーネント
           │
           ├─ ReportLegend (凡例)
           │
           └─ ReportSummary (サマリー)
```

### データフロー図

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

URLパラメータ ─────────▶ useCustomReport ────────────▶ 保存済みレポート設定
                              │
セッションストレージ ──▶ 設定復元
                              │
サイドバー設定 ────────▶ state群（多数）
                              │
                              ├──▶ createGroupedSpreadsheet
                              │          │
                              │          ▼
                              │    useReport('grouped')
                              │          │
                              │          ▼
                              │    groupedData
                              │
                              └──▶ createCustomSpreadsheet
                                        │
                                        ▼
                                  useReport('default')
                                        │
                                        ▼
                                    graphData
                                        │
                                        ▼
取引/カテゴリ/          ────────▶ DataEntity
支払先/口座(DB)                        │
                                        ▼
                              ChooseGraph / ReportLegend / ReportSummary
                                        │
                                        ▼
                                  画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CustomReport.tsx | `packages/desktop-client/src/components/reports/reports/CustomReport.tsx` | ソース | メインコンポーネント |
| custom-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/custom-spreadsheet.ts` | ソース | グラフデータ集計 |
| grouped-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/grouped-spreadsheet.ts` | ソース | グループ化データ集計 |
| ReportSidebar.tsx | `packages/desktop-client/src/components/reports/ReportSidebar.tsx` | ソース | 設定サイドバー |
| ReportTopbar.tsx | `packages/desktop-client/src/components/reports/ReportTopbar.tsx` | ソース | ツールバー |
| ChooseGraph.tsx | `packages/desktop-client/src/components/reports/ChooseGraph.tsx` | ソース | グラフ選択・描画 |
| ReportLegend.tsx | `packages/desktop-client/src/components/reports/ReportLegend.tsx` | ソース | 凡例コンポーネント |
| ReportSummary.tsx | `packages/desktop-client/src/components/reports/ReportSummary.tsx` | ソース | サマリーコンポーネント |
| ReportOptions.ts | `packages/desktop-client/src/components/reports/ReportOptions.ts` | ソース | オプション定義 |
| disabledList.ts | `packages/desktop-client/src/components/reports/disabledList.ts` | ソース | 無効オプション定義 |
| setSessionReport.ts | `packages/desktop-client/src/components/reports/setSessionReport.ts` | ソース | セッション保存 |
