405 lines
16 KiB
Markdown
405 lines
16 KiB
Markdown
# 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:
|
|
|
|
```sql
|
|
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:
|
|
|
|
```sql
|
|
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):**
|
|
```json
|
|
{
|
|
"guild_id": "uuid",
|
|
"category_id": null,
|
|
"type": "voice",
|
|
"name": "lobby",
|
|
"topic": "General voice"
|
|
}
|
|
```
|
|
|
|
**CHANNEL_CREATED broadcast (0x0074):**
|
|
```json
|
|
{
|
|
"channel": {
|
|
"id": "uuid",
|
|
"guild_id": "uuid",
|
|
"category_id": null,
|
|
"type": "voice",
|
|
"name": "lobby",
|
|
"topic": "General voice",
|
|
"position": 3
|
|
}
|
|
}
|
|
```
|
|
|
|
**ADMIN_UPDATE_ROLE (0x0082):**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"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
|
|
```
|