VNOX-Server/docs/05-features/admin-panel.md

16 KiB

Admin Panel — Design

Target: Phase 1.1 (core) → Phase 1.2 (guilds, roles) → Phase 2 (plugins, bot permissions)

Separation of concerns

Layer Config file (TOML) Admin panel (GUI)
Infrastructure bind, ports, data_dir, TLS certs —
Node identity name, address Display only
Storage backend, sqlite_path, retention —
Security federation gate, rate limits, session timeout Ban list, mute, kick
Runtime state — Channels, roles, members, invites, audit log
Plugins Plugin enable/disable Permission keys, commands

Rule of thumb: If it needs a server restart → TOML. If it can apply live → GUI.


Permission System

Designed for both built-in actions and plugin/bot commands (inspired by LuckPerms).

Built-in permission keys

vnox.admin.manage_channels      — create, edit, delete channels
vnox.admin.manage_roles         — create, edit, delete roles
vnox.admin.manage_members       — kick, ban, mute, timeout
vnox.admin.manage_invites       — create, delete invites
vnox.admin.manage_guild         — edit guild name, icon, settings
vnox.admin.view_audit_log       — read audit log

vnox.channel.read               — view channel
vnox.channel.send               — send messages
vnox.channel.voice_connect      — join voice channel
vnox.channel.voice_speak        — speak in voice (push-to-talk)
vnox.channel.voice_mute_members — server-mute others

vnox.dm.send                    — send direct messages
vnox.friend.request             — send friend requests
vnox.presence.view              — see online status

Custom permission keys (plugin/bot commands)

Plugins register their permissions at load time via the RPC API:

mybot.command.greet            — /greet command
mybot.command.play             — /play music
mybot.command.ban_override     — override sub-command

Wildcard support:

vnox.admin.*                   — all admin permissions
vnox.channel.*                 — all channel permissions
mybot.*                        — all commands from mybot
*                              — everything (owner only)

How it works

┌──────────────────────────────────────────────────┐
│  Role Editor — "Moderator"                        │
├──────────────────────────────────────────────────┤
│  Permission keys:                                │
│                                                   │
│  ┌─ Built-in ──────────────────────────────┐     │
│  │ ☑ vnox.admin.manage_channels            │     │
│  │ ☑ vnox.admin.manage_members             │     │
│  │ ☐ vnox.admin.manage_roles               │     │
│  │ ☑ vnox.admin.view_audit_log             │     │
│  │ ☑ vnox.channel.*                        │     │
│  └──────────────────────────────────────────┘     │
│                                                   │
│  ┌─ Plugin permissions ────────────────────┐     │
│  │ ☑ mybot.command.greet                   │     │
│  │ ☐ mybot.command.play                    │     │
│  │ ☑ mybot.command.*                       │     │
│  └──────────────────────────────────────────┘     │
│                                                   │
│  ┌─ Custom key ────────────────────────────┐     │
│  │ [ Type a permission key... ]  [ +Add ]  │     │
│  └──────────────────────────────────────────┘     │
│                                                   │
│        [Cancel]  [Save]                           │
└──────────────────────────────────────────────────┘

Resolution order (highest priority wins):

  1. Owner — overrides everything
  2. Channel override (user-specific) — allow/deny
  3. Channel override (role-specific) — allow/deny
  4. Role hierarchy (top role has higher priority)
  5. @everyone default
  6. Server-wide default

Each override is (allow_mask, deny_mask) — deny always beats allow at the same level.

Database

Already specified in docs/10-database.md:

roles(id, guild_id, name, color, permissions BITMASK, position)
channel_overrides(id, channel_id, target_id, target_type, allow_mask, deny_mask)
member_roles(member_guild_id, member_user_id, role_id)

Custom permission keys are stored separately:

CREATE TABLE permission_keys (
  id TEXT PRIMARY KEY,
  guild_id TEXT NOT NULL,
  name TEXT NOT NULL,           -- e.g. "mybot.command.greet"
  description TEXT,             -- e.g. "Allow using /greet command"
  plugin_id TEXT,               -- which plugin registered it, null = built-in
  created_at TIMESTAMP NOT NULL
);

