Skip to main content

Dashboard

The dashboard is the app's home screen (route /). It answers two questions: what is running right now, and what is it costing? Everything else on the page is in service of starting or stopping a server.

The Hyveon dashboard: four KPI tiles across the top, a filter box, and a three-column grid of game cards each showing a status badge, hostname, cost per hour and Start button

The KPI strip

Four tiles across the top. Each has a label, a large value, and a small delta line underneath.

TileValueDelta line
Servers running2/5 — running over total declaredall idle, or 2 active
Current run rateSum of $/hour estimates across currently-running games, e.g. $0.12per hour
Est. month captotalPerHourIfAllOn × 24 × days in the current month — what a full month would cost with every server running 24/7, e.g. $89.28if every game ran all month
Active alertsCount of games in the error stateall healthy, or 3 need attention

Both cost tiles are computed entirely from the free per-game Fargate estimate (the costs.estimate IPC channel, already fetched for the game cards' $ per hour stat) and the current run state — the app makes no AWS Cost Explorer API calls, ever. There is no "no data" em-dash state for these tiles the way the old actuals-driven tiles had, because there is no external call that can fail: the underlying estimate is either available (from costs.estimate) or defaults to $0.00.

Servers running shows an em-dash when no games are declared at all. Active alerts always shows a real number, including 0.

For real dollars actually billed to your AWS account, see the Costs page's link-out to the AWS Cost Explorer console.

Game cards

One card per declared game. The grid is three columns on a wide window, two on a medium one, one on a narrow one.

Status badge

BadgeMeaning
RUNNINGAn ECS task is running and healthy
STARTINGRunTask has been issued; the task has not reached RUNNING yet
STOPPEDNo task running. This is the normal resting state
NOT DEPLOYEDNo infrastructure has been deployed yet — the Pulumi stack has no outputs. Run apply on the Infrastructure page
ERRORThe task or its status lookup failed

Every state change is also announced to screen readers, e.g. "minecraft server is now running".

When a card is in the ERROR state and the backend supplied a reason, that reason is shown as a short line of red text under the header, next to a warning icon — e.g. Task failed to start: insufficient capacity. No reason is shown if the backend didn't supply one.

Connect string

Under the game name the card shows the server's hostname (minecraft.example.com), falling back to its raw public IP if DNS has not resolved yet, or the muted text no hostname if neither is known.

When there is something to copy, a copy button sits next to it. Pressing it writes the hostname to your clipboard. There is no visible confirmation — no toast, no icon change — so if nothing seems to happen, the copy most likely worked. When both a hostname and a public IP are known, the IP is also shown in parentheses; the button copies the hostname.

Stat tiles

Three small tiles across the card:

LabelShows
Last runLive while running, Booting while starting, otherwise. Despite the label it is a state, not a timestamp
$ per hourEstimated Fargate cost for this game's CPU/memory pair, e.g. $0.049. if no estimate is available
TaskThe first eight characters of the running task's ID, or

Start and Stop

The card shows exactly one of the two buttons:

Game stateButtonEnabled
STOPPED / NOT DEPLOYEDStartYes
RUNNING / STARTINGStopYes
ERRORStartYes — lets you retry starting the server without leaving the dashboard

After pressing either button the card locks for three seconds, then re-fetches that one game's status and unlocks. The lock applies even if the call failed, so a transient error never leaves a card stuck.

Starting shows a toast: minecraft is starting. Failures show an error toast with the underlying reason.

Two more buttons sit alongside:

The stop confirmation

Pressing Stop opens a dialog:

Stop minecraft?

Active sessions will end.

[Cancel] [Stop server]

There is a checkbox: Don't ask again for this session. Ticking it and confirming suppresses the dialog for the rest of the session — subsequent Stop presses act immediately.

Two things to know about that suppression:

  • It is global, not per-game. Suppressing it on one card suppresses it for every card.
  • It lives in memory for the lifetime of the app window. It survives moving between screens; it is cleared when you restart or reload the app.

Ticking the box and then pressing Cancel does nothing — the suppression is only recorded if you actually confirm.

The undo toast

Every successful stop produces a neutral toast reading minecraft stopped with an Undo action, visible for five seconds. Pressing Undo issues a start for the same game and schedules a status refresh. It appears whether the stop went through the dialog or the suppressed fast path.

The file manager

Files on a game card opens a small modal titled File Manager — Minecraft:

Mounts the game's EFS save data — browse, upload, and download files.

The modal itself does not list files. It launches an on-demand FileBrowser container on Fargate that mounts that game's EFS access point read-write, then hands you a link to it.

ButtonBehaviour
LaunchStarts the helper task. Disabled while it is already running or starting
StopStops it. Disabled when nothing is running
CloseDismisses the modal. The helper task keeps running

The status line tracks the helper:

  • Not running. Click Launch to start FileBrowser.
  • Starting… checking again in 5 seconds.
  • Running — click the link below to open FileBrowser. — followed by an Open FileBrowser at http://<ip>:8080 ↗ link that opens in your browser.

Once launched, all browsing, uploading, downloading, renaming and deleting happens in FileBrowser's own web UI, not in Hyveon.

Login. Each launch generates a random password, bcrypt-hashes it, and starts the container with that hash instead of --noauth — FileBrowser enforces a real login instead of being wide open on its public port. The modal shows the username (admin) and the one-time plaintext password inline next to the connection link, right after a successful Launch — copy it now, since Hyveon never displays it again (a fresh, different password is generated on every launch, including a re-launch of the same game).

Things worth knowing:

  • Only one helper per game can run at a time.
  • The helper auto-stops after 2 hours if you don't stop it yourself — an EventBridge Scheduler one-time schedule calls ecs:StopTask directly the moment the task starts. Pressing Stop cancels that schedule too, so stopping early doesn't leave a stale auto-stop behind. This exists because the watchdog Lambda's idle-shutdown logic only ever looks at {game}-server tasks, never the FileBrowser helper's filemgr-* ones — a forgotten session used to run (and bill) indefinitely.
  • The helper's port is still reachable from the whole internet while it is up — only the auth gap is closed here, not the exposure. Narrowing the security group to the operator's own IP is a known, separately-tracked follow-up.
  • The connection is plain http://, not https:// — there is no TLS in front of the helper task, so the one-time password (and the FileBrowser session it starts) travels in cleartext. Treat the link as you would any unencrypted admin panel: fine for a quick trusted-network session, not for browsing it over an untrusted network.
  • Startup takes roughly 30 seconds; the modal polls every 5 seconds while the task is transitioning and stops polling once it settles.
  • If infrastructure has not been deployed you get Infrastructure not deployed. Deploy first. in the status line.

Dismiss the modal with Close, by clicking the backdrop, or by pressing Escape.

The pending-changes banner

When the declared game server configuration (deployment-config.json) has changes that have not been applied to AWS, an orange banner appears at the top of the dashboard:

Configuration changed, 3 changes pending — run plan and apply on the Infrastructure page to deploy (1 to create, 0 to delete, 2 to update) View pending

View pending links to the Games page. The banner is checked every 30 seconds.

How dismissal works

The × button dismisses the banner, but the dismissal is tied to the exact set of pending changes, not to a simple "hide" flag. Concretely:

  • Dismissing records a signature of the current drift report (which games, which kinds of change, which fields) in session storage.
  • The banner stays hidden while the drift report matches that signature. This survives moving between screens.
  • The banner comes back as soon as the pending set changes — a new game edited, one removed, different fields touched.
  • If a Pulumi apply clears the drift entirely, the stored dismissal is wiped, so if the same change reappears later you are told about it again.
  • Restarting or reloading the app clears the dismissal.

The banner is also hidden — rather than showing a broken state — if the drift check itself fails.

Filtering

A search box above the grid, placeholder Filter by game or hostname…. Matching is a case-insensitive substring against the game name or the hostname (or the public IP, when there is no hostname), so typing part of an address works.

Loading and empty states

SituationWhat you see
Before the first status poll returnsLoading servers…
No games declared or deployedA card headed No games deployed, explaining that you declare a game on the Games page, then run a plan and apply from Infrastructure to create its ECS task definition, EFS volume, and CloudWatch log group — with links to the setup guide and to add a game
Filter matches nothingNo games match "abc".

If the very first status poll fails, the page stays on Loading servers… — the polling indicator next to the filter box is what tells you something is wrong.

Polling

Game status is polled every 20 seconds, app-wide, and keeps running as you move between screens.

The indicator next to the filter box shows Updated 12s ago, spins while a poll is in flight, and reveals next refresh in 8s on hover. If two whole intervals pass without a successful poll it turns into a red Stale · last updated … pill, which clears itself on the next success.

The Refresh button in the top bar forces every poller to run immediately. The LIVE pill next to it summarises the same health across all pollers.

The top bar doubles as the app's window title bar — drag any empty area of it to move the window, and on Linux it shows in-app minimize/maximize/close buttons since the OS title bar is hidden.

Note that the underlying per-game cost estimates (costs.estimate) are fetched once on mount, not part of that 20-second cycle — see The KPI strip above. The Current run rate and Est. month cap tiles still change every poll, though, since they're recomputed from the current run state each time. The pending-changes banner has its own separate cadence — see The pending-changes banner above.