# 画面設計書 30-レポートダッシュボード画面

## 概要

本ドキュメントは、Actual Budgetアプリケーションにおけるレポートダッシュボード画面の設計仕様を定義するものである。

### 本画面の処理概要

複数のレポートウィジェットをグリッドレイアウトで表示するカスタマイズ可能なダッシュボード画面である。純資産、キャッシュフロー、支出分析、カスタムレポートなど様々なウィジェットを追加・配置でき、ユーザーの分析ニーズに合わせたダッシュボードを構築できる。

**業務上の目的・背景**：家計管理において、収支状況や資産推移を視覚的に把握することは重要である。本画面は、様々な観点のレポートを一つのダッシュボードに集約することで、財務状況の総合的な把握を可能にする。ユーザーはウィジェットの追加・削除・配置変更を自由に行え、自分にとって最適なダッシュボードを構築できる。複数のダッシュボードを切り替えて使用することも可能。

**画面へのアクセス方法**：サイドバーの「Reports」メニュー、またはコマンドバーから `/reports` または `/reports/:dashboardId` ルートに遷移することでアクセスする。

**主要な操作・処理内容**：
1. ダッシュボードの表示・切り替え
2. ウィジェットの追加（様々なレポートタイプ）
3. ウィジェットのレイアウト編集（ドラッグ&ドロップ、リサイズ）
4. ウィジェットの削除・コピー
5. ダッシュボード設定のインポート・エクスポート
6. ダッシュボードのリセット・削除

**画面遷移**：
- 遷移元：サイドバー、コマンドバー
- 遷移先：各レポート詳細画面、カスタムレポート作成画面

**権限による表示制御**：特別な権限制御は設けられていない。一部のウィジェット（クロスオーバー、予算分析等）はフィーチャーフラグで表示制御。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | 予算レポート・ダッシュボード | 主機能 | レポートカードの一覧表示・ダッシュボード管理 |
| 33 | 収支レポート | 補助機能 | 収支レポートカードの表示 |
| 34 | カテゴリ別支出 | 補助機能 | カテゴリ別支出カードの表示 |
| 36 | カスタムレポート保存 | 補助機能 | カスタムレポート設定の保存・読み込み |

## 画面種別

ダッシュボード

## URL/ルーティング

- `/reports` - デフォルトダッシュボード
- `/reports/:dashboardId` - 指定ダッシュボード

デスクトップ・モバイル両対応（レスポンシブ）

## 入出力項目

| 項目名 | 項目ID | データ型 | 入力/出力 | 必須 | 説明 |
|--------|--------|----------|-----------|------|------|
| ダッシュボードID | dashboardId | string | 入力（URL） | 任意 | 表示対象のダッシュボードID |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| ヘッダータイトル | string | "Reports: {ダッシュボード名}" |
| ダッシュボードセレクター | select | ダッシュボード切り替え用ドロップダウン |
| ウィジェット追加ボタン | button | 新規ウィジェット追加メニュー |
| 編集モードボタン | button | ダッシュボード編集モードの切り替え |
| メニューボタン | button | リセット・インポート・エクスポート・削除メニュー |
| ウィジェットグリッド | grid | ドラッグ&ドロップ対応のグリッドレイアウト |
| ローディング表示 | indicator | データ取得中の表示 |

## イベント仕様

### 1-画面初期表示

画面表示時にダッシュボード設定とウィジェットデータを取得する。

**処理フロー**:
1. `useDashboardPages()` でダッシュボード一覧を取得
2. `useDashboard(dashboard.id)` で現在のダッシュボードのウィジェット設定を取得
3. `useReports()` でカスタムレポート一覧を取得
4. `sessionStorage` に現在のURLを保存
5. ウィジェットをレイアウトデータに変換

### 2-ウィジェット追加

「Add new widget」ボタン押下時にウィジェット追加メニューを表示する。

**処理フロー**:
1. ポップオーバーメニューを表示
2. ウィジェットタイプを選択（cash-flow, net-worth, spending等）
3. `dashboard-add-widget` API を呼び出し
4. カスタムレポートの場合は既存レポートを選択またはレポート作成画面へ遷移

### 3-レイアウト編集

編集モード中にウィジェットをドラッグ&ドロップまたはリサイズする。

**処理フロー**:
1. `isEditing` を `true` に設定
2. `ReactGridLayout` でドラッグ&ドロップ・リサイズを有効化
3. `onLayoutChange` でレイアウト変更を検知
4. `dashboard-update` API を呼び出してレイアウトを保存

### 4-ウィジェット削除

ウィジェットの削除ボタン押下時にウィジェットを削除する。

**処理フロー**:
1. `onRemoveWidget(widgetId)` を呼び出し
2. `dashboard-remove-widget` API を呼び出し

