# 機能設計書 63-ユーザーアカウント停止

## 概要

本ドキュメントは、Fat Free CRM の管理機能における「ユーザーアカウント停止」機能の設計を記述する。

### 本機能の処理概要

管理者がユーザーアカウントを一時的に停止（サスペンド）するための機能である。停止されたユーザーはシステムにログインできなくなるが、関連データは保持される。

**業務上の目的・背景**：長期休暇、休職、セキュリティ上の理由など、一時的にユーザーのシステムアクセスを制限する必要がある場合に使用する。ユーザーデータを削除せずにアクセスを停止できるため、復帰時の再有効化が容易である。

**機能の利用シーン**：
- 長期休暇・育児休暇中の従業員アカウント停止
- セキュリティインシデント発生時の緊急アカウント停止
- 退職予定者の段階的なアクセス制限
- 不正アクセス疑いのあるアカウントの一時停止

**主要な処理内容**：
1. 停止対象ユーザーの特定
2. suspended_at カラムへの現在時刻の設定
3. 画面の即時更新（AJAX）

**関連システム・外部連携**：Devise 認証システムと連携。suspended_at が設定されたユーザーは `active_for_authentication?` が false を返し、ログインがブロックされる。

**権限による制御**：本機能は管理者権限（admin: true）を持つユーザーのみが実行可能。また、自分自身を停止することはできない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 34 | ユーザー管理一覧画面 | 主画面 | 停止リンクの表示元 |
| 35 | ユーザー管理詳細画面 | 補助機能 | ユーザーアカウントの停止 |

## 機能種別

CRUD操作（Update）/ 状態管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer | Yes | 停止対象ユーザーID | 存在するユーザーID、自分自身でないこと |

### 入力データソース

- URL パラメータ（ユーザーID）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @user | User | 停止後のユーザーオブジェクト |

### 出力先

- 画面表示（AJAX レスポンスによる部分更新）
- users テーブル（suspended_at カラム）

## 処理フロー

### 処理シーケンス

```
1. 管理者がユーザー一覧画面で停止リンクをクリック
   └─ AJAX リクエスト: PUT /admin/users/:id/suspend

2. suspend アクションで停止処理を実行
   └─ 対象が自分自身でないことを確認
   └─ suspended_at に現在時刻を設定

3. 結果を返却
   └─ ユーザー行を更新（停止状態の表示に変更）
```

### フローチャート

```mermaid
flowchart TD
    A[停止リンククリック] --> B[PUT /admin/users/:id/suspend]
    B --> C{対象は自分自身?}
    C -->|Yes| D[何もしない]
    C -->|No| E[suspended_at = Time.now]
    E --> F[update_attribute 実行]
    F --> G[画面更新 JS 返却]
    D --> G
    G --> H[ユーザー行を更新表示]
    H --> I[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-63-01 | 自己停止禁止 | 管理者は自分自身のアカウントを停止できない | 停止対象が current_user の場合 |
| BR-63-02 | 即時反映 | 停止後、対象ユーザーの新規ログイン・セッション更新がブロックされる | 常時 |
| BR-63-03 | データ保持 | 停止中もユーザーの関連データは全て保持される | 常時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| アカウント停止 | users | UPDATE | suspended_at カラムに現在時刻を設定 |

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

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | suspended_at | Time.now | バリデーションスキップ（update_attribute） |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 業務エラー | 自分自身を停止しようとした場合 | 更新処理をスキップ |
| - | 認可エラー | 非管理者によるアクセス | ルート画面にリダイレクト |

### リトライ仕様

特になし（単純な UPDATE 操作のため）

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

`update_attribute` は単一カラムの更新であり、バリデーションをスキップして即時コミットされる。

## パフォーマンス要件

- AJAX リクエストのため、レスポンス時間は 500ms 以内を目標
- 単一カラムの UPDATE のみであり、特別なパフォーマンス考慮は不要

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

- 管理者権限チェック（before_action :require_admin_user）
- 自己停止の防止（コントローラー内条件分岐）
- CSRF トークンによるクロスサイトリクエストフォージェリ対策

## 備考

- 停止されたユーザーは以下の状態になる：
  - `suspended?` が true を返す
  - `active_for_authentication?` が false を返す（ログイン不可）
  - ユーザー一覧で「Suspended」ステータスが表示される
- 再有効化は「ユーザーアカウント再有効化」機能（No.64）で行う

---

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

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

### 推奨読解順序

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

まず、ユーザーモデルの停止関連メソッドを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/users/user.rb` | suspended? メソッド、active_for_authentication? メソッド |
| 1-2 | schema.rb | `db/schema.rb` | users テーブルの suspended_at カラム |

**読解のコツ**:
- **111-113行目**: `suspended?` は `suspended_at != nil` で判定
- **120-122行目**: `active_for_authentication?` で `!suspended?` を含む複合条件をチェック

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | users_controller.rb | `app/controllers/admin/users_controller.rb` | suspend アクション |
| 2-2 | application_controller.rb | `app/controllers/admin/application_controller.rb` | 管理者権限チェック |

**主要処理フロー**:
- **87-91行目**: suspend アクション

```ruby
def suspend
  @user.update_attribute(:suspended_at, Time.now) if @user != current_user
  respond_with(@user)
end
```

#### Step 3: ビュー層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _user.html.haml | `app/views/admin/users/_user.html.haml` | 停止リンクの表示条件、状態表示 |
| 3-2 | suspend.js.haml | `app/views/admin/users/suspend.js.haml` | 停止後の画面更新処理 |

**読解のコツ**:
- `_user.html.haml` の3-6行目で停止状態のステータス表示を切り替え
- `_user.html.haml` の18-23行目で停止リンクまたは「Suspend!」のグレー表示を切り替え

#### Step 4: ルーティングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | routes.rb | `config/routes.rb` | admin/users の suspend ルート |

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

```
[Admin::UsersController#suspend]
    │
    ├─ @user != current_user チェック
    │
    ├─ @user.update_attribute(:suspended_at, Time.now)
    │      └─ バリデーションスキップで直接 UPDATE
    │
    └─ respond_with(@user)
           └─ suspend.js.haml
                  └─ _user.html.haml（再レンダリング）

[User#active_for_authentication?]（ログイン時に呼ばれる）
    │
    ├─ super（Devise の基本チェック）
    ├─ confirmed?
    ├─ !awaits_approval?
    └─ !suspended?
           └─ suspended_at != nil
```

### データフロー図

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

ユーザーID         ───▶ load_resource             ───▶ @user
                           │
                   ───▶ current_user チェック
                           │
                           ├─ 自分自身 ───────────▶ 更新スキップ
                           │
                           └─ 他ユーザー
                                  │
                                  ▼
                        update_attribute
                        (suspended_at = Time.now)
                                  │
                                  ▼
                           users テーブル更新
                                  │
                                  ▼
                           画面更新（AJAX）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| users_controller.rb | `app/controllers/admin/users_controller.rb` | コントローラー | suspend アクションの実装 |
| application_controller.rb | `app/controllers/admin/application_controller.rb` | コントローラー | 管理者権限チェック |
| user.rb | `app/models/users/user.rb` | モデル | suspended?, active_for_authentication? メソッド |
| _user.html.haml | `app/views/admin/users/_user.html.haml` | ビュー | ユーザー行の表示、停止リンク |
| suspend.js.haml | `app/views/admin/users/suspend.js.haml` | ビュー | 停止後の画面更新 JS |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（PUT /admin/users/:id/suspend） |
| schema.rb | `db/schema.rb` | 設定 | データベーススキーマ（suspended_at カラム） |
