管理画面のメニューはサーバーから配信されることが少なくありません。役割ごとに見える入口が変わり、ページ追加のたびにフロントエンドを再リリースする必要もなくなります。ただし、やるべきことは受け取った内容をそのまま描画することではなく、メニュー・ルート・ボタンの三か所を同じ規則で締めることです。

メニューの契約

メニューは「グループ + 項目」で配信します。項目はパス、ラベルまたはラベルキー、アイコン、所属グループ、並び順、非表示フラグ、権限コード、子項目を持ちます。グループはサイドバーの順序を決め、階層は四段までに制限して、異常な入れ子がサイドバーを壊さないようにします。

外部リンクの項目はアドレスと開き方を自分で宣言します。新しいウィンドウ、同じウィンドウ、埋め込みのいずれかです。埋め込みは許可しているサイトに限ります。X-Frame-Options: DENY を返すサイトは空白になります。

寛容な処理もフロントエンド側の責務です。異常なパス、未知のアイコン、深すぎる子項目は整えたうえで、読める警告リストを残します。実 API をつなぐときは、利用者からの報告を待たずにこのリストを確認します。

ルートは登録済みページしか知らない

動的ルートのコンポーネントはローカルの登録表から取得します。API は登録済みページを参照できても、新しいコードを持ち込むことはできません。未ログインや権限不足のアドレスは、空白ではなくログイン画面か 403 に着地します。

三か所を同じ規則で

  • メニュー:権限コードで項目を絞り、権限のない入口は描画しません。
  • ルート:URL を直接入力しても同じガードに掛かり、403 に着地します。
  • ボタン:<Can permission="customer:create"> が新規作成やエクスポートを制御し、権限がない場合は黙って失敗せず無効状態を示します。

権限コードは *(すべて)、module:*(モジュール内すべて)、完全一致の三通りで書けるため、役割の違いは一つの一覧で表現できます。ドキュメントに契約の全文があり、オンラインデモでは二つのアカウントを比較できます。同じアドレスでも管理者は操作ログを見られ、テストアカウントは 403 になります。