# 機能設計書 66-ユーザー管理

## 概要

本ドキュメントは、Actualアプリケーションにおけるユーザー管理機能の設計仕様を記載したものである。複数ユーザーの管理機能（管理者向け）を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Actualをチームや家庭で共有利用する場合、複数のユーザーを管理し、予算ファイルへのアクセス権を制御する必要がある。ユーザー管理機能は、管理者がユーザーの作成・編集・削除、およびファイルへのアクセス権の付与・取消を行うことを可能にする。

**機能の利用シーン**：
- 新しいチームメンバーにアクセス権を付与する場合
- ユーザーの役割（ロール）を変更する場合
- 退職者や家族のアクセス権を削除する場合
- 予算ファイルの所有権を移譲する場合

**主要な処理内容**：
1. ユーザー一覧の取得（GET /users/）
2. ユーザーの作成（POST /users）
3. ユーザーの更新（PATCH /users）
4. ユーザーの削除（DELETE /users）
5. ファイルアクセス権の取得（GET /access）
6. ファイルアクセス権の付与（POST /access）
7. ファイルアクセス権の削除（DELETE /access）
8. ファイル所有権の移譲（POST /access/transfer-ownership/）

**関連システム・外部連携**：
- 認証システム（authテーブル）
- ファイル管理システム（filesテーブル）
- セッション管理（validateSession）

**権限による制御**：
- 管理者（isAdmin）のみがユーザーCRUD操作を実行可能
- ファイルアクセス権操作は管理者または対象ファイルの権限保持者のみ
- オーナーユーザーは削除不可

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 41 | ユーザーディレクトリ画面 | 主機能 | ユーザー一覧の表示・管理（管理者専用） |
| 42 | ユーザーアクセス管理画面 | 主機能 | ユーザーアクセス権限の設定・管理 |

## 機能種別

CRUD操作 / 認可管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| userName | string | Yes | ユーザー名 | 空文字不可、重複不可 |
| role | string | Yes | ロール名 | 有効なロールID |
| displayName | string | No | 表示名 | - |
| enabled | boolean | No | 有効/無効フラグ | デフォルトtrue |
| id | string | Yes（更新時） | ユーザーID | 有効なUUID |
| fileId | string | Yes（アクセス権操作時） | ファイルID | 有効なファイルID |
| userId | string | Yes（アクセス権操作時） | ユーザーID | 有効なユーザーID |
| newUserId | string | Yes（所有権移譲時） | 新所有者ID | 有効なユーザーID |

### 入力データソース

- HTTPリクエストボディ
- HTTPクエリパラメータ
- セッショントークン（X-Actual-Token）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| status | string | 処理結果（'ok' / 'error'） |
| data | object | レスポンスデータ（id等） |
| reason | string | エラー理由（エラー時） |
| details | string | エラー詳細（エラー時） |

### 出力先

- HTTPレスポンス（JSON）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ Express middleware（JSON parse、ロギング）

2. セッション検証
   └─ validateSessionMiddlewareでトークン検証

3. 権限チェック
   └─ isAdmin()で管理者権限を確認

4. バリデーション
   └─ 必須パラメータ、ロール存在、ユーザー存在等を確認

5. ビジネスロジック実行
   └─ UserService関数を呼び出し

6. レスポンス返却
   └─ JSON形式でステータスとデータを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[リクエスト受信]
    B --> C[セッション検証]
    C --> D{有効なセッション?}
    D -->|No| E[401 Unauthorized]
    D -->|Yes| F{管理者?}
    F -->|No| G[403 Forbidden]
    F -->|Yes| H[バリデーション]
    H --> I{バリデーション成功?}
    I -->|No| J[400 Bad Request]
    I -->|Yes| K[ビジネスロジック実行]
    K --> L{処理成功?}
    L -->|No| M[エラーレスポンス]
    L -->|Yes| N[200 OK + データ]
    E --> O[終了]
    G --> O
    J --> O
    M --> O
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-66-001 | 管理者権限必須 | ユーザーCRUD操作は管理者のみ実行可能 | 全ユーザー操作 |
| BR-66-002 | オーナー削除不可 | システムオーナーユーザーは削除できない | DELETE /users |
| BR-66-003 | ユーザー名重複不可 | 同じユーザー名は登録できない | POST /users |
| BR-66-004 | ロール検証 | 有効なロールのみ設定可能 | POST/PATCH /users |
| BR-66-005 | ファイル所有権移譲 | 削除時にファイルはオーナーに移譲 | DELETE /users |
| BR-66-006 | アクセス権重複不可 | 同一ユーザー・ファイルの組み合わせは重複不可 | POST /access |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ユーザー一覧取得 | users | SELECT | 全ユーザー取得 |
| ユーザー作成 | users | INSERT | 新規ユーザー作成 |
| ユーザー更新 | users, user_roles | UPDATE | ユーザー情報更新 |
| ユーザー削除 | users, user_access, files | DELETE/UPDATE | ユーザー削除とファイル移譲 |
| アクセス権取得 | user_access | SELECT | ファイルアクセス権取得 |
| アクセス権付与 | user_access | INSERT | アクセス権追加 |
| アクセス権削除 | user_access | DELETE | アクセス権削除 |
| 所有権移譲 | files | UPDATE | ファイル所有者変更 |

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

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | UUID生成 | 主キー |
| INSERT | user_name | ユーザー名 | 必須 |
| INSERT | display_name | 表示名 | null可 |
| INSERT | enabled | 1 or 0 | デフォルト1 |
| UPDATE | user_name | 新しいユーザー名 | - |
| UPDATE | display_name | 新しい表示名 | - |
| UPDATE | enabled | 新しい有効フラグ | - |
| DELETE | id | 削除対象ID | - |

