
Summary
この文書の要点
- メニュー表示はUXであり、セキュリティ境界ではない。
- ルート定義と必要権限を対応付ける。
- ナビゲーション表示用の権限とAPI実行権限を同じソースから解決する。
- 権限不足、機能停止、未契約、準備中を別状態として画面に反映する。
どこが設計の難所か
管理画面では、ロールごとに見えるメニューを変えることがあります。しかし、URLを直接入力すれば画面が開ける、APIを直接呼べる、という状態では権限設計として不十分です。
フロントエンドは利用者体験を良くするためにメニューを制御できますが、ブラウザ上のコードは利用者が見られます。権限の最終判断はサーバー側で行う必要があります。
Reactの画面では、ロールに応じてメニューを出し分けるのは簡単です。しかし表示を隠すだけではAPIを守れません。また、権限があるのに導線がない、導線があるのにAPIで拒否される状態は利用者の混乱につながります。
境界をどう切るか
ルート、メニュー、API操作に必要権限を定義し、同じロールモデルを参照します。React Routerではルートガードで未権限画面を出し、APIではリクエストごとに権限を確認します。
設計では、権限をUIのif文ではなく、capabilityとして扱います。画面側はcapability一覧を受け取り、ナビゲーション、ボタン、ルートガードに使います。API側は同じcapabilityまたはロール定義から実行可否を判定します。
実装で効く細部
権限定義はTypeScriptの定数として管理し、メニュー生成とルートガードで使います。APIレスポンスで利用可能権限を返す場合は、サーバー側の権限定義とずれないようにします。画面上のボタンも操作権限に基づいて表示します。
React Routerでは、loaderでユーザーのcapabilitiesを取得し、ナビゲーション定義に必要capabilityを持たせます。隠す、無効化する、説明付きで表示する、別画面へ誘導するなど、状態ごとの表示方針を分けます。
- メニュー定義にrequiredCapabilityを持たせ、ロール名を直接書かない。
- API側は必ずサーバーで権限判定し、画面表示に依存しない。
- 権限変更後に古いナビゲーションが残らないよう、セッションやキャッシュを更新する。
壊れ方を観測する
検証では、各ロールでメニューが正しく出るか、URL直打ちで権限外画面に入れないか、API直接呼び出しが拒否されるかを確認します。権限追加時にテストが漏れないよう、ロール表をテストケースにします。
検証では、ロールごとの表示だけでなく、URL直打ち、API直接呼び出し、権限変更直後の画面更新を確認します。Playwrightでロール別の主要導線を回すと、導線と権限のずれを検出できます。
捨てた選択肢とトレードオフ
権限定義を共通化しすぎると、フロントとバックエンドの結合が強くなります。公開してよい権限名だけをフロントへ渡し、判定の本体はAPIに残す設計が安全です。
権限がない機能を完全に隠すと画面はすっきりしますが、なぜ使えないか分かりにくい場合があります。無効表示にすると説明しやすい一方、画面が複雑になります。業務上必要な気づきと情報露出のバランスが必要です。
現場に残す判断軸
ロール別ナビゲーションは、権限管理の見た目部分にすぎません。メニュー、ルート、APIを同じ考え方で検証することで、使いやすさと安全性を両立できます。
ロール別ナビゲーションは、見た目の条件分岐ではありません。権限モデルと導線を同じ定義から作ると、画面とAPIの整合性を保ちやすくなります。


