# 画面設計書 1-ホーム画面

## 概要

本ドキュメントは、OpenCodeデスクトップアプリケーションのホーム画面の設計仕様を定義する。

### 本画面の処理概要

ホーム画面は、OpenCodeデスクトップアプリケーション起動時に最初に表示される画面であり、ユーザーがプロジェクトを選択・管理するための中心的なインターフェースを提供する。

**業務上の目的・背景**：開発者がOpenCodeを使用してAI支援開発を行う際、まず作業対象となるプロジェクトディレクトリを選択する必要がある。この画面は、最近開いたプロジェクトへの迅速なアクセスと、新規プロジェクトの追加を可能にし、開発作業の開始をスムーズにする役割を担う。

**画面へのアクセス方法**：アプリケーション起動時に自動的に表示される。また、サイドバーのホームアイコンをクリック、またはプロジェクトが選択されていない状態でルートURL（/）にアクセスすることで表示される。

**主要な操作・処理内容**：
1. 最近開いたプロジェクト一覧の表示（最大5件、更新日時順）
2. プロジェクトディレクトリの選択・オープン
3. サーバー接続状態の確認と切り替え
4. ディレクトリピッカーダイアログによる新規プロジェクト追加

**画面遷移**：
- 遷移元：アプリ起動時、レイアウト画面（プロジェクト未選択時）
- 遷移先：ディレクトリレイアウト画面（プロジェクト選択後）

**権限による表示制御**：特になし。ただし、サーバー接続状態によってディレクトリ選択方法が変化する（ローカルサーバーの場合はネイティブダイアログ、リモートサーバーの場合はカスタムダイアログを使用）。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 49 | プロジェクト検出 | 主機能 | 最近開いたプロジェクト一覧の表示、プロジェクトディレクトリの自動検出 |
| 48 | 設定ファイル管理 | 補助機能 | ユーザー設定に基づくホームディレクトリパスの取得 |
| 56 | 国際化 | 補助機能 | 画面内テキストの多言語対応（language.t関数による翻訳） |

## 画面種別

一覧 / ダッシュボード

## URL/ルーティング

`/` (ルート)

## 入出力項目

| 項目名 | 入力/出力 | 型 | 必須 | 説明 |
|--------|----------|------|------|------|
| プロジェクトディレクトリパス | 入力 | string | - | 新規プロジェクトとして開くディレクトリの絶対パス |

## 表示項目

| 項目名 | 型 | 説明 |
|--------|------|------|
| OpenCodeロゴ | 画像 | アプリケーションロゴ（薄い透過表示） |
| サーバー接続状態ボタン | ボタン | 接続中のサーバー名と接続状態インジケーター |
| 最近開いたプロジェクト一覧 | リスト | 最大5件の最近開いたプロジェクト |
| プロジェクトパス | テキスト | ホームディレクトリを~に置換した相対パス表示 |
| 最終更新日時 | テキスト | プロジェクトの最終更新からの相対時間 |
| プロジェクト追加ボタン | ボタン | 新規プロジェクトを開くためのボタン |
| 空状態メッセージ | テキスト | プロジェクトがない場合の案内メッセージ |

## イベント仕様

### 1-プロジェクト選択

ユーザーがプロジェクト一覧から項目をクリックした際の処理。

処理フロー：
1. `layout.projects.open(directory)` でプロジェクトを開く
2. `server.projects.touch(directory)` でサーバーに最終アクセス時刻を通知
3. `navigate(\`/${base64Encode(directory)}\`)` でディレクトリレイアウト画面に遷移

### 2-新規プロジェクト追加

「プロジェクトを開く」ボタンをクリックした際の処理。

処理フロー（ローカルサーバー接続時）：
1. `platform.openDirectoryPickerDialog()` でネイティブディレクトリ選択ダイアログを表示
2. ユーザーが選択したディレクトリを取得
3. 選択されたディレクトリごとに `openProject()` を実行

処理フロー（リモートサーバー接続時）：
1. `dialog.show(() => <DialogSelectDirectory />)` でカスタムダイアログを表示
2. ユーザーがディレクトリパスを入力または選択
3. 選択されたディレクトリに対して `openProject()` を実行

### 3-サーバー切り替え

サーバー接続状態ボタンをクリックした際の処理。

処理フロー：
1. `dialog.show(() => <DialogSelectServer />)` でサーバー選択ダイアログを表示
2. ユーザーが接続先サーバーを選択
3. サーバー接続状態が更新される

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| プロジェクト選択 | project | UPDATE | プロジェクトの最終アクセス時刻を更新 |
| 新規プロジェクト追加 | project | INSERT | 新規プロジェクトレコードを作成 |

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

#### project

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | time.updated | 現在のタイムスタンプ（Date.now()） | プロジェクト選択時 |
| INSERT | worktree | 選択されたディレクトリパス | 新規追加時 |
| INSERT | time.created | 現在のタイムスタンプ | 新規追加時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| home.recentProjects | 情報 | 最近開いたプロジェクト | プロジェクトが1件以上存在する場合 |
| home.empty.title | 情報 | プロジェクトがありません | プロジェクトが存在しない場合 |
| home.empty.description | 情報 | プロジェクトを開いて開始してください | プロジェクトが存在しない場合 |
| command.project.open | アクション | プロジェクトを開く | ボタンラベル |