CREATE UNIQUE INDEX idx_perm_keys_guild_name ON permission_keys(guild_id, name);

Role grants use the same roles.permissions bitmask for built-in keys (first 128 bits). For custom/plugin keys beyond 128, they're stored in a separate table:

CREATE TABLE role_perm_grants (
  role_id TEXT NOT NULL,
  permission_key TEXT NOT NULL,  -- "mybot.command.greet"
  granted INTEGER NOT NULL,      -- 1 = allow, 0 = deny
  PRIMARY KEY (role_id, permission_key),
  FOREIGN KEY(role_id) REFERENCES roles(id)
);

Channel Management

Create Channel

Right-click channel list → "Create Channel"
  or
Server Settings → Channels → [+ Add]

Modal:

┌──────────────────────────────────────┐
│  Create Channel                      │
├──────────────────────────────────────┤
│                                      │
│  Name        [_________________]     │
│                                      │
│  Type        ○ Text  ● Voice         │
│                                      │
│  Category    [General ▼]  [None]     │
│                                      │
│  Topic       [_________________]     │
│                                      │
│  ┌─ Permissions ▾ ─────────────┐     │
│  │ @everyone                    │     │
│  │   ☑ View Channel             │     │
│  │   ☑ Send Messages            │     │
│  │   ☐ Voice Connect            │     │
│  │                              │     │
│  │ @admin                       │     │
│  │   ☑ Everything               │     │
│  └──────────────────────────────┘     │
│                                      │
│           [Cancel]     [Create]       │
└──────────────────────────────────────┘

Edit Channel

Double-click channel or right-click → "Edit Channel".

Same modal pre-filled, plus:

  • Name change — updates slug
  • Category change — moves channel
  • Drag position — reorder inside category
  • Delete — with confirmation (soft delete in DB)

Drag & Drop

Channels                    Server: My Server
─────────────────────────────────────────────
▶ TEXT CHANNELS                           [+]
  ○ general
  ○ announcements                       
▸ VOICE CHANNELS                         [+]
  ○ lobby         ← drag handles ≡
  ○ afk           ← can drag to reorder inside category
                  ← can drag to another category

Behavior:

  • Drag handle ≡ on hover
  • Drop zone highlight between channels and around categories
  • Hold Ctrl to copy permission overrides when moving to another category
  • Position stored in channels.position column (integer, step by 10 for gaps)
  • Changes broadcast via CHANNEL_UPDATED packet to all guild members in real-time

Server Settings UI Layout

Server Settings: "My Server"
─────────────────────────────────────────────
│  Navigation           │  Content Panel     │
│                       │                    │
│  Overview             │  ┌──────────────┐  │
│  Channels             │  │              │  │
│  Roles                │  │  (dynamic)   │  │
│  Members              │  │              │  │
│  Invites              │  └──────────────┘  │
│  Bans                 │                    │
│  Audit Log            │                    │
│  Plugins              │                    │
│  ───────────────────  │                    │
│  Danger Zone          │                    │
│    Delete Server      │                    │
│    Transfer Owner     │                    │
│                       │                    │
└───────────────────────────────────────────┘

Overview tab

┌──────────────────────────────────────────┐
│  Server Overview                          │
│                                          │
│  Name     [My Server________________]    │
│  Description [_______________________]   │
│                                          │
│  Icon     [🔵 Upload image]  drag & drop │
│                                          │
│  Owner:   loki5512344                    │
│  Region:  Warsaw (default)               │
│  Created: 2026-06-06                     │
│                                          │
│  ████████████████████░░  Manage Channels │
│  ████████████░░░░░░░░░░  Manage Roles    │
│                                          │
│              [Save Changes]              │
└──────────────────────────────────────────┘

Plugins tab

