# 機能設計書 33-設定画面

## 概要

本ドキュメントは、Liam DBアプリケーションにおける組織設定画面について記述する。本機能は、組織管理者が一般設定、メンバー管理、請求設定、プロジェクト設定を一元的に管理できるタブベースのインターフェースを提供する。

### 本機能の処理概要

**業務上の目的・背景**：マルチテナント型SaaSアプリケーションにおいて、組織レベルの各種設定を効率的に管理する仕組みが必要である。本機能は、組織名の変更、メンバー管理、請求設定、プロジェクト設定を統合的なUIで提供し、管理業務の効率化を実現する。

**機能の利用シーン**：
- 組織名を変更する場面（会社名変更、チーム名変更等）
- 組織メンバーの一覧確認・招待・削除を行う場面
- 組織の請求・サブスクリプション情報を確認する場面（実装予定）
- プロジェクト設定を管理する場面（実装予定）
- 組織を削除する場面

**主要な処理内容**：
1. 一般設定（General）：組織名の表示・更新、組織削除
2. メンバー設定（Members）：メンバー一覧表示、招待、削除
3. 請求設定（Billing）：請求・サブスクリプション設定（実装準備中）
4. プロジェクト設定（Projects）：プロジェクト関連設定（実装準備中）

**関連システム・外部連携**：
- Supabase：認証およびデータベース操作
- Next.js：Server Actions、ルーティング

**権限による制御**：
- 設定画面へのアクセス：組織メンバーのみ（RLSで制御）
- 組織削除：組織メンバーのみ実行可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 16 | 設定-一般画面 | 主画面 | 組織の一般設定を管理 |
| 17 | 設定-プロジェクト画面 | 主画面 | 組織のプロジェクト設定を管理（実装準備中） |
| 18 | 設定-メンバー画面 | 主画面 | 組織メンバーの管理画面 |
| 19 | 設定-請求画面 | 主画面 | 請求およびサブスクリプション設定を管理（実装準備中） |

## 機能種別

CRUD操作 / 管理画面

## 入力仕様

### 入力パラメータ

#### 組織名更新

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| organizationId | string | Yes | 組織ID | UUID形式 |
| name | string | Yes | 新しい組織名 | 空文字不可、トリム処理 |

#### 組織削除

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| organizationId | string | Yes | 組織ID | UUID形式 |
| confirmationText | string | Yes | 確認テキスト | 組織名と完全一致 |

### 入力データソース

- 画面入力（組織名フォーム、削除確認フォーム）
- URLパラメータ（タブ指定）
- Cookie（組織ID）

## 出力仕様

### 出力データ

#### 組織名更新結果

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | boolean | 処理成功フラグ |
| error | string \| null | エラーメッセージ |
| message | string \| null | 成功メッセージ |

#### 組織削除結果

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | boolean | 処理成功フラグ |
| error | string \| null | エラーメッセージ |
| message | string \| null | 成功メッセージ |

### 出力先

- 画面表示（Toast通知、フォーム）
- データベース（organizationsテーブル）
- セッションストレージ（削除成功メッセージ）

## 処理フロー

### 処理シーケンス

#### 設定画面表示フロー

```
1. /settings/* URLへアクセス
   └─ layout.tsxがレンダリング
2. ヘッダーからURLパスを取得
   └─ x-url-pathヘッダーを参照
3. タブ値の決定
   └─ パスの最後のセグメントをValibotで検証
4. 設定画面レイアウト表示
   └─ TabsRoot + SettingsHeader
5. 子ページのレンダリング
   └─ TabsContent内にchildren表示
```

#### 組織名更新フロー

```
1. 組織名入力フィールドを編集
   └─ defaultValueに現在の組織名
2. Saveボタンクリック
   └─ form action経由でupdateAction実行
3. Server Action実行（updateOrganizationName）
   └─ 空文字チェック、トリム処理
4. データベース更新
   └─ organizations.nameをUPDATE
5. パスの再検証
   └─ revalidatePath実行
6. Toast通知表示
   └─ useEffectで状態変化を検知
```

#### 組織削除フロー

```
1. Delete Organizationセクション表示
   └─ 危険操作として赤系UIで表示
2. Deleteボタンクリック
   └─ DeleteConfirmationModal表示
3. 確認テキスト入力
   └─ 組織名と完全一致を要求
4. 削除確認ボタンクリック
   └─ deleteAction実行
5. Server Action実行（deleteOrganization）
   └─ 組織を削除
6. リダイレクト
   └─ sessionStorageにメッセージ保存後、組織一覧へ
```

### フローチャート

