Files
browser/openspec/changes/repair-server-live-operations-console/design.md
T

4.5 KiB

Context

Server cards and server detail headers already consume GET /api/v1/metrics/server-instances, but the Platform service currently synthesizes online server values from instance identity and config version when no Run sample exists. The repository already has durable metric sample ingest/query, log stream metadata, cursor-based log queries, job polling, and a SCUM Source RCON dispatch path. The change should connect those existing primitives to the operator UI without adding raw shell access or leaking machine details.

Goals / Non-Goals

Goals:

  • Make per-server metrics represent the latest real Run sample or a clearly empty/stale state.
  • Refresh server list and detail operational data automatically at bounded intervals.
  • Keep 编辑部署 on the server list and remove deployment editing from the server detail page.
  • Replace the low-value detail overview surface with direct operational sections and drawers for live logs and management terminal.
  • Keep logs and commands readable in the existing game-operations theme and shared console primitives.

Non-Goals:

  • No browser-direct shell, raw socket console, host-path display, credential display, or Run endpoint address display.
  • No new run executor source tree, cloud-provider workflow, billing, or marketplace expansion.
  • No platform-side game-specific command execution beyond routing through existing plugin/platform-mediated capabilities such as Source RCON.

Decisions

Decision 1: Latest sample beats synthetic projection

ListServerMetricsForSession will select the most recent persisted MetricSample for each visible server. If no sample exists, the response returns only safe identity/online/source/timestamp metadata with no fabricated player, TPS, latency, or resource percentages. The UI will render --, 等待上报, or 指标过期 based on sample freshness.

Alternative considered: keep deterministic placeholders and label them as simulated. This still makes the server card look operational when it is not, so it is rejected.

Decision 2: Polling over new transports

The frontend will use bounded polling: server cards refresh metrics/jobs every few seconds, detail headers refresh the same projections, and live logs tail with /log-streams/query using afterSeq. This reuses existing routes and avoids adding WebSocket/SSE infrastructure in the same change.

Alternative considered: introduce WebSockets for true streaming. That is better long-term, but it would require new transport contracts and channel ownership beyond this targeted repair.

Decision 3: Drawers for live operational windows

Server list actions open drawers/dialogs for 实时日志 and 管理终端. These windows do not resize cards, cover metrics inside the card, or create a tall action stack. The log drawer supports source selection, pause/resume, manual refresh, clear visible buffer, and autoscroll. The terminal drawer provides command history-like output and uses the existing SCUM Source RCON dispatch for SCUM servers; unsupported plugins show a safe unsupported state.

Alternative considered: route every action through the detail page. Operators asked for card-level fast access, so drawers preserve context without forcing navigation.

Decision 4: Detail page starts as an operations workspace

The detail page no longer exposes deployment editing and does not keep a default overview panel. Its navigation starts on live logs and keeps configuration, plugin controls, AI assistant, operation history, and runtime controls as explicit sections. Runtime binding and distribution controls remain available where they are operational controls, not the create/list deployment editor.

Alternative considered: keep overview but empty it down. That preserves a tab the user already identified as low-value, so it is removed.

Risks / Trade-offs

  • [Risk] Existing local/demo data may have no metric samples and therefore show fewer numbers. → Mitigation: render clear pending/stale labels and retain manual refresh.
  • [Risk] Polling can create noisy requests on many cards. → Mitigation: use bounded intervals, reuse existing list endpoints, and clear timers on unmount.
  • [Risk] Operators may expect a raw terminal. → Mitigation: label it 管理终端, show the mediated command target, and make unsupported/direct-shell boundaries explicit in the UI.
  • [Risk] CSS changes could drift from the theme. → Mitigation: use shared console/drawer/button primitives and keep CSS declarations compact per repository rules.