Files
firefrost-services/docs/code-bridge/archive/REQ-2026-04-14-server-command-center.md

11 KiB

Feature Request: Server Command Center Rebuild

Date: 2026-04-14 Topic: Rebuild Trinity Console server module into a full server command center Priority: HIGH — post-launch week, target build start April 15+ Filed by: Chronicler #87 Scope: Large — multiple new files, DB migration, new npm dependency


Background

The current server matrix page (/admin/servers) is functional but minimal:

  • Shows online/offline, whitelist status, last sync, Discord channel status
  • Sync Now + Toggle Whitelist buttons only
  • Discord channel detection is broken for many servers (slug derivation from full name fails)
  • No power controls, no restart scheduling, no createserver/delserver from UI
  • _matrix_body.ejs duplicates all card HTML inline instead of using _server_card.ejs

Michael wants this page to become a Server Command Center — the single place to manage every aspect of every game server without touching the Pterodactyl panel UI.


Session Context (Chronicler #87, April 13-14)

Tonight we:

  • Discovered all Discord channel detection is broken due to slug derivation failures (e.g. "All the Mods 10: To the Sky" → code generates all-the-mods-10-to-the-sky, Discord has atm10-tts)
  • Designed the short_name system to fix this permanently
  • Added Pterodactyl Admin API key to Arbiter .env and ops manual
  • Added Uptime Kuma API key to Arbiter .env
  • Confirmed Uptime Kuma 2.1.0 uses Socket.IO (not REST) for monitor management
  • Established that /createserver and /delserver move to Trinity Console buttons (slash commands remain as fallback only)
  • Confirmed 5 Discord channels per server: chat, in-game, forum, status, voice

New Environment Variables (already added to /opt/arbiter-3.0/.env)

UPTIME_KUMA_URL=http://localhost:3001
UPTIME_KUMA_API_KEY=uk2_-iM8Trb4ftJCedpv2Kcz2JRSD49Zrv-gbNkVyh87
PANEL_ADMIN_KEY=ptla_4eKCnPBofAmvLDjouTGS5OagDpIra58nRetjnXOeoh5

Note: PANEL_CLIENT_KEY and PANEL_APPLICATION_KEY already exist in .env. Use PANEL_ADMIN_KEY for power actions and application-level calls.


Part 1: Database Migration

New table: server_config

CREATE TABLE IF NOT EXISTS server_config (
  server_identifier VARCHAR(36) PRIMARY KEY,
  short_name VARCHAR(64) UNIQUE,
  short_name_locked BOOLEAN DEFAULT false,
  display_name VARCHAR(128),
  restart_enabled BOOLEAN DEFAULT true,
  restart_offset_minutes INTEGER DEFAULT 0,
  node VARCHAR(8),
  pterodactyl_name VARCHAR(128),
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

restart_enabled and restart_offset_minutes are for Task #94 (Global Restart Scheduler) — include now, use later.


Part 2: New npm Dependency

npm install uptime-kuma-api

This is the official Socket.IO wrapper for Uptime Kuma 2.x. REST API only exposes status pages — monitor CRUD requires Socket.IO.


Part 3: New Service Files

src/services/uptimeKuma.js

Wrapper around uptime-kuma-api. Must handle:

  • Connect/disconnect lifecycle (don't leave connections open)
  • createMonitor(name, hostname, port, discordChannelId) — creates a Game monitor type, sets Discord notification to the status channel
  • deleteMonitor(name) — finds by name, deletes
  • Error handling if Kuma is unreachable (don't crash createserver)

Monitor config to use:

  • Type: port (TCP port check, works for Minecraft)
  • Interval: 60 seconds
  • Name format: {pterodactyl_name} - {node} (matches existing monitors e.g. "Stoneblock 4 - TX")
  • Notification: Discord webhook to the {short_name}-status channel

Important: Look at existing monitors in Uptime Kuma to match the exact format. Run this to see existing monitor names:

# Check existing monitor names via Kuma API

src/services/pterodactyl.js

Consolidate Pterodactyl API calls. Must handle:

  • powerAction(identifier, signal) — start/stop/restart/kill
  • sendCommand(identifier, command) — send console command
  • getServerResources(identifier) — CPU, RAM, player count (via SFTP query or resources endpoint)
  • Uses PANEL_CLIENT_KEY for client endpoints, PANEL_ADMIN_KEY for application endpoints

Part 4: Backend Route Changes

src/routes/admin/servers.js — major additions

POST /:identifier/set-short-name

  • Validates short_name is URL-safe (lowercase, hyphens, numbers only)
  • Checks uniqueness against server_config table
  • If not locked: saves to DB, sets short_name_locked = false
  • Returns updated card HTML via HTMX

POST /:identifier/lock-short-name

  • Sets short_name_locked = trueIRREVERSIBLE
  • Returns updated card HTML (lock button disappears, field becomes read-only)

POST /:identifier/createserver

  • Requires short_name_locked = true — reject if not
  • Creates Discord category: 🎮 {pterodactyl_name}
  • Creates 5 channels under category:
    • {short_name}-chat (text)
    • {short_name}-in-game (text)
    • {short_name}-forum (forum)
    • {short_name}-status (text — Uptime Kuma posts here)
    • {pterodactyl_name} (voice)
  • Creates Uptime Kuma monitor linked to status channel
  • Returns success/error to card

POST /:identifier/delserver

  • Confirmation required (HTMX confirm dialog)
  • Deletes all 5 channels + category from Discord
  • Deletes Uptime Kuma monitor
  • Does NOT delete server_config row (keep history)
  • Does NOT touch Pterodactyl (server stays in panel)

POST /:identifier/power

  • Body: { signal: 'start' | 'stop' | 'restart' | 'kill' }
  • Calls pterodactyl.powerAction()
  • Returns inline status to card

POST /:identifier/console

  • Body: { command: string }
  • Calls pterodactyl.sendCommand()
  • Used for the restart warning title/tellraw commands

Part 5: View Changes

src/views/admin/servers/_server_card.ejs — full rebuild

Each card should display:

Header row:

  • Server name (bold)
  • Node badge (🔥 TX1 or ❄️ NC1)
  • Online/offline pill (green pulse or gray)

Short name section (shown if not locked):

  • Text input: "Discord short name (e.g. atm10-tts)"
  • "Save" button → hx-post="/:id/set-short-name"
  • "Lock In" button (red, confirm dialog) → hx-post="/:id/lock-short-name"
  • Warning: "⚠️ Once locked, this cannot be changed"

Short name section (shown if locked):

  • Shows short-name as read-only badge
  • No edit option

Stats row (2-col grid):

  • Whitelist: Enabled / 🔓 Disabled
  • Last Sync: timestamp

Discord channels status:

  • If locked: show each of 5 channels with /
  • If not locked: show "Set short name to enable channel detection"

Action buttons:

  • Sync Now
  • Toggle Whitelist
  • 🚀 Create Server (Discord) — only if locked, only if channels missing
  • 🗑️ Delete Server (Discord) — only if channels exist, red, confirm required
  • Power: ▶️ Start | ⏹ Stop | 🔄 Restart (only if online status known)

src/views/admin/servers/_matrix_body.ejs

Refactor to use <%- include('./_server_card', { server }) %> instead of duplicating card HTML.


Part 6: Discord Channel Detection Fix

Update checkServerChannels() in servers.js to use short_name from server_config instead of deriving from the full server name.

// NEW: use short_name from DB
function checkServerChannels(shortName, serverName, allChannels) {
  if (!shortName) return { missing: [], found: [], complete: false, unconfigured: true };
  
  const expectedChannels = [
    { name: `${shortName}-chat`, type: 'text' },
    { name: `${shortName}-in-game`, type: 'text' },
    { name: `${shortName}-forum`, type: 'forum' },
    { name: `${shortName}-status`, type: 'text' },
    { name: serverName.split(' - ')[0].replace(/\s*\([^)]*\)/g, '').trim(), type: 'voice' }
  ];
  // ... rest of detection logic
}

Part 7: Existing Short Names to Pre-Populate

These are already confirmed from Discord channel audit (Chronicler #87):

Pterodactyl Name short_name Node
All the Mods 10: To the Sky atm10-tts NC1
All the Mons all-the-mons NC1
Mythcraft 5 mythcraft-5 NC1
All of Create (Creative) all-of-create NC1
DeceasedCraft deceasedcraft NC1
Sneak's Pirate Pack sneaks-pirate-pack NC1
Otherworld [Dungeons & Dragons] otherworld NC1
Farm Crossing 6 farm-crossing-6 NC1
Homestead - A Cozy Survival Experience homestead NC1
Stoneblock 4 stoneblock-4 TX1
Society: Sunlit Valley society-sunlit-valley TX1
Submerged 2 submerged-2 TX1
Beyond Depth beyond-depth TX1
Beyond Ascension beyond-ascension TX1
Cottage Witch cottage-witch TX1
All The Mons (Private) - TX all-the-mons-private TX1
Wold's Vaults wolds-vaults TX1

Write a migration script that pre-populates server_config with these AND sets short_name_locked = true for all of them — they're already live in Discord, locking is appropriate.

Farm Crossing 6 is missing its -status channel — note this in the card UI so Michael can run createserver for just that channel (or we handle partial channel creation).


Part 8: Files to Create/Modify

File Action
src/services/uptimeKuma.js NEW
src/services/pterodactyl.js NEW
src/routes/admin/servers.js MODIFY (major)
src/views/admin/servers/_server_card.ejs REBUILD
src/views/admin/servers/_matrix_body.ejs REFACTOR
package.json MODIFY (add uptime-kuma-api)
migrations/add-server-config.sql NEW
migrations/seed-server-config.sql NEW

Part 9: What NOT to Build Yet

These are on the roadmap but NOT in this request:

  • Restart scheduler UI — Task #94, separate request after this lands
  • Console command input on card — Phase 2
  • RAM/CPU/player count display — Phase 2
  • Partial channel creation (create only missing channels) — Phase 2

Build the foundation clean. Phase 2 adds to it.


Deployment Notes

  • Run npm install after adding uptime-kuma-api
  • Run migration SQL before deploying new code
  • Pre-populate server_config with seed data before first load
  • Test createserver on a non-live server first (use All of Create Creative as test bed — it has no subscribers)
  • Standard deploy pattern: clone to /tmp, rsync to /opt/arbiter-3.0, restart arbiter-3

Questions for Code Before Starting

  1. Does uptime-kuma-api npm package support Uptime Kuma 2.1.0? Verify before using.
  2. What's the correct Discord category structure — should all 5 channels live under one 🎮 {name} category, or does the voice channel go in a separate voice category?
  3. Farm Crossing 6 is missing only the -status channel — should createserver handle partial creation (only create missing channels) or always create all 5?

Filed by Chronicler #87 — April 14, 2026 This is the foundation of the Server Command Center. Build it clean.