┌──────────────────────────────────────────┐
│  Plugins                                  │
│                                          │
│  ┌─ Installed ─────────────────────┐     │
│  │ 🎵 MusicBot     v1.2  [Config]  │     │
│  │    [Disable]  [Permissions ▸]   │     │
│  │                                  │     │
│  │ 🤖 ModBot       v0.8  [Config]  │     │
│  │    [Disable]  [Permissions ▸]   │     │
│  └──────────────────────────────────┘     │
│                                          │
│  [Install from URL...]                    │
│                                          │
│  ┌─ Permission Keys ──────────────────┐  │
│  │ Search: [___________________]  🔍  │  │
│  │                                    │  │
│  │ Key                     │ Granted  │  │
│  │ ────────────────────────────────   │  │
│  │ musicbot.command.play  │ admin    │  │
│  │ musicbot.command.skip  │ @everyone│  │
│  │ modbot.warn            │ mod      │  │
│  │ modbot.ban             │ admin    │  │
│  └──────────────────────────────────────┘
└──────────────────────────────────────────┘

LNEx Protocol Packets

New packets for admin operations:

PID 0x0070  ADMIN_LIST_CHANNELS     client → gateway
PID 0x0071  ADMIN_CREATE_CHANNEL    client → gateway
PID 0x0072  ADMIN_UPDATE_CHANNEL    client → gateway
PID 0x0073  ADMIN_DELETE_CHANNEL    client → gateway
PID 0x0074  CHANNEL_CREATED         gateway → broadcast
PID 0x0075  CHANNEL_UPDATED         gateway → broadcast
PID 0x0076  CHANNEL_DELETED         gateway → broadcast

PID 0x0080  ADMIN_LIST_ROLES        client → gateway
PID 0x0081  ADMIN_CREATE_ROLE       client → gateway
PID 0x0082  ADMIN_UPDATE_ROLE       client → gateway
PID 0x0083  ADMIN_DELETE_ROLE       client → gateway
PID 0x0084  ADMIN_ADD_ROLE_MEMBER   client → gateway
PID 0x0085  ADMIN_REMOVE_ROLE_MEMBER client → gateway

PID 0x0090  ADMIN_KICK_MEMBER       client → gateway
PID 0x0091  ADMIN_BAN_MEMBER        client → gateway
PID 0x0092  ADMIN_UNBAN_MEMBER      client → gateway
PID 0x0093  ADMIN_MUTE_MEMBER       client → gateway

PID 0x00A0  GUILD_UPDATE            client → gateway
PID 0x00A1  GUILD_DELETE            client → gateway (owner only)
PID 0x00A2  GUILD_TRANSFER          client → gateway (owner only)

Examples:

ADMIN_CREATE_CHANNEL (0x0071):

{
  "guild_id": "uuid",
  "category_id": null,
  "type": "voice",
  "name": "lobby",
  "topic": "General voice"
}

CHANNEL_CREATED broadcast (0x0074):

{
  "channel": {
    "id": "uuid",
    "guild_id": "uuid",
    "category_id": null,
    "type": "voice",
    "name": "lobby",
    "topic": "General voice",
    "position": 3
  }
}

ADMIN_UPDATE_ROLE (0x0082):

{
  "role_id": "uuid",
  "name": "Moderator",
  "color": 16744960,
  "permissions": {
    "vnox.admin.manage_channels": true,
    "vnox.admin.manage_members": true,
    "mybot.command.greet": true,
    "mybot.command.warn": true
  },
  "hoist": true,
  "mentionable": true
}

ADMIN_UPDATE_CHANNEL (0x0072) — includes position changes via drag & drop:

{
  "channel_id": "uuid",
  "name": "general",
  "category_id": "uuid",
  "position": 5,
  "topic": "General discussion"
}

Permission checks flow

Client click "Create Channel"
  │
  ▼
Client sends ADMIN_CREATE_CHANNEL → Gateway
  │
  ▼
Gateway checks:
  1. Is user authenticated?                → 403 if no
  2. Is user in guild?                     → 403 if no
  3. Does user have vnox.admin.manage_channels?
     - Resolve role hierarchy
     - Check channel_overrides (none — new channel)
     - Check wildcards (vnox.admin.*)
     - Owner override                     → 403 if no
  │
  ▼
Gateway: INSERT into channels table
Gateway: INSERT into channel_overrides if specified
Gateway: Broadcast CHANNEL_CREATED to all guild members
Gateway: Log to audit_logs
  │
  ▼
All clients in guild see new channel in channel list