```mermaid
flowchart TD
    A[/settings/* アクセス] --> B[URLパス解析]
    B --> C{タブ値有効?}
    C -->|No| D[デフォルトタブ]
    C -->|Yes| E[指定タブ]
    D --> F[レイアウト表示]
    E --> F
    F --> G{タブ選択}
    G -->|General| H[一般設定ページ]
    G -->|Members| I[メンバー設定ページ]
    G -->|Billing| J[請求設定ページ]
    G -->|Projects| K[プロジェクト設定ページ]

    H --> L{操作}
    L -->|組織名変更| M[updateOrganizationName]
    M --> N[DB更新]
    N --> O[Toast: 成功]
    L -->|組織削除| P[確認モーダル表示]
    P --> Q{確認テキスト一致?}
    Q -->|No| R[削除ボタン無効]
    Q -->|Yes| S[deleteOrganization]
    S --> T[sessionStorage保存]
    T --> U[組織一覧へリダイレクト]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-01 | 認証必須 | 設定画面アクセスには認証が必要 | 全ページ |
| BR-33-02 | 組織ID必須 | 有効な組織IDがCookieに必要 | 全ページ |
| BR-33-03 | 組織名非空 | 組織名は空文字不可 | 組織名更新時 |
| BR-33-04 | 削除確認 | 組織削除時は組織名の完全一致入力が必要 | 組織削除時 |
| BR-33-05 | タブURLパス | URLパスの末尾セグメントがタブ値に対応 | タブ切り替え時 |

### 計算ロジック

タブ値の決定：URLパスの最後のセグメントをValibotスキーマで検証
```typescript
const pathSegments = urlPath.split('/')
const lastSegment = pathSegments[pathSegments.length - 1]
const result = safeParse(SettingsTabSchema, lastSegment)
```

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 組織情報取得 | organizations | SELECT | 組織名等の取得 |
| 組織名更新 | organizations | UPDATE | 組織名の変更 |
| 組織削除 | organizations | DELETE | 組織の削除 |
| メンバー取得 | organization_members, users | SELECT | メンバー一覧取得 |
| 招待取得 | invitations | SELECT | 招待一覧取得 |

### テーブル別操作詳細

#### organizations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name | id = organizationId | 組織情報取得 |
| UPDATE | name | 入力値（トリム済み） | 組織名更新 |
| DELETE | - | id = organizationId | 組織削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 認証エラー | 組織ID取得失敗 | ログインページへリダイレクト |
| - | 組織不存在 | 指定IDの組織が存在しない | 404ページ表示 |
| - | バリデーションエラー | 組織名が空 | 'Organization name cannot be empty'メッセージ |
| - | DB更新エラー | UPDATE失敗 | 'Failed to update organization name'メッセージ |
| - | 確認テキスト不一致 | 削除確認時に組織名と不一致 | 削除ボタン無効化 |

### リトライ仕様

リトライ機構は実装されていない。エラー発生時はユーザーが再度操作を行う。

## トランザクション仕様

単一テーブルへの単一操作のため、明示的なトランザクション管理は不要。組織削除時は関連データのカスケード削除がデータベース側で処理される。

## パフォーマンス要件

- 設定画面表示：サブセカンドでの応答
- 組織名更新：サブセカンドでの応答
- 組織削除：関連データ量に依存、数秒の遅延が発生する可能性

## セキュリティ考慮事項

- RLSにより組織メンバーのみがアクセス可能
- 組織削除は確認テキスト（組織名完全一致）を要求
- Server Actions経由でのみDB操作を実行
- XSS対策としてReactの自動エスケープを活用

## 備考

- Billing、Projectsタブは現在実装準備中（プレースホルダー表示）
- 削除成功メッセージはsessionStorageに保存し、リダイレクト先で表示
- useActionStateフックを使用した状態管理とToast通知の連携

---

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

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

### 推奨読解順序

#### Step 1: 設定画面の構造を理解する

設定画面全体のレイアウトとタブ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constants.ts | `frontend/apps/app/app/settings/constants.ts` | SETTINGS_TAB定数とValibotスキーマ |
| 1-2 | layout.tsx | `frontend/apps/app/app/settings/layout.tsx` | TabsRoot/TabsContentによるタブ構造 |

**読解のコツ**: Valibotのunion/literalを使用してタブ値の型安全性を確保している。

#### Step 2: 各タブページを理解する

各設定ページのルーティングと構成を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | page.tsx | `frontend/apps/app/app/settings/general/page.tsx` | 一般設定ページのエントリーポイント |
| 2-2 | page.tsx | `frontend/apps/app/app/settings/members/page.tsx` | メンバー設定ページのエントリーポイント |
| 2-3 | page.tsx | `frontend/apps/app/app/settings/billing/page.tsx` | 請求設定ページ（プレースホルダー） |
| 2-4 | page.tsx | `frontend/apps/app/app/settings/projects/page.tsx` | プロジェクト設定ページ（プレースホルダー） |

**主要処理フロー**:
1. **6-14行目（general/page.tsx）**: getOrganizationIdでnullの場合はloginへリダイレクト
2. **7-26行目（members/page.tsx）**: 組織情報取得とOrganizationMembersPageへの受け渡し

#### Step 3: 一般設定の実装を理解する

組織名変更と削除機能の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | GeneralPage.tsx | `frontend/apps/app/components/GeneralPage/GeneralPage.tsx` | サーバーコンポーネント |
| 3-2 | GeneralPageClient.tsx | `frontend/apps/app/components/GeneralPage/components/GeneralPageClient/GeneralPageClient.tsx` | クライアントコンポーネント |
| 3-3 | updateOrganizationName.ts | `frontend/apps/app/components/GeneralPage/components/GeneralPageClient/actions/updateOrganizationName.ts` | 組織名更新Server Action |

**主要処理フロー**:
- **24-28行目（GeneralPageClient.tsx）**: useActionStateで更新アクションの状態管理
- **38-52行目**: 状態変化時のToast通知表示
- **102-111行目**: フォームとServer Actionの連携

#### Step 4: メンバー設定の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | OrganizationMembersPage.tsx | `frontend/apps/app/components/OrganizationMembersPage/OrganizationMembersPage.tsx` | メンバーページサーバーコンポーネント |
| 4-2 | getMembersAndInvites.ts | `frontend/apps/app/components/OrganizationMembersPage/services/getMembersAndInvites.ts` | メンバー・招待データ取得 |

**主要処理フロー**:
- **21-22行目**: メンバーと招待データの並行取得
- **35-40行目**: ClientSearchWrapperへのデータ受け渡し

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

```
/settings/* (layout.tsx)
    │
    ├─ SettingsHeader（タブナビゲーション）
    │
    ├─ /settings/general (page.tsx)
    │      └─ GeneralPage
    │             └─ GeneralPageClient
    │                    ├─ updateOrganizationAction
    │                    │      └─ updateOrganizationName
    │                    │             └─ supabase.from('organizations').update()
    │                    │
    │                    └─ deleteOrganizationAction
    │                           └─ deleteOrganization
    │                                  └─ supabase.from('organizations').delete()
    │
    ├─ /settings/members (page.tsx)
    │      └─ OrganizationMembersPage
    │             ├─ getOrganizationMembers
    │             ├─ getOrganizationInvites
    │             └─ ClientSearchWrapper
    │
    ├─ /settings/billing (page.tsx) - プレースホルダー
    │
    └─ /settings/projects (page.tsx) - プレースホルダー
```

### データフロー図

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

設定画面アクセス:
URLパス ───▶ getDefaultTabFromPath ───▶ TabsRoot defaultValue
                                              │
                                              └───▶ タブ表示

組織名更新:
フォーム入力 ───▶ updateAction ───▶ updateOrganizationName
                                          │
                                          ├─ バリデーション
                                          └─ organizations UPDATE
                                                    │
                                          useActionState ◀──┘
                                                    │
                                                    └───▶ Toast通知

組織削除:
確認テキスト ───▶ DeleteConfirmationModal
                         │
                         ├─ テキスト一致確認
                         └─ deleteAction ───▶ deleteOrganization
                                                    │
                                                    └─ organizations DELETE
                                                              │
                                          sessionStorage ◀────┘
                                                    │
                                                    └───▶ 組織一覧へリダイレクト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| layout.tsx | `frontend/apps/app/app/settings/layout.tsx` | ソース | 設定画面レイアウト |
| constants.ts | `frontend/apps/app/app/settings/constants.ts` | ソース | タブ定義・スキーマ |
| SettingsHeader.tsx | `frontend/apps/app/app/settings/components/components/SettingsHeader/SettingsHeader.tsx` | ソース | タブナビゲーション |
| page.tsx (general) | `frontend/apps/app/app/settings/general/page.tsx` | ソース | 一般設定ページ |
| page.tsx (members) | `frontend/apps/app/app/settings/members/page.tsx` | ソース | メンバー設定ページ |
| page.tsx (billing) | `frontend/apps/app/app/settings/billing/page.tsx` | ソース | 請求設定ページ |
| page.tsx (projects) | `frontend/apps/app/app/settings/projects/page.tsx` | ソース | プロジェクト設定ページ |
| GeneralPage.tsx | `frontend/apps/app/components/GeneralPage/GeneralPage.tsx` | ソース | 一般設定コンポーネント |
| GeneralPageClient.tsx | `frontend/apps/app/components/GeneralPage/components/GeneralPageClient/GeneralPageClient.tsx` | ソース | 一般設定クライアント |
| updateOrganizationName.ts | `frontend/apps/app/components/GeneralPage/components/GeneralPageClient/actions/updateOrganizationName.ts` | ソース | 組織名更新Action |
| deleteOrganization.ts | `frontend/apps/app/components/GeneralPage/components/GeneralPageClient/actions/deleteOrganization.ts` | ソース | 組織削除Action |
| DeleteConfirmationModal.tsx | `frontend/apps/app/components/GeneralPage/components/GeneralPageClient/components/DeleteOrganizationButtonClient/DeleteConfirmationModal/DeleteConfirmationModal.tsx` | ソース | 削除確認モーダル |
| OrganizationMembersPage.tsx | `frontend/apps/app/components/OrganizationMembersPage/OrganizationMembersPage.tsx` | ソース | メンバーページ |
| getMembersAndInvites.ts | `frontend/apps/app/components/OrganizationMembersPage/services/getMembersAndInvites.ts` | ソース | メンバーデータ取得 |
| layout.module.css | `frontend/apps/app/app/settings/layout.module.css` | スタイル | レイアウトスタイル |
| GeneralPage.module.css | `frontend/apps/app/components/GeneralPage/GeneralPage.module.css` | スタイル | 一般設定スタイル |