#### user_access

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | ユーザーID | - |
| INSERT | file_id | ファイルID | - |
| DELETE | user_id, file_id | 削除条件 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | セッション無効 | ログイン要求 |
| 403 | Forbidden | 管理者権限なし | 権限エラー表示 |
| 400 | user-cant-be-empty | ユーザー名が空 | バリデーションエラー |
| 400 | role-cant-be-empty | ロールが空 | バリデーションエラー |
| 400 | role-does-not-exists | 無効なロール | バリデーションエラー |
| 400 | user-already-exists | ユーザー名重複 | バリデーションエラー |
| 400 | cannot-find-user-to-update | 更新対象不在 | バリデーションエラー |
| 404 | invalid-file-id | ファイル不在 | バリデーションエラー |
| 400 | user-already-have-access | アクセス権重複 | バリデーションエラー |
| 400 | file-denied | ファイル権限なし | 権限エラー |

### リトライ仕様

特になし。エラー発生時は即座にレスポンスを返却。

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

各API操作は個別のトランザクションで処理。ユーザー削除時は以下の順序で処理：
1. ユーザーアクセス権削除（deleteUserAccess）
2. ファイル所有権移譲（transferAllFilesFromUser）
3. ユーザー削除（deleteUser）

## パフォーマンス要件

- API応答時間: 500ms以内
- ユーザー一覧取得: 200ms以内

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

- 全APIはセッション認証必須
- 管理者権限チェック（isAdmin）
- ファイルアクセス権チェック（checkFilePermission）
- オーナーユーザー保護（削除不可）

## 備考

- Express.jsベースのREST API
- ミドルウェア: requestLoggerMiddleware, validateSessionMiddleware, errorMiddleware
- OpenID認証との統合対応

---

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

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

### 推奨読解順序

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

まず、ユーザーとアクセス権の関連を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | app-admin.js | `packages/sync-server/src/app-admin.js` | リクエスト/レスポンス構造 |
| 1-2 | user-service.ts | `packages/sync-server/src/services/user-service.ts` | UserService関数群 |

**読解のコツ**: APIレスポンスは{status, data}または{status, reason, details}の形式で統一されている。

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

処理の起点となるExpressルートを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | app-admin.js | `packages/sync-server/src/app-admin.js` | Expressアプリケーション定義 |

**主要処理フロー**:
1. **13-18行目**: Expressアプリ初期化、ミドルウェア設定
2. **20-27行目**: GET /owner-created/ - オーナー存在確認
3. **29-38行目**: GET /users/ - ユーザー一覧取得
4. **40-90行目**: POST /users - ユーザー作成
5. **92-142行目**: PATCH /users - ユーザー更新
6. **144-178行目**: DELETE /users - ユーザー削除
7. **180-216行目**: GET /access - アクセス権取得
8. **218-271行目**: POST /access - アクセス権付与
9. **273-318行目**: DELETE /access - アクセス権削除
10. **320-351行目**: GET /access/users - アクセス権ユーザー一覧
11. **353-408行目**: POST /access/transfer-ownership/ - 所有権移譲

#### Step 3: 認可処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | account-db.js | `packages/sync-server/src/account-db.js` | isAdmin関数 |
| 3-2 | validate-user.ts | `packages/sync-server/src/util/validate-user.ts` | validateSession関数 |
| 3-3 | middlewares.ts | `packages/sync-server/src/util/middlewares.ts` | validateSessionMiddleware |

**主要処理フロー（認可）**:
- **isAdmin**: ユーザーIDから管理者権限を判定
- **validateSession**: リクエストからセッショントークンを検証
- **validateSessionMiddleware**: Express middleware版

#### Step 4: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | user-service.ts | `packages/sync-server/src/services/user-service.ts` | 各サービス関数 |