### 5-ウィジェットコピー

ウィジェットを別のダッシュボードにコピーする。

**処理フロー**:
1. ターゲットダッシュボードを選択
2. `dashboard-copy-widget` API を呼び出し

### 6-ダッシュボードリセット

ダッシュボードをデフォルト状態にリセットする。

**処理フロー**:
1. メニューから「Reset to default」を選択
2. `dashboard-reset` API を呼び出し
3. Undo通知を表示

### 7-インポート・エクスポート

ダッシュボード設定をJSON形式でインポート・エクスポートする。

**処理フロー（エクスポート）**:
1. 現在のレイアウトとウィジェット設定をJSON形式に変換
2. `window.Actual.saveFile` でファイル保存

**処理フロー（インポート）**:
1. `window.Actual.openFileDialog` でJSONファイルを選択
2. `dashboard-import` API を呼び出し
3. 成功時にUndo通知を表示、エラー時にエラー通知

### 8-ダッシュボード削除

ダッシュボードを削除する。

**処理フロー**:
1. メニューから「Delete dashboard」を選択
2. `dashboard-delete` API を呼び出し
3. 別のダッシュボードに遷移

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ウィジェット追加 | widgets | INSERT | ウィジェットの追加 |
| レイアウト変更 | widgets | UPDATE | 位置・サイズの更新 |
| ウィジェット削除 | widgets | DELETE | ウィジェットの削除 |
| ウィジェットコピー | widgets | INSERT | ウィジェットのコピー |
| ダッシュボードリセット | widgets | DELETE/INSERT | 全ウィジェット入れ替え |
| ダッシュボードインポート | widgets | DELETE/INSERT | 全ウィジェット入れ替え |
| ダッシュボード削除 | dashboard_pages, widgets | DELETE | ダッシュボードと関連ウィジェット削除 |

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

#### widgets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | UUID自動生成 | 一意識別子 |
| INSERT | type | ウィジェットタイプ | net-worth-card, cash-flow-card等 |
| INSERT | x, y, width, height | グリッド位置・サイズ | |
| INSERT | meta | JSON（設定データ） | ウィジェット固有設定 |
| INSERT | dashboard_page_id | ダッシュボードID | 所属ダッシュボード |
| UPDATE | x, y, width, height | 新しい位置・サイズ | WHERE id = :id |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | ローディング | "Loading reports..." | レポート読み込み中 |
| MSG-002 | ローディング | "Import is running..." | インポート処理中 |
| MSG-003 | 成功 | "Dashboard has been successfully reset to default state..." | リセット成功時 |
| MSG-004 | 成功 | "Dashboard has been successfully imported..." | インポート成功時 |
| MSG-005 | エラー | "Failed parsing the imported JSON." | JSONパースエラー |
| MSG-006 | エラー | バリデーションエラーメッセージ | バリデーションエラー |
| MSG-007 | エラー | "Failed importing the dashboard file." | インポート失敗 |
| MSG-008 | エラー | "Fatal error occurred: unable to open import file dialog." | ダイアログ表示失敗 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| カスタムレポートが見つからない | ウィジェットを表示しない |
| インポートファイル形式不正 | エラー通知を表示 |
| ダッシュボードが1つしかない場合の削除 | 削除ボタンを無効化 |

## 備考

- ウィジェットタイプ：net-worth-card, cash-flow-card, crossover-card, spending-card, budget-analysis-card, markdown-card, custom-report, summary-card, calendar-card, formula-card
- クロスオーバーレポートと予算分析レポートはフィーチャーフラグで制御
- 数式カードはformulaModeフィーチャーフラグで制御
- モバイルでは1列レイアウト、デスクトップでは12列グリッド
- 編集モードはデスクトップでのみ有効

---

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

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

### 推奨読解順序

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

ダッシュボードとウィジェットの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models/index.d.ts | `packages/loot-core/src/types/models/index.d.ts` | DashboardEntity, Widget, CustomReportWidget等の型 |

**読解のコツ**: Widgetは `type`, `x`, `y`, `width`, `height`, `meta` を持つ。typeによってmetaの構造が異なる。

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

ダッシュボード画面の全体構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Overview.tsx | `packages/desktop-client/src/components/reports/Overview.tsx` | メインコンポーネント（800行以上） |

**主要処理フロー**:
1. **68-100行目**: コンポーネント定義とステート・フック初期化
2. **112-161行目**: レイアウト計算（mobileLayout, desktopLayout）
3. **168-202行目**: 通知処理（インポート成功等）
4. **204-214行目**: onResetDashboard関数
5. **216-231行目**: onLayoutChange関数
6. **233-244行目**: onAddWidget関数
7. **285-366行目**: onImport関数
8. **398-814行目**: JSXレンダリング（ReactGridLayout含む）

