UI for Admin — 概要
4D 運用スタッフが Guinness 管理者 API(api-admin)を操作するためのバックオフィス Web UI。
目的
- 管理者アカウント・組織・プロジェクト・アプリユーザーの CRUD
- 認証(ログイン・パスワード忘れ・パスワードリセット・プロフィール取得)
- ロール(RBAC)に応じた操作可否の制御
スコープ
含むもの
- 認証フロー全般(
/auth/login、/auth/logout、/auth/forgot_password、/auth/reset_password、/auth/me) /admins、/organizations、/projects、/usersの一覧・詳細・作成・編集・ソフト削除・ハード削除- ロールフラグ(
admin_access、organization_access、project_access、user_access)に基づく画面・ボタンのガード
含まないもの
バックエンド契約
- API ソース:
GenAI-Guinness-backend/apps/admin - OpenAPI 3.1 スペック:
/api/v1/doc(JSON) - Swagger UI:
/api/v1/docs - バージョン: v1(
/api/v1プレフィックス)
認証
パターン: httpOnly Cookie + ステートレス Next.js プロキシ。
採用理由:
- JWT は JavaScript から到達不可(XSS 耐性)
- Next.js 側にセッション状態がないので水平スケールが単純
SameSite=Lax+ 同一オリジンプロキシで CSRF を回避
Next.js が設定する Cookie:
| Cookie | 属性 | TTL |
|---|---|---|
admin_token |
httpOnly, Secure, SameSite=Lax | 約 15 分 |
admin_refresh_token |
httpOnly, Secure, SameSite=Lax | 長期(バックエンド設定に従う) |
認証フロー
| フロー | 動作 |
|---|---|
| ログイン | フォーム → Next.js /api/auth/login → 管理者 API /auth/login → 2 つの Cookie をセット → { user } のみをブラウザに返却(トークンは返さない) → TanStack Query の auth/me キャッシュをプライム |
| 認証済みリクエスト | ブラウザ /api/proxy/<path> → プロキシが Cookie 読込 → Authorization: Bearer 付与して管理者 API に転送 |
| 401 時のトークン更新 | プロキシが /auth/refresh(リフレッシュ Cookie を添付)→ 成功なら admin_token Cookie を更新しオリジナルリクエストをリプレイ。ブラウザ側フェッチャーは単一の refresh Promise で並列 401 をコアレッシング(バーストごとに 1 回の refresh のみ発生) |
| ログアウト | Next.js /api/auth/logout → 管理者 API /auth/logout(サーバー側セッション行を削除)→ 両 Cookie を削除 |
| パスワード忘れ / リセット | セッションは不要。Next.js ルートが管理者 API に素通し |
採用しない方式(理由付き)
- localStorage / sessionStorage に JWT を保存 — XSS リスク。JS から到達可能
- インメモリのみ(リロードで消える / サイレントリフレッシュが複雑)
- NextAuth — バックエンドセッションと衝突
- Amplify Auth SDK — Cognito 直通のため、管理者 API のセッションテーブルと DB 由来 RBAC をバイパス
バックエンド確認事項
- リフレッシュエンドポイントの正確なパスとリクエスト / レスポンス形状(
routes/v1/auth.tsにrefreshTokenRouteのインポートはあるが詳細未確認) - リフレッシュトークンの rotation 有無と、rotation 直後の旧トークンに対する grace window の有無
- レスポンスエンベロープ移行計画(
{ success, data }vs 旧形式)— フェッチャーの正規化レイヤーに影響
RBAC
管理者 API は各管理者に role フラグを付与する:
admin_accessorganization_accessproject_accessuser_access
各フラグは AccessLevel(NONE / READ / READ_WRITE)を持つ。UI は 3 層でガードする:
middleware.ts(エッジ) —admin_tokenCookie の有無をチェック。なければ/loginへ(authenticated)/layout.tsx(サーバーコンポーネント) —/auth/meを取得し{ user, role }を Provider で子に注入。レイアウトレベルの必須フラグがREAD未満なら 404- ページ / ボタン単位 —
useCan(flag, level)でボタンや画面要素を非表示 / 無効化
ページ構成(主要画面)
| ルート | 必要なロール | 機能 |
|---|---|---|
/login |
認証不要 | ログイン |
/forgot-password, /reset-password |
認証不要 | パスワードリセットフロー |
/admins |
admin_access >= READ |
管理者一覧 |
/admins/[id] |
admin_access >= READ |
管理者詳細・編集(READ_WRITE でボタン表示) |
/organizations |
organization_access >= READ |
組織一覧 |
/organizations/[id] |
organization_access >= READ |
組織詳細・編集 |
/projects |
project_access >= READ |
プロジェクト一覧(organization_id フィルタ、ページネーション、ソート) |
/projects/[id] |
project_access >= READ |
プロジェクト詳細・編集 |
/users |
user_access >= READ |
アプリユーザー一覧 |
/users/[id] |
user_access >= READ |
アプリユーザー詳細・編集 |
/profile |
認証済み | 自分のプロフィール(/auth/me)、パスワード変更 |
アクター
関連ドキュメント
- API for Admin — バックエンド側
- テックスタック — 採用技術一覧
- ディレクトリ構成 — レイヤー構成とリクエストフロー
- セットアップ — Orval 設定とフェッチャー
- コーディングルール — バリデーションと実装規約