InfraGuard

役割とチーム · 所有者

役割とチームは情報用のラベルにすぎません — アクセスを開くのはレベルだけです — あわせてユーザーとチームを統合した所有者ピッカーを解説します。

概要 — 何をする画面か

役割 と チーム は、人を分類するための 情報用ラベル です。画面と操作へのアクセスを開く唯一の要素は レベル(user_level) です。ユーザーが何を見られるか、何を保存・削除できるかは 100% レベル で決まります。役割(「DBA」「DevOps」「セキュリティ」)やチーム(「インフラチーム」「セキュリティチーム」)は 表示・組織のためのタグ であり、権限は一切付与しません。

これにより権限モデルはシンプルに保たれます。誰かに管理者権限を与えるには レベルを上げます — 役割を変えるのではありません。ユーザーに「セキュリティ」のタグを付けてもセキュリティ画面は開きません。そのためにはレベルがスタッフ(5)以上である必要があります。

この記事では次の3点を扱います。

  1. 役割(infr_role) — 6種類の職務ラベル(DBA、DevOps、セキュリティ、管理者、スタッフ、開発者)。
  2. チーム(infr_team) — 組織単位。ユーザーの所属と資産の担当割り当てに使います。
  3. 所有者ピッカー — ユーザーとチームのどちらでも割り当てられる統合ドロップダウン。単一の情報源(SOT)は App\Support\Owners です。インスタンス・ハードウェア・ストレージの「担当(所有者)」項目がこれを使います。

アクセス制御 = レベル(user_level)のみ。役割とチームはプログラム的に権限を開きません。レベルの体系は アクセスレベル(RBAC) を参照してください。

こんなときに使う

画面構成

/admin/users(管理 ▸ ユーザー・権限)には2つのタブがあります。

タブ 内容
ユーザー ユーザー一覧(ログイン ID · 氏名 · メール · ロール · チーム · レベル · 状態 · 最終ログイン)+ モーダル CRUD
チーム チーム一覧(名称 · 色 · リーダー · 説明 · メンバー数)+ モーダル CRUD

ユーザー編集モーダルにはレベル/ロール/チームの選択欄があり、その下に次のヒントが表示されます。

レベルがアクセス権を決めます — デモ(閲覧)、スタッフ(運用)、管理者(すべて)。ロールは表示用のラベルです。

使い方

役割 — 職務ラベル

役割マスタは6件で、InfrRoleSeeder が key を基準に冪等に upsert します。

key ラベル 色トークン seq
dba DBA info 10
devops DevOps accent 20
security セキュリティ crit 30
admin 管理者 warn 40
staff スタッフ muted 50
developer 開発者 good 60

役割の admin(ラベル「管理者」)は 管理者レベル(10)とは何の関係もありません。役割は単なるラベルなので、役割が「管理者」でもレベルがデモ(1)のユーザーは何も保存できません。逆に、レベル10の管理者は役割が空でも管理機能をすべて使えます。

チーム — 組織単位

チームは チーム タブで自由に CRUD できます。シードされる4チームは次のとおりです。

名称 色 説明
インフラチーム accent サーバー・ネットワーク・ストレージ運用
セキュリティチーム crit 検知 · 対応 · 遮断
開発チーム good サービス開発 · デプロイ
DBA チーム info データベース運用 · チューニング

チーム編集項目:

項目 意味
名称(name) 必須。チーム名
色(color) バッジの色調(accent/crit/good/info/muted …)
リーダー(lead_user_id) ユーザー1名(任意)
説明(description) 自由記述
有効(is_active) 無効のチームは所有者ピッカーに表示されません

所有者ピッカー — ユーザーとチームの統合

資産(サーバーインスタンス、ハードウェア、ストレージ)には「担当(所有者)」項目があり、人でもチームでも 指定できます。この統合ピッカーのルールは App\Support\Owners(SOT)にあります。

保存形式 = 2カラム

資産テーブルは所有者を2つのカラムに保存します。

カラム 意味
owner_id ユーザーまたはチームの整数 PK
owner_type 'user' または 'team'

フロントエンドの受け渡し形式 = 単一の ref 文字列

ブラウザ(フォーム・フィルター)は owner_type と owner_id を1つの文字列としてやり取りします。

user:5     → user id 5
team:3     → team id 3