## 例外処理

| 状況 | 処理内容 |
|------|---------|
| サーバー接続失敗 | サーバー接続状態インジケーターが赤色に変化、ダイアログで再接続を促す |
| ディレクトリ選択キャンセル | 何も処理せず現在の状態を維持 |
| 無効なディレクトリパス | トーストメッセージでエラーを通知 |

## 備考

- プロジェクト一覧は更新日時の降順でソートされ、最大5件まで表示される
- ホームディレクトリパスは`~`に置換されて表示される
- 複数プロジェクトの同時選択が可能（multipleオプション）

---

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

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

### 推奨読解順序

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

プロジェクト情報やグローバル状態の型定義を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | global-sync.tsx | `packages/app/src/context/global-sync.tsx` | グローバル同期データの構造（project配列など） |
| 1-2 | layout.tsx | `packages/app/src/context/layout.tsx` | レイアウトコンテキストのプロジェクト管理関数 |

**読解のコツ**: `useGlobalSync`が返す`sync.data`にプロジェクト一覧が格納されている。

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

処理の起点となるホーム画面コンポーネントを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | home.tsx | `packages/app/src/pages/home.tsx` | ホーム画面のメインコンポーネント |

**主要処理フロー**:
1. **17行目**: `Home`関数コンポーネントの定義開始
2. **18-24行目**: 各種コンテキストのフック呼び出し（sync, layout, platform, dialog, navigate, server, language）
3. **25行目**: ホームディレクトリパスのメモ化
4. **26-31行目**: 最近開いたプロジェクト一覧の取得とソート
5. **40-44行目**: `openProject`関数 - プロジェクト選択時の処理
6. **46-69行目**: `chooseProject`関数 - ディレクトリピッカーの表示制御

#### Step 3: コンテキストとダイアログを理解する

画面で使用される依存コンポーネントを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dialog-select-directory.tsx | `packages/app/src/components/dialog-select-directory.tsx` | ディレクトリ選択ダイアログの実装 |
| 3-2 | dialog-select-server.tsx | `packages/app/src/components/dialog-select-server.tsx` | サーバー選択ダイアログの実装 |
| 3-3 | server.tsx | `packages/app/src/context/server.tsx` | サーバー接続状態の管理 |

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

```
Home (home.tsx)
    │
    ├─ useGlobalSync() ─────────> GlobalSyncContext
    │      └─ sync.data.project (プロジェクト一覧取得)
    │
    ├─ useLayout() ─────────────> LayoutContext
    │      └─ layout.projects.open() (プロジェクトを開く)
    │
    ├─ useServer() ─────────────> ServerContext
    │      ├─ server.healthy() (接続状態確認)
    │      ├─ server.isLocal() (ローカル判定)
    │      └─ server.projects.touch() (アクセス記録)
    │
    ├─ usePlatform() ───────────> PlatformContext
    │      └─ platform.openDirectoryPickerDialog() (ネイティブダイアログ)
    │
    ├─ useDialog() ─────────────> DialogContext
    │      └─ dialog.show() (カスタムダイアログ表示)
    │
    └─ useNavigate() ───────────> SolidJS Router
           └─ navigate() (画面遷移)
```

### データフロー図

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

プロジェクト一覧          createMemo(recent)              ソート済み一覧表示
(sync.data.project) ────▶ (更新日時降順、最大5件) ────▶ (<For each={recent()}>)

ディレクトリ選択          chooseProject()                 画面遷移
(ダイアログ/ピッカー) ──▶ openProject() ───────────────▶ navigate()
                              │
                              └─▶ layout.projects.open()
                              └─▶ server.projects.touch()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| home.tsx | `packages/app/src/pages/home.tsx` | ソース | ホーム画面メインコンポーネント |
| global-sync.tsx | `packages/app/src/context/global-sync.tsx` | ソース | グローバルデータ同期コンテキスト |
| layout.tsx | `packages/app/src/context/layout.tsx` | ソース | レイアウト管理コンテキスト |
| server.tsx | `packages/app/src/context/server.tsx` | ソース | サーバー接続管理コンテキスト |
| platform.tsx | `packages/app/src/context/platform.tsx` | ソース | プラットフォーム固有機能コンテキスト |
| language.tsx | `packages/app/src/context/language.tsx` | ソース | 国際化コンテキスト |
| dialog-select-directory.tsx | `packages/app/src/components/dialog-select-directory.tsx` | ソース | ディレクトリ選択ダイアログ |
| dialog-select-server.tsx | `packages/app/src/components/dialog-select-server.tsx` | ソース | サーバー選択ダイアログ |
| button.tsx | `packages/ui/src/button.tsx` | ソース | UIボタンコンポーネント |
| logo.tsx | `packages/ui/src/logo.tsx` | ソース | ロゴコンポーネント |
| encode.ts | `packages/util/src/encode.ts` | ソース | Base64エンコード関数 |