**主要関数**:
- getOwnerCount: オーナー数取得
- getAllUsers: 全ユーザー取得
- getUserByUsername: ユーザー名で検索
- getUserById: IDで検索
- insertUser: ユーザー作成
- updateUserWithRole: ユーザー更新
- deleteUser: ユーザー削除
- deleteUserAccess: アクセス権削除
- transferAllFilesFromUser: ファイル移譲
- checkFilePermission: 権限チェック
- getUserAccess: アクセス権取得
- addUserAccess: アクセス権追加
- deleteUserAccessByFileId: アクセス権削除（ファイル単位）
- getAllUserAccess: 全アクセス権取得
- updateFileOwner: 所有者更新
- validateRole: ロール検証

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

```
Express Router (app-admin.js)
    │
    ├─ Middleware
    │      ├─ express.json()
    │      ├─ express.urlencoded()
    │      ├─ requestLoggerMiddleware
    │      └─ validateSessionMiddleware
    │
    ├─ GET /owner-created/
    │      └─ UserService.getOwnerCount()
    │
    ├─ GET /users/
    │      └─ UserService.getAllUsers()
    │
    ├─ POST /users
    │      ├─ isAdmin(res.locals.user_id)
    │      ├─ UserService.validateRole(role)
    │      ├─ UserService.getUserByUsername(userName)
    │      └─ UserService.insertUser(...)
    │
    ├─ PATCH /users
    │      ├─ isAdmin(res.locals.user_id)
    │      ├─ UserService.validateRole(role)
    │      ├─ UserService.getUserById(id)
    │      └─ UserService.updateUserWithRole(...)
    │
    ├─ DELETE /users
    │      ├─ isAdmin(res.locals.user_id)
    │      ├─ UserService.getOwnerId()
    │      ├─ UserService.deleteUserAccess(item)
    │      ├─ UserService.transferAllFilesFromUser(ownerId, item)
    │      └─ UserService.deleteUser(item)
    │
    ├─ GET /access
    │      ├─ UserService.checkFilePermission(...)
    │      ├─ isAdmin(res.locals.user_id)
    │      ├─ UserService.getFileById(fileId)
    │      └─ UserService.getUserAccess(...)
    │
    ├─ POST /access
    │      ├─ validateSession(req, res)
    │      ├─ UserService.checkFilePermission(...)
    │      ├─ UserService.getFileById(fileId)
    │      ├─ UserService.countUserAccess(...)
    │      └─ UserService.addUserAccess(...)
    │
    ├─ DELETE /access
    │      ├─ validateSession(req, res)
    │      ├─ UserService.checkFilePermission(...)
    │      ├─ UserService.getFileById(fileId)
    │      └─ UserService.deleteUserAccessByFileId(...)
    │
    ├─ GET /access/users
    │      ├─ UserService.checkFilePermission(...)
    │      ├─ isAdmin(res.locals.user_id)
    │      ├─ UserService.getFileById(fileId)
    │      └─ UserService.getAllUserAccess(fileId)
    │
    └─ POST /access/transfer-ownership/
           ├─ UserService.checkFilePermission(...)
           ├─ isAdmin(res.locals.user_id)
           ├─ UserService.getFileById(fileId)
           ├─ UserService.getUserById(newUserId)
           └─ UserService.updateFileOwner(...)
```

### データフロー図

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

HTTPリクエスト ───────┐
(Authorization,      │
 Body, Query)        │
                     ▼
              ┌─────────────────┐
              │ Express Router  │
              │ app-admin.js    │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ Middleware      │
              │ - JSON parse    │
              │ - Session検証   │
              │ - Logging       │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ 権限チェック    │
              │ - isAdmin()     │
              │ - checkFile     │
              │   Permission()  │
              └────────┬────────┘
                       │
        ┌──────────────┼──────────────┐
        │              │              │
        ▼              ▼              ▼
   ┌─────────┐   ┌─────────┐   ┌─────────┐
   │403      │   │バリデー │   │ビジネス │
   │Forbidden│   │ション   │   │ロジック │
   └─────────┘   └────┬────┘   └────┬────┘
                      │              │
                      ▼              ▼
                ┌─────────┐   ┌─────────────┐
                │400      │   │UserService  │
                │Bad      │   │関数呼び出し │
                │Request  │   └─────┬───────┘
                └─────────┘         │
                                    ▼
                            ┌─────────────┐
                            │ account-db  │
                            │ SQL実行     │
                            └─────┬───────┘
                                  │
                                  ▼
                            ┌─────────────┐
                            │HTTPレスポンス│
                            │JSON形式     │
                            └─────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| app-admin.js | `packages/sync-server/src/app-admin.js` | ソース | メインルーター |
| app-admin.test.js | `packages/sync-server/src/app-admin.test.js` | テスト | ユニットテスト |
| user-service.ts | `packages/sync-server/src/services/user-service.ts` | ソース | サービス層 |
| account-db.js | `packages/sync-server/src/account-db.js` | ソース | DB接続・isAdmin関数 |
| validate-user.ts | `packages/sync-server/src/util/validate-user.ts` | ソース | セッション検証 |
| middlewares.ts | `packages/sync-server/src/util/middlewares.ts` | ソース | Express middleware |
