管理画面 — ユーザー管理仕様 (FR-012)
| 項目 | 内容 |
|---|---|
| 対象FR | FR-012(管理画面 — ユーザー管理) |
| 優先度 | 低 |
| ステータス | 詳細化済み |
| フェーズ | Phase 6 |
概要
運用担当者は管理画面からユーザーの一覧表示・詳細閲覧・アカウント停止・削除を行える。管理者の認証は一般ユーザーと同じワンタイムコード方式(FR-001/002)を使用し、users テーブルの role で権限を判別する。管理者権限は柔軟なRBACモデルで管理し、ロールごとに操作可能な範囲を制御する。
前提条件(依存FR)
| 依存FR | 必要な機能 | 用途 |
|---|---|---|
| FR-001/002(認証) | ワンタイムコード認証 | 管理者ログイン |
管理者認証
ログインフロー
- 管理者は管理画面のログインページからメールアドレスを入力
- 一般ユーザーと同じワンタイムコード認証フロー(FR-001/002)で認証
- 認証成功後、
users.roleを確認し管理者権限を持つ場合のみ管理画面へ遷移 - 管理者権限がないユーザー →
403 Forbidden
ロール
| ロール | 説明 |
|---|---|
user | 一般ユーザー(デフォルト) |
admin | 管理者(管理画面アクセス可能) |
- ロールは DB の
users.roleカラムで管理する(default:user) - 初期管理者はシードデータまたは DB 直接操作で設定する
RBAC(ロールベースアクセス制御)
権限モデル
管理者の操作権限はロールに紐づく admin_roles テーブルで管理する。
| リソース | キー | 操作 |
|---|---|---|
| ユーザー管理 | users | list / view / suspend / delete |
| マスタデータ管理 | masterData | list / create / update / delete |
| ダッシュボード | dashboard | view / export |
| お知らせ管理 | announcements | list / create / update / delete |
デフォルトロール
super_admin(スーパー管理者):
{ "users": ["list", "view", "suspend", "delete"], "masterData": ["list", "create", "update", "delete"], "dashboard": ["view", "export"], "announcements": ["list", "create", "update", "delete"]}operator(運用担当):
{ "users": ["list", "view", "suspend"], "masterData": ["list", "create", "update"], "dashboard": ["view"], "announcements": ["list", "create", "update"]}viewer(閲覧者):
{ "users": ["list", "view"], "masterData": ["list"], "dashboard": ["view"], "announcements": ["list"]}ユーザー一覧・検索
検索条件
| パラメータ | 型 | 説明 |
|---|---|---|
| q | varchar | メールアドレスの部分一致検索 |
| status | varchar | active / suspended(フィルタ) |
| sort | varchar | createdAt / email(default: createdAt) |
| order | varchar | asc / desc(default: desc) |
| limit | integer | 取得件数(default: 20、最大100) |
| offset | integer | スキップ件数(default: 0) |
ユーザー詳細で表示する情報
| 項目 | 説明 |
|---|---|
| 基本情報 | メールアドレス、ロール、登録日時 |
| ペット情報 | 登録ペット数、ペット一覧(名前・品種) |
| 利用状況 | 最終ログイン日時、アクティブセッション数 |
| 停止状態 | 停止中か否か、停止理由、停止日時 |
アカウント停止
停止フロー
- 管理者がユーザー詳細画面で「アカウント停止」を実行
- 停止理由を入力(必須、1〜500文字)
users.suspended_atに現在日時、users.suspension_reasonに理由を設定- 該当ユーザーの全アクティブセッションを即座に無効化
- 停止ユーザーは以降のログインが不可になる
停止解除
- 管理者が「停止解除」を実行すると
suspended_atとsuspension_reasonをnullに更新 - 停止解除後、ユーザーは通常通りログイン可能
アカウント削除
- 管理者が手動でアカウントを削除できる
- 削除は論理削除(
users.deleted_atに日時を設定) - 削除されたアカウントのデータ(ペット・健康記録等)はデータ保持期間(90日)後にバッチ処理で物理削除
- 削除後のログインは不可
APIエンドポイント
全エンドポイントで管理者認証必須。
ユーザー管理
| メソッド | パス | 概要 | 必要権限 |
|---|---|---|---|
| GET | /api/admin/users | ユーザー一覧 | users.list |
| GET | /api/admin/users/:userId | ユーザー詳細 | users.view |
| POST | /api/admin/users/:userId/suspend | アカウント停止 | users.suspend |
| POST | /api/admin/users/:userId/unsuspend | アカウント停止解除 | users.suspend |
| DELETE | /api/admin/users/:userId | アカウント削除 | users.delete |
ロール管理
| メソッド | パス | 概要 | 必要権限 |
|---|---|---|---|
| GET | /api/admin/roles | ロール一覧 | users.list |
| POST | /api/admin/roles | ロール作成 | users.suspend |
| PATCH | /api/admin/roles/:roleId | ロール更新 | users.suspend |
| DELETE | /api/admin/roles/:roleId | ロール削除 | users.delete |
| PATCH | /api/admin/users/:userId/role | ユーザーロール変更 | users.suspend |
GET /api/admin/users — ユーザー一覧
{ "data": [ { "id": 1, "email": "user@example.com", "role": "user", "petCount": 3, "suspendedAt": null, "createdAt": "2026-01-01T00:00:00Z" } ], "pagination": { "total": 150, "limit": 20, "offset": 0 }}GET /api/admin/users/:userId — ユーザー詳細
{ "data": { "id": 1, "email": "user@example.com", "role": "user", "createdAt": "2026-01-01T00:00:00Z", "updatedAt": "2026-02-01T00:00:00Z", "suspendedAt": null, "suspensionReason": null, "lastLoginAt": "2026-02-20T10:00:00Z", "activeSessionCount": 2, "pets": [ { "id": 1, "name": "そうにゃ", "breedName": "アメリカンショートヘア", "createdAt": "2026-01-15T00:00:00Z" } ] }}POST /api/admin/users/:userId/suspend — アカウント停止
// リクエスト{ "reason": "利用規約違反のため"}| フィールド | 型 | 必須 | バリデーション |
|---|---|---|---|
| reason | varchar | ○ | 1〜500文字 |
- 成功時:
200 OK - 既に停止中:
409 Conflict - 管理者自身の停止:
422 Unprocessable Entity
POST /api/admin/users/:userId/unsuspend — 停止解除
- 成功時:
200 OK - 停止中でない:
409 Conflict
DELETE /api/admin/users/:userId — アカウント削除
- 成功時:
204 No Content - 管理者自身の削除:
422 Unprocessable Entity
DBテーブル(変更・追加)
users テーブルへの追加カラム
| カラム | 型 | 備考 |
|---|---|---|
| role | varchar | user / admin(default: user) |
| suspended_at | timestamptz | 停止日時(nullable) |
| suspension_reason | text | 停止理由(nullable) |
| deleted_at | timestamptz | 論理削除日時(nullable) |
| last_login_at | timestamptz | 最終ログイン日時(nullable) |
admin_roles
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| name | varchar | ロール名(一意制約) |
| description | varchar | 説明 |
| permissions | jsonb | 権限セット |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- デフォルトロール(super_admin / operator / viewer)はシードデータとして用意
認可ルール
- 全エンドポイントで
users.role = 'admin'であること - 各操作は
admin_roles.permissionsに基づいてリソース×操作単位で制御 - 権限がない操作:
403 Forbidden - 管理者自身の停止・削除は不可
- スーパー管理者ロールの削除は不可(保護)
エッジケース
- 管理者自身を停止しようとした場合 →
422 Unprocessable Entity - 管理者自身を削除しようとした場合 →
422 Unprocessable Entity - 最後のスーパー管理者を降格しようとした場合 →
422 Unprocessable Entity(最低1人のスーパー管理者が必要) - 停止中のユーザーがAPIにアクセスした場合 →
403 Forbidden(「アカウントが停止されています」メッセージ付き) - 削除済みユーザーがログインしようとした場合 → 通常の認証コード送信応答を返す(アカウントの存在を漏らさない)が、コード検証時に失敗扱い
- ロールが削除された場合 → 該当ロールに紐づくユーザーは
userロールにフォールバック
拡張予定(現時点ではスコープ外)
- 管理者操作の監査ログ
- 2要素認証(管理者向け強化認証)
- ユーザーへのメール通知(停止通知等)
- ユーザーデータのエクスポート機能
- 一括操作(複数ユーザーの一括停止等)
検証方法
- 管理者がユーザー一覧を取得でき、検索・フィルタが正しく動作すること
- ユーザー詳細にペット情報・利用状況が表示されること
- アカウント停止後に該当ユーザーがログインできないこと
- アカウント停止後に全セッションが無効化されること
- 停止解除後にユーザーがログインできること
- 管理者自身の停止・削除が拒否されること
- 権限がない操作に
403が返ること - 一般ユーザーが管理画面APIにアクセスした場合に
403が返ること - ロール変更が即座に反映されること
- 最後のスーパー管理者の降格が拒否されること