AdminRole¶
The AdminRole table implements role-based access control (RBAC) for the QS-Bridge platform. Each row maps a player to an administrative role level, defining what actions they are authorized to perform through the admin panel or direct reducer calls.
Scope¶
🌍 Global — Admin roles apply cluster-wide. An administrator's role level is the same regardless of which server they are managing. All game hooks and the admin panel subscribe to the full table.
Schema¶
| Column | Type | Constraints | Description |
|---|---|---|---|
role_id |
u64 |
Primary Key, auto-increment | Unique identifier for this role assignment |
player_id |
String |
Unique | Platform-wide player identifier |
role |
AdminRoleLevel |
— | The assigned role level (enum) |
granted_by |
String |
— | Identifier of the admin who granted this role |
granted_at |
Timestamp |
— | When the role was granted |
Rust Definition¶
#[spacetimedb::table(public, name = admin_role)]
pub struct AdminRole {
#[primary_key]
#[auto_inc]
pub role_id: u64,
#[unique]
pub player_id: String,
pub role: AdminRoleLevel,
pub granted_by: String,
pub granted_at: Timestamp,
}
AdminRoleLevel Enum¶
#[derive(SpacetimeType, Clone, Debug, PartialEq)]
pub enum AdminRoleLevel {
Owner,
Admin,
Moderator,
}
| Level | Description | Typical Permissions |
|---|---|---|
Owner |
Platform owner / super-administrator | All operations; can grant/revoke any role |
Admin |
Full administrator | Bans, kicks, config changes, whitelist management |
Moderator |
Limited administrator | Kicks, temporary bans, view-only for some settings |
Usage Patterns¶
Authorization in Panel Reducers¶
Panel wrapper reducers check the caller's admin role before delegating to the underlying admin reducer. This provides a second authorization layer beyond the is_gateway() guard:
// Pseudocode — panel reducer authorization
#[spacetimedb::reducer]
pub fn panel_ban_player(ctx: &ReducerContext, player_id: String, reason: String) {
if !is_gateway(ctx) {
return;
}
// Look up the panel session to identify the acting admin
let session = PanelSession::filter_by_player_id(&actor_player_id)
.expect("Panel session must exist");
// Check role level
let role = AdminRole::filter_by_player_id(&session.player_id);
match role {
Some(r) if r.role == AdminRoleLevel::Admin || r.role == AdminRoleLevel::Owner => {
// Authorized — proceed with ban
admin_ban(ctx, player_id, reason);
}
_ => {
log::warn!("Insufficient permissions for panel_ban_player");
}
}
}
Unique Constraint¶
The unique constraint on player_id ensures each player has at most one role assignment. To change a player's role, the existing row must be updated — not a second row inserted. This prevents conflicting role assignments.
Role Hierarchy¶
The AdminRoleLevel enum defines an implicit hierarchy: Owner > Admin > Moderator. The platform does not enforce this hierarchy through database constraints — it is enforced in reducer logic. For example, a Moderator cannot grant Admin roles, and an Admin cannot revoke an Owner role.
Game Hook Usage¶
Game hooks subscribe to the AdminRole table to identify in-game administrators. This enables game-specific features like admin commands, spectator mode access, or debug tools based on the player's platform-level role.
Related Reducers¶
| Reducer | Operation |
|---|---|
admin_grant_role |
Inserts or updates an AdminRole row |
admin_revoke_role |
Deletes the AdminRole row for a player |
Related Subscriptions¶
| Subscriber | Query | Purpose |
|---|---|---|
| Game Hook | SELECT * FROM admin_role |
In-game admin identification and permissions |
| Admin Panel | SELECT * FROM admin_role |
Role management UI, permission checks |
For full subscription architecture, see Subscriptions.
Related Pages¶
- PanelSession — Active panel sessions (references admin level)
- PanelAuditLog — Audit trail for role changes
- Reducers —
admin_grant_roleandadmin_revoke_role - SpacetimeDB Module — The
is_gateway()guard and authorization model