ブートストラップの選択肢(Owners::options())は optgroup 描画用に2つのグループを返します(20秒キャッシュ)。クローズされたユーザー(is_close=1)と無効のチーム(is_active=0)は除外されます。

{
  "users": [ { "ref": "user:5", "id": 5, "name": "Jane Doe" } ],
  "teams": [ { "ref": "team:3", "id": 3, "name": "Infra Team" } ]
}

サーバー側の分解・再構築

ヘルパー 挙動
Owners::split($ref) "user:5" → ['user', 5]。不正な形式 → ['user', 0](= 未割り当て)
Owners::ref($ownerId, $ownerType) (5, 'user') → "user:5"。ownerId が空 → null
Owners::resolveName($ownerId, $ownerType) カード・一覧用の表示名(該当なしなら null、20秒キャッシュ)
Owners::flush() ユーザー・チーム変更後にキャッシュを無効化

たとえばインスタンスの保存コントローラーは次のようにしています。

// 所有者 ref("user:5"/"team:3")→ owner_id + owner_type
[$ownerType, $ownerId] = Owners::split($request->input('owner_ref'));
$payload['owner_id']   = $ownerId ?: null;
$payload['owner_type'] = $ownerId ? $ownerType : 'user';   // 未設定時の既定は 'user'

同じ ref は所有者による 絞り込み にも使われます。一覧クエリは owner パラメーター(user:5/team:3)を split() で分解し、WHERE owner_id = ? AND owner_type = ? に絞り込みます。

所有者ピッカーは インスタンス、ハードウェア、ストレージ・ファイル の各資産画面でまったく同じものが再利用されています。チームを所有者に指定すると、責任の所在がチーム全体になります(誰か1人が抜けても揺らぎません)。

アバター · イニシャル · 色

ラベルの横に表示されるアバターは、氏名から RolePolicy が生成します。

データソース

テーブル 用途
infr_role 役割マスタ(情報用ラベル6件)— key·name·color·seq·is_active
infr_team チームマスタ — name·color·lead_user_id·description·is_active·seq
users ユーザー — user_level(アクセスを決定)、role_id(NULL 可)、team_id(NULL 可)
資産テーブル 所有者を owner_id + owner_type(user/team)の2カラムで保存(インスタンス/ハードウェア/ストレージなど)

SOT ヘルパー:

アクセス権限

ガード(最後の管理者の保護)

状況 結果
最後の有効な管理者を降格・無効化・削除する 拒否 — 「最後の有効な管理者は降格・無効化・削除できません。」
自分の管理者レベルを下げる・無効化する 拒否 — 「自分の管理者権限を降格・無効化することはできません。」
自分自身を削除する 拒否 — 「自分自身を削除することはできません。」
ログイン ID が既に使われている 拒否 — 「そのログイン ID は既に使われています。」

トラブルシューティング · FAQ

Q. 「セキュリティ」の役割を付けたのにセキュリティ画面が開きません。 役割はラベルであり、権限を開きません。セキュリティ画面(ほとんどが閲覧)には レベル が必要です — スタッフ(5)以上に引き上げてください。RBAC レベル を参照してください。

Q. 所有者のドロップダウンに出てこないユーザー・チームがあります。 クローズされたユーザー(is_close=1)と無効のチーム(is_active=0)はピッカーから除外されます。該当のユーザー・チームを再度有効にしてください。一覧が古いままの場合は20秒キャッシュの期限切れを待ちます(Owners::flush() で即座に無効化できます)。

Q. チームを削除すると、そのメンバーも消えますか。 いいえ。ユーザーは残り、team_id が null(未所属)になるだけです。資産の owner_type='team' 参照は別なので、資産も削除されません(所有者の表示が空になるだけです)。

Q. 所有者を保存したのに名前が表示されません。 resolveName() は20秒キャッシュです。名称を変更した直後であれば、まもなく反映されます。あわせて ref の形式が user:5/team:3 になっているか確認してください。形式が壊れていると split() は未割り当て(user:0)として扱います。

Q. 1人のユーザーに役割を2つ持たせられますか。 いいえ。role_id は単一の値(NULL 可)です。組織的なグルーピングも必要なら、チーム(これも単一の値)を使ってください。

関連項目

사용자 · 팀 관리
사용자 · 팀 관리