#### Step 3: 各ウィジェットカードを理解する

レポートカードコンポーネントの実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | NetWorthCard.tsx | `packages/desktop-client/src/components/reports/reports/NetWorthCard.tsx` | 純資産カード |
| 3-2 | CashFlowCard.tsx | `packages/desktop-client/src/components/reports/reports/CashFlowCard.tsx` | キャッシュフローカード |
| 3-3 | SpendingCard.tsx | `packages/desktop-client/src/components/reports/reports/SpendingCard.tsx` | 支出カード |

#### Step 4: ダッシュボード管理フックを理解する

ダッシュボードデータの取得・更新を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | useDashboard.ts | `packages/desktop-client/src/hooks/useDashboard.ts` | ダッシュボード取得フック |

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

```
Overview
    │
    ├─ useDashboardPages()
    │      └─ ダッシュボード一覧取得
    │
    ├─ useDashboard(dashboard.id)
    │      └─ ウィジェット設定取得
    │
    ├─ useReports()
    │      └─ カスタムレポート一覧取得
    │
    ├─ useFeatureFlag()
    │      └─ crossoverReport, budgetAnalysisReport, formulaMode
    │
    ├─ DashboardHeader / DashboardSelector
    │      └─ ヘッダー・ダッシュボード切り替え
    │
    ├─ ReactGridLayout
    │      ├─ NetWorthCard
    │      ├─ CashFlowCard
    │      ├─ CrossoverCard
    │      ├─ SpendingCard
    │      ├─ BudgetAnalysisCard
    │      ├─ MarkdownCard
    │      ├─ CustomReportListCards
    │      ├─ SummaryCard
    │      ├─ CalendarCard
    │      └─ FormulaCard
    │
    ├─ onAddWidget()
    │      └─ send('dashboard-add-widget')
    │
    ├─ onRemoveWidget()
    │      └─ send('dashboard-remove-widget')
    │
    ├─ onLayoutChange()
    │      └─ send('dashboard-update')
    │
    ├─ onResetDashboard()
    │      └─ send('dashboard-reset')
    │
    ├─ onExport()
    │      └─ window.Actual.saveFile()
    │
    └─ onImport()
           └─ send('dashboard-import')
```

### データフロー図

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

サーバーDB ───────────▶ useDashboard() ──────────────────▶ widgets
                             │
                             ▼
                     レイアウト計算 ──────────────────────▶ currentLayout
                     (mobile/desktop)
                             │
                             ▼
                     ReactGridLayout
                             │
ドラッグ操作 ────────▶ onLayoutChange() ─────────────────▶ dashboard-update API
                             │
ウィジェット追加 ───▶ onAddWidget() ─────────────────────▶ dashboard-add-widget API
                             │
ウィジェット削除 ───▶ onRemoveWidget() ──────────────────▶ dashboard-remove-widget API
                             │
リセット ────────────▶ onResetDashboard() ───────────────▶ dashboard-reset API
                             │
インポート ──────────▶ onImport() ───────────────────────▶ dashboard-import API
                             │
エクスポート ────────▶ onExport() ───────────────────────▶ ファイル保存
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Overview.tsx | `packages/desktop-client/src/components/reports/Overview.tsx` | ソース | メインコンポーネント |
| index.tsx (reports) | `packages/desktop-client/src/components/reports/index.tsx` | ソース | ルーティング |
| DashboardHeader.tsx | `packages/desktop-client/src/components/reports/DashboardHeader.tsx` | ソース | ヘッダー |
| DashboardSelector.tsx | `packages/desktop-client/src/components/reports/DashboardSelector.tsx` | ソース | ダッシュボード選択 |
| NetWorthCard.tsx | `packages/desktop-client/src/components/reports/reports/NetWorthCard.tsx` | ソース | 純資産カード |
| CashFlowCard.tsx | `packages/desktop-client/src/components/reports/reports/CashFlowCard.tsx` | ソース | キャッシュフローカード |
| SpendingCard.tsx | `packages/desktop-client/src/components/reports/reports/SpendingCard.tsx` | ソース | 支出カード |
| MarkdownCard.tsx | `packages/desktop-client/src/components/reports/reports/MarkdownCard.tsx` | ソース | テキストウィジェット |
| CustomReportListCards.tsx | `packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx` | ソース | カスタムレポートカード |
| useDashboard.ts | `packages/desktop-client/src/hooks/useDashboard.ts` | ソース | ダッシュボードフック |
| useReports.ts | `packages/desktop-client/src/hooks/useReports.ts` | ソース | レポートフック |
| FinancesApp.tsx | `packages/desktop-client/src/components/FinancesApp.tsx` | ソース | ルーティング定義（258行目） |
