Add admin shard control: config, status, town crier (phase 5)

- admin/uoLink.controller.js: GET /admin/uo-link/config (masked config + live
  health + ingestion stats from the socket/broadcaster); PUT to save base/ws
  URL + write-only token + protocol + enabled, which (re)starts or stops the WS
  ingest client and activity-logs the change; POST/DELETE /uo-link/towncrier to
  publish/remove town-crier messages; GET /uo-link/stream (admin SSE channel,
  full feed incl. audit/cheat). Mounted adminOnly with express-validator guards
  + #swagger annotations (new "Admin · Shard" tag, TownCrierRequest schema).
- server.js: startup probe (checkUoLink) that logs reachability and warns
  loudly on a protocol mismatch when the integration is enabled.
- client: api.admin uo-link methods; ShardAdmin.jsx control panel (status
  panel with ingestion stats, config form, town crier) modeled on
  DiscordBotAdmin; wired into AdminLayout nav/titles + the /admin/shard route.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011qPmpmVH1xGCiZoz9m9vW3
This commit is contained in:
2026-07-11 02:22:17 -05:00
parent 1c9a9d26e1
commit e7bc316863
9 changed files with 825 additions and 0 deletions

View File

@@ -57,6 +57,7 @@ const doc = {
{ name: 'Admin · Activity', description: 'Admin activity log' },
{ name: 'Admin · Bot Activity', description: 'Bot-scoring/ban state and emergency unban (admin only)' },
{ name: 'Admin · Discord Bot', description: 'Discord bot token/config and live status (admin only)' },
{ name: 'Admin · Shard', description: 'uo-link sidecar connection config, live status and town crier (admin only)' },
{ name: 'Admin · Auth Providers', description: 'SSO provider configuration (admin only)' },
{ name: 'Admin · Users', description: 'User management (admin only)' },
],
@@ -587,6 +588,15 @@ const doc = {
linkedAt: { type: 'string', format: 'date-time' },
},
},
TownCrierRequest: {
type: 'object',
required: ['id', 'lines'],
properties: {
id: { type: 'string', maxLength: 64, description: 'Re-posting the same id replaces the prior entry.', example: 'news-42' },
lines: { type: 'array', items: { type: 'string', maxLength: 200 }, example: ['Hear ye!', 'Market tax is now 5%.'] },
durationSec: { type: 'integer', minimum: 1, maximum: 86400, example: 3600 },
},
},
},
},
}