Server status slot: states and data contract #51
Notifications
Due Date
No due date set.
Blocks
#57 The home board
ShadowsOverWestgate/sow-nodebb-theme
Reference: ShadowsOverWestgate/sow-nodebb-theme#51
Reference in New Issue
Block a user
Part of #47
Question
What does the server status slot show, and what data does it need?
Today
sow-nodebb-plugin-pages/templates/home.tplhardcodes two servers (Live, Testing), a dead dot, the string "Status unknown", a direct-connect addressplay.westgate.pw, and a Connect Guide link. Nothing is behind it. The servers are going live, so the slot needs to be designed for real data — and to degrade honestly until the feed exists.Resolve:
Then file the feed request as an issue in
sow-nodebb, carrying that contract, and link it here. Building the feed is out of scope for this map; specifying what it must return is not.Resolution
The slot answers exactly one question: "can I log in right now?" Everything that does not serve that decision is cut.
What it shows
Two peer cards, Live and Testing, side by side — equal weight, no subordination.
Each card:
X players online— the raw number, always. Honesty beats vanity:2 players onlineon a Tuesday morning is what it says. No thresholds, no "a few", no14/60cap (a fraction reads emptier than a count).hh:mm:ss, in a slot the failure states reuseOne Connect Guide link for the whole strip, not per card.
Explicitly cut as noise: player cap, last-updated (surfaced only when stale), any dashboard/telemetry chrome beyond the dot — per #49's No Machines, Only Fittings.
The three bad states
Collapsing these into one grey "Status unknown" is the current failure, and the worst of the three lies: server up, page says unknown, player leaves.
X players online+ uptimeOfflineRestarting(replaces uptime — the card never grows)Status unavailableThe address stays visible and copyable in every state, including the two where we do not know: the server may be fine and the player should be free to try anyway.
staleis decided by the browser, not the feed — a feed that is down cannot tell you it is down. Ifgenerated_atis older than the stale threshold, the page stops believing the document, whatever it says.Where the slot lives
Home only. A topbar status pip is a real idea but not this ticket's call — it is permanent chrome on every forum and wiki page, so it belongs to the shell tickets (#54 ornament set, #56 width and density) once those exist. Footer is worthless for a "right now" decision.
Transport: why not Prometheus directly
The truth already exists in Prometheus —
sow-codebase'sPlayerCountMetricsServiceexports player count and the online player list, plus readiness and main-thread metrics (sow-codebase/docs/server-overview.md). But the browser must never talk to Prometheus:sow-platform/docs/runbooks/observability.md): game metrics live onnetcup-game, NodeBB runs onovh-main(hosts/ovh-main/configuration.nix). Exporter and Prometheus ports bind to thebr-sowbridge only — "unreachable from the internet on either host" (modules/firewall.nix). A Prometheus never sees the other host.So Prometheus is the source of truth; a small JSON document is the transport. The JSON stops being hand-written and becomes a projection of the metrics.
Publisher: the game host (
netcup-game). It renders the document from its own local Prometheus and ships it to a public URL. Rejected alternative: NodeBB onovh-mainpulling fromnetcup-game, which needs a cross-host hole the observability design deliberately does not have. Publishing from the game host also means the status survives NodeBB being down, and staleness is self-evident from the timestamp.The data contract
Served as JSON over HTTPS,
Cache-Control: no-store, CORS readable by the forum origin.version1. Bumped only on a breaking change; consumers ignore unknown fields.generated_atserversservers[].idlive,testing). Never shown.servers[].nameservers[].stateup|down|restarting. No other value; an unknown value is treated asdown.servers[].players0when notup. Never null, never negative.servers[].addresshost:port, exactly as a player must type it.servers[].started_atnullunlessstateisup.servers[].game_timenullif unavailable.Uptime is derived, never transmitted. The feed sends
started_at; the browser subtracts it from its own clock. Nothing polls per second to make a clock tick — a per-second display, if wanted, is a local timer over a value already held.netcup-game.visibilitychange), refetched immediately on becoming visible again.Status unavailableregardless of itsstate.down.Out of scope, deliberately
Player names are not in v1. The contract carries counts only. The home page stays simple: count per server plus a link out to a real player list. A
/playerlistpage — portraits, hide flags, the Astrolabe-style view — is a separate effort spanningsow-nodebb-plugin-pages,sow-codebase, and platform metrics, and it is where the visibility/opt-out decision has to be made before any name is ever published. Arelith is inspiration, not a thing to copy.Follow-up issues
Building the feed is out of scope for this map; specifying what it must return was not.
netcup-game, per this contract.sow-status.jsonstub./playerlistpage (future, blocked on the two above).