From 896ad689ed3c3a02047af503edd00a430b61a817 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 21:39:56 +0000 Subject: [PATCH 1/4] docs: mirror the main repo roadmap status Current pre-v1 release, shipped in v0.3.0 and since, and one In progress line per open spec. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- src/content/docs/roadmap.mdx | 417 ++++++++++++++++++++++++++++++----- 1 file changed, 360 insertions(+), 57 deletions(-) diff --git a/src/content/docs/roadmap.mdx b/src/content/docs/roadmap.mdx index 3ad649d..cbf6e84 100644 --- a/src/content/docs/roadmap.mdx +++ b/src/content/docs/roadmap.mdx @@ -13,62 +13,365 @@ import DocsCallout from "../../components/docs/DocsCallout.astro"; import IconList from "../../components/docs/IconList.astro"; import { VERSION } from "../../config"; -## Beta status — {VERSION} - -Core workflows — deploy a game server, console, files, backups/restore, modules, RBAC — work end to end and are covered by unit, integration, and kind-based e2e test suites. - -
- - -
- -## Coming in v0.3.0 - - - The following features are in active development for v0.3.0-rc.1 and later. They are not available in v0.2.0-beta.8. +## Current release + +- **Version:** {VERSION} (pre-v1), released 2026-10-05. See the [changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md). +- **What works today:** see the [README](https://github.com/GameplanePanel/Gameplane/blob/master/README.md) and the [architecture overview](./architecture/). + + + The CRDs, operator, API, agent, and dashboard are feature-complete for the v1 scope and stabilized for external testing, but the project is not yet recommended for unattended production. This page tracks what stands between v0.3 and a v1 GA release. -
- - -
- -Deferred items graduate off this list as they ship — the [changelog](../changelog/) has the release-by-release record. +It is a living document: items move out of it as they ship, and anything discovered along the way gets added. + +--- + +## Shipped in v0.3.0 and since + +### Since v0.3.0 (Unreleased) + +- Independent central panel: Docker Compose runs the API and dashboard without a host Kubernetes cluster; a standalone Helm profile runs without the central operator or workloads ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Credential maintenance: standalone key custody, offline `rotate-panel-key`, `PUT /clusters/{name}/kubeconfig`, and `PUT`/`DELETE /clusters/{name}/gateway` ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Extended telemetry tier: a second, separately consented tier with a random install ID and fixed-set categories; signed reports ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Telemetry receiver dashboard and an optional public `GET /v1/summary` ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Proof-of-work on telemetry ingestion, off by default ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Telemetry provider runbook at `docs/telemetry-provider.md` ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Optional Steam display names on player lists, via a Steam Web API key ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Nuclear Option player lists are structured (`steamId`, `faction`) ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- New optional `GameTemplate` field `spec.rcon.authentication` (default `true`) allows consoles with no RCON Secret ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Standalone credential protection: keys kept outside database volumes, transactional rotation ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Remote workload boundaries: verified TLS, dial-time unsafe-destination rejection, bounded responses; `GAMEPLANE_REMOTE_ALLOWED_CIDRS` / `api.remoteAllowedCIDRs` ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Removed: the Hell Let Loose module is withdrawn from the official catalog ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Upgrade-note behaviour changes: telemetry is on by default for new installs after a first-login notice; installs with a saved basic toggle start sending to the default receiver after upgrade; an empty `api.telemetry.endpoint` means the project default receiver; the receiver `/metrics` moved to `:8081` and needs the dashboard token; the bundled receiver stores data on a PVC by default; receiver `DASHBOARD_TOKEN` must be at least 32 characters ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Breaking: selected-cluster module and template grants need a cluster-wide grant for remote catalogs ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Upgrade note: every game pod gains an empty capture `emptyDir`, so existing GameServers roll once on upgrade ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). + +### Shipped in v0.3.0 + +- Configurable backup/restore Job retry limit and deadline Helm values ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Multicluster gateways and unified server management across clusters ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- User theme customization: presets, custom colors with a WCAG AA check, custom CSS overlay, safe mode ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Network capture sidecar: admin-only, on-demand PCAPNG capture from running game pods ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Module authoring toolkit `gp-module` (scaffold, validate, preview, package) and the dashboard Modules builder ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- 13 new top Steam game modules ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Nuclear Option dedicated server support ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Install-time config: Helm-seeded OIDC role mappings and a default StorageClass for game-data PVCs ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Share link expiry options (presets, custom date, no expiry) replacing the 90-day cap ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Console WebSocket robustness on non-default ports, and input queueing ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Existing PVC for SQLite via `api.storage.existingClaim` ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- REST and CLI console protocols for games with HTTP admin APIs or PTY-only consoles ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Mod archive path confinement (zip-slip and symlink guards) ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Design and visual polish: HeroUI foundation and brand re-theme ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Experimental PostgreSQL backend works end to end ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Owner-only server operations (transfer, collaborators, wipe, delete) need the owner or an admin ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Data wipe failures fail the Job and set `DataWipe=False`; backup/restore quiesce lifecycle fixed, and restore removes files created after the snapshot ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- SQLite DSN gets `busy_timeout(5000)` by default; agent metrics on a separate unauthenticated `:9090` listener that the PodMonitor scrapes ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). +- Multi-cluster request scoping, OIDC role re-evaluation, bootstrap-admin reset, cluster registration removal, mod bundle integrity, and tunnel credential handling hardened ([changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md)). + +### Earlier releases (before v0.3.0) + +#### Multi-cluster: dashboard cluster selector (PR #107) (shipped v0.2.0-beta.6) + +The initial dashboard selector routed requests to one cluster at a time. The +[unified dashboard](https://github.com/GameplanePanel/Gameplane/blob/master/docs/unified-dashboard.md) now combines authorized resources with +optional location filters; selection remains in node inventory administration. +Server operations retain their own cluster and namespace. Pod logs and PTY +WebSockets use that cluster's Kubernetes API. + +The [optional private agent gateway](./remote-agent-gateway/) supports RCON, +game-file logs, file/player operations, module actions and agent-based mods. +Remote capture downloads and cleanup bind files to GameServer and NetworkCapture +UIDs. Registry browsing, modpacks and ID-list configuration use the selected +Kubernetes client and template. Upgrade the gateway, operator, agents and capture +sidecars together; direct Kubernetes connectivity remains required. + +Dedicated gateway health in the dashboard remains follow-up work. The existing +cluster-health indicator reports Kubernetes connectivity only. + +#### Multi-cluster: dual-cluster e2e coverage (PR #104) (shipped v0.2.0-beta.6) + +A real `kind ×2` e2e test (multicluster bucket) asserting `?cluster=` dispatch +lands a GameServer on cluster B and that a viewer scoped to cluster A cannot see it. + +#### Audit log integrity (tamper evidence) (PR #103, dashboard banner PR #108) (shipped v0.2.0-beta.6) + +Complete end-to-end. Backend: migration `005_audit_chain.sql`, +`Auditor.insertChained`/`Auditor.Verify`, and `GET /admin/audit/verify`. The +dashboard integrity banner — surfacing a verification break to the admin on the +audit page — shipped in PR #108. + +**Design (as implemented):** + +- Migration `005_audit_chain.sql` added `prev_hash` + `hash` columns. +- On insert (inside a transaction, serialized per-process by a mutex — see the + single-writer caveat on `insertChained`) compute + `hash = SHA-256(prev_hash || canonical(row))`, and upsert `audit.head` + (the newest row's id + hash) in the same transaction. +- `Verify()` walks the chain and reports the first break, exposed as an + admin-only `GET /admin/audit/verify`. It also checks `audit.head` against + the newest surviving row, so truncating the tail (`DELETE ... WHERE id > N`, + which leaves every surviving link internally consistent) is detected too — + previously a known blind spot. +- `Prune` writes a checkpoint (the newest about-to-be-deleted row's id + hash, + in the `config` table under `audit.checkpoint`) before deleting, so + verification resumes from the checkpoint rather than the genesis row. + +**What this does and does not guarantee:** the chain is unkeyed, and the +checkpoint/head it verifies against live in the same DB-writable `config` +table. It reliably catches naive in-DB tampering (`UPDATE`/`DELETE`, including +tail truncation) and accidental corruption — it does not, and cannot, defeat a +sophisticated attacker with DB write access who also recomputes and rewrites +the checkpoint/head to match. The external sinks (stdout/webhook/S3) remain the +append-only record of last resort such an attacker cannot retroactively alter. +An HMAC-keyed chain (key held outside the database) would close that +remaining gap and is a candidate future hardening, not yet implemented. + +Threat-model context lives in [`security.md`](./security/). + +#### Upgrade testing (`e2e upgrade` bucket) (shipped v0.2.0-beta.8) + +`helm upgrade` was the most dangerous operation a user performs and the only +one CI never exercised. It now runs on every PR, on both amd64 and arm64: +`deploy/kind/upgrade.sh` installs the **previous release's published chart and +published GHCR images**, `TestUpgrade_FromPreviousRelease` seeds a running +GameServer with data plus an admin user, upgrades to the working-tree chart, +and asserts the CRD schema was updated, the server and its volume bytes +survived, and the pre-upgrade admin can still log in (proving migrations ran +against a populated SQLite volume). + +The CRD assertion is self-calibrating: it computes which schema properties the +working tree declares that the installed release lacks, then requires the +pre-upgrade hook to have added exactly those — so it cannot rot into a vacuous +pass as the schema evolves. + +This closes the CRD-upgrade caveat as a *tested* path rather than a documented +one. Note the caveat's own docs were stale and are corrected: the chart's +`crds.autoApply` pre-upgrade hook has been applying CRDs automatically for a +while, but [`install.md`](./installation/) still told users to run +`kubectl apply` by hand. + +Not yet covered: upgrades skipping several releases at once, and Postgres [experimental]. + +#### Idle auto-sleep (backend PR #180, dashboard PR #182) (shipped v0.2.0-beta.8) + +Opt-in per server (`spec.idle`): the operator scales a GameServer to zero once +it has reported no online players for `afterMinutes`, and brings it back on a +`wakeWindows` cron tick or an explicit `POST /servers/{name}:wake`. On a +single-node homelab the overnight reservation of several idle servers is the +dominant cost; this releases it without touching the data volume. + +**Design (as implemented):** + +- Sleeping drives the existing `softStop` path, so the module-declared stop + sequence runs and the world saves before the pod goes away. +- The sleep marker is an operator-owned annotation, **not** `spec.suspend`. + That field is the user's own power switch (the `:start`/`:stop` verbs patch + it), so overloading it would make an automatic sleep indistinguishable from a + deliberate stop — and a wake window would then resurrect a server its owner + had turned off. Wake uses a request/ack token pair like the restart primitive. +- Phase reuses `Suspended`; the `IdleAsleep` condition reason, `status.idle`, + and an `-o wide` print column distinguish it from a manual stop. +- A stale heartbeat or an absent player count both freeze the idle clock rather + than reading as empty — unknown is not zero. Each refusal records a reason on + `status.idle`, so a server that can never sleep explains itself. +- `gameplane_gameservers_idle{state=asleep|awake}` reports the saving. +- The dashboard (PR #182) renders a slept server as **Asleep** rather than + `Suspended`, and replaces its Start button with **Wake**. That substitution + is a bug fix, not decoration: an asleep server has `spec.suspend` still + `false`, so the Start button the phase used to offer patched a field to the + value it already held — a silent no-op that never woke anything. Only + `:wake` clears the operator's marker. +- The server's Overview surfaces `status.idle.reason` (capitalized) as the + sleep card's own state line — including while still asleep, if a wake + window failed to parse — so a server that isn't accumulating idle time + says why instead of looking broken. The one reason meaning the trigger can + never fire ("this game reports no player count") gets a plainer "Will + never sleep" label instead, with the operator's reason underneath it. + +**Follow-up:** `status.idle.nextWakeTime`. The dashboard lists the configured +wake windows as raw cron strings, because the operator computes the next tick +only for its own requeue and never persists it — and re-deriving it in the +browser would duplicate scheduling semantics the operator owns (rule 10). +Persisting it on status is the right fix, and is a CRD change rather than a +dashboard one. + +#### Wake-on-connect for idle auto-sleep (shipped v0.2.0-beta.8) + +A sentinel [optional] component holds advertised ports while a server is asleep and wakes +it on a genuine connection attempt. Opt-in per server via `spec.idle.wakeOnConnect` +(default false), with per-port protocol awareness to avoid corrupting handshakes. + +**Design (as implemented):** + +- New optional component: `sentinel/` (distroless Docker image, configured via + `operator.sentinelImage`). While a GameServer is armed (`spec.idle.wakeOnConnect=true`) + and asleep, the operator runs it as a 1-replica Deployment `-waker`. +- The sentinel holds the game's advertised ports (read from `spec.networking` + and `GamePort.advertise`) and switches traffic between the game pod and itself + via Service endpoint surgery: when asleep, the Service points to the sentinel; + when waking, it points back to the game pod (via a `-game-direct` ClusterIP + Service the game pod advertises to). +- New shared module: `gameproto/` for Minecraft and Terraria real handshake + parsing (`Consumed` field lets callers reconstruct the client stream for lossless + replay). Every other game uses `generic` — a packets-in-window heuristic. +- New CRD fields: `GameServer.spec.idle.wakeOnConnect` (bool, default false) and + `GamePort.wakeProtocol` (enum: `minecraft|terraria|generic|none`, default `generic`). +- Modules: `minecraft-java` and `terraria` declare their parser. +- Server-list pings are answered in place without waking (parsing distinguishes + a join from a status query); the player's client gets a protocol-native + "waking up, try again" message if the game misses the deadline (25s default). +- UDP-only games (Valheim, Factorio, etc.) hold no connection, so they use the + generic heuristic and wake-and-drop — the client retries. +- Hostport mode is deliberately asymmetric: the sentinel cannot hold the host port + the game pod needs to schedule, so on wake it bounces held clients and exits. + Service-backed modes (ClusterIP/NodePort/LoadBalancer) proxy through until Ready. +- Costs one small pod per sleeping server, which is why it is opt-in. + +**Honest limitations:** Only Minecraft and Terraria get real parsing; tModLoader +also declares the Terraria parser. The other 26 of the 29 catalog modules use the +`generic` default (they hold no connection to parse), and hostport is asymmetric as described. + +#### Read-only MCP server (PR #105) (shipped v0.2.0-beta.6) + +An [MCP](https://modelcontextprotocol.io) server letting an AI assistant read +current cluster state and *propose* fixes — strictly read-only, no writes. + +A new optional component [optional] (distroless Docker image, Helm toggle) exposing only +`List` / `Get` / `Watch` over the Gameplane CRDs plus Pods, Events, and pod logs. +"Propose a fix" returns suggested YAML or `kubectl` invocations as text — no +create/update/delete/patch tool exists. See the [MCP server README](https://github.com/GameplanePanel/Gameplane/blob/master/mcp-server/README.md). + +#### Module signing: active for official bundles (ECDSA P-256, Rekor-logged) (shipped v0.2.0-beta.8) + +The keyed-cosign signing mechanism is implemented and e2e-proven, and +`ModuleSource.spec.verify` can require a valid signature. It is now **active** +for official bundles with Sigstore Rekor transparency logging: `cosign.pub` +(ECDSA P-256) is committed under `signing/` (and baked into the chart for +module verification), and the Helm chart is signed for the first time. +`publish-edge` signs the rolling images, `release` signs the tagged images, +the chart, and the official bundles, and `republish-modules` re-signs bundles +out of band — all by digest with the provisioned `COSIGN_PRIVATE_KEY`, all +recording their signatures in the public Rekor transparency log, and all +fail-closed when the key is absent. The operator's verify path remains +offline/keyed, preserving air-gapped functionality. See +[Signing official bundles](./module-authoring/). + +#### Hermetic module images (gameplane-module#35, docs in #178) (shipped v0.2.0-beta.8) + +Every shipped module's default image is now pinned by digest, so a server +binary can no longer change underneath a user on pod restart with no version +bump or changelog. This was not hypothetical: `terraria-latest` moved from +Terraria 1.4.4.9 to 1.4.5.6, changing the network protocol version and +breaking the e2e Terraria bot. + +Eight games also gained a real `spec.versions` list, so a floating tag now +survives only where drift is the user's explicit, labelled choice. The +module repo's `validate.py` enforces the rule (`spec.image` and any +`default: true` entry are an error if unpinned, with a `# gameplane:floating` +opt-out), and a monthly workflow refreshes the pins. Authoring rules live in +[Pinning images by digest](./module-authoring/). + +--- + +## In progress + +Status as of 2026-10-14. Task counts come from each spec's `tasks.md`. + +- **Spec 002, Nuclear Option module and load-balancer IP pool override** (`specs/002-nuclear-option-ip-pool/`): 136 of 143 tasks done. Blocked: the server does not bind UDP 7777, so no join client can be built until a real-client packet capture documents the handshake (maintainer decision, 2026-10-11). Unblocked by: that packet capture. The join test, its bucket and the coverage row wait on it. +- **Spec 009, code scanning remediation and Dependabot** (`specs/009-remediate-security-dependabot/`): 80 of 82 tasks done. Blocked: TypeScript 7 is blocked because the `@typescript-eslint` peer range stops before TypeScript 7, and ESLint 10 is blocked because `eslint-plugin-react` does not accept `^10`. Unblocked by: a `@typescript-eslint` release that accepts TypeScript 7 (then T055/T056 and PR #272), and an `eslint-plugin-react` release that accepts `^10` (then PR #386, and #387 if open). +- **Spec 013, expand test coverage** (`specs/013-expand-test-coverage/`): 39 of 62 tasks done. No external blocker is named. Open work is the live web e2e specs, the optional-components e2e, the Postgres e2e, docs and checks, and the archive step. Some tasks wait for the first green CI run of their job, and the archive waits until every PR is merged. Open PRs for this spec are in progress. +- **Spec 019, app localization and community language packs** (`specs/019-localization-language-packs/`): 0 of 105 tasks checked; the four design decisions are settled. The implementation is on open PR #668 and is not yet on `master`. Unblocked by: merging PR #668, which needs human approval. The first step is the `i18n/` module and checker. +- **Spec 021, edit game configuration from server Settings** (`specs/021-settings-game-config/`): implemented, 20 of 24 tasks done, pending CI and review. Blocked: CI must go green and a human must approve the PR. Unblocked by: that approval and merge, then archiving to `done_021`. +- **Spec 022, default telemetry destination, extended telemetry and telemetry dashboard** (`specs/022-default-telemetry-dashboard/`): 109 of 119 tasks done. The shipped feature is unchanged until the version-trend amendment (2026-10-14, T101 to T110) lands. Blocked: T104 needs Pencil design work on the machine where Pencil runs; T109 needs the user's sign-off before editing existing tests `lifecycle_test.go:11` and `charts_test.go:83`; T110 waits for the PR to merge. Unblocked by: the design work, that sign-off, and the merge. +- **Spec 023, change-based test selection** (`specs/023-change-based-test-selection/`): 0 of 52 tasks done; no open decisions remain. No blocker is named. T001 creates the `ci: full-run` label. T052 needs 30 merged PRs to measure runner minutes. +- **Spec 023, standalone panel and API** (`specs/023-standalone-panel/`, see [standalone panel](https://github.com/GameplanePanel/Gameplane/blob/master/docs/standalone-panel.md)): the core behaviour is listed under Unreleased in the [changelog](https://github.com/GameplanePanel/Gameplane/blob/master/CHANGELOG.md). The spec has no `tasks.md`, so the remaining work is not tracked. Unblocked by: writing `tasks.md`. +- **Spec 024, documentation refresh, feature catalog and roadmap status** (`specs/024-docs-feature-list-refresh/`): in progress: the catalog, roadmap and sync check are drafted; the website and main repo PRs are next. No blocker is named. + +--- + +## Blocking v1 + +Nothing hard-blocks v1 anymore. What stands between v0.3 and a v1 GA is the +production-readiness hardening below — tracked items, not code gaps. + +--- + +## Wanted for v1, not blocking + +### Production-readiness hardening (planned) + +- A documented backup/restore **drill** — a runbook an operator can follow. + The *coverage* half of this item is already done and was stale here: + `TestRestore_RoundTrip` (`test/e2e/restore_e2e_test.go`) writes a marker into + a server's PVC, backs it up, wipes it, restores, and asserts the bytes came + back — against the real in-cluster restic-server that `ensureResticRepo` + provisions. What is missing is the human-facing runbook, not the test. +- Resource-limit guidance sized from real workloads rather than defaults. + +### Postgres driver: production readiness (experimental) + +SQLite is the only production-tested driver. The Postgres driver (build tag +`-tags postgres`) now works end to end (#518): migrations 001–012 have +hand-written Postgres equivalents (`api/internal/db/migrations/postgres/`), +every later migration is one portable file both drivers run +(`migrations/common/`), the Postgres connection rewrites `?` placeholders to +`$n`, and runtime timestamps are generated in Go. The `api (postgres)` CI job +builds the api with the tag and runs `api/internal/db`'s tests against a real +PostgreSQL server. It stays **experimental** until the rest lands: running the +handler/auth/audit test suites and the kind e2e and upgrade suites against +Postgres, a published image built with `-tags postgres`, and multi-replica +safety (the user-management lock and the audit hash chain assume a single API +process). + +--- + +## Known gaps tracked for completion + +### Users page: service accounts and identity-provider tabs (planned, v1.1) + +The Users page has two placeholder tabs (`web/src/routes/Users.tsx`, +`ServiceAccountsTab` and `IdpTab`). **Service accounts** (machine-to-machine +API tokens) don't exist yet and are tracked for v1.1. **Identity providers** +has no controls of its own: OIDC providers are already managed under Admin +Settings → Authentication (see [OIDC provider setup](https://github.com/GameplanePanel/Gameplane/blob/master/docs/oidc.md)), or through +the `api.oidc.*` Helm values. The tab's own UI is tracked for v1.1. + +### Game module template specifications (planned) + +Constitution IV requires a `specs.md` file per game module documenting the +template's authoring and configuration — the game module itself, not its +join-protocol wire format. Those specification files belong in the +`gameplane-module` submodule repo (e.g., `modules/minecraft-java/specs.md`), +are tracked there in the module repository rather than in this main repo, and +are a known incomplete item for v1. As of 2026-10-14, 26 of the 29 modules have +a `specs.md`; `enshrouded`, `minecraft-java` and `v-rising` do not yet. See the +module submodule's project board for status. + +--- + + + +--- + +## Game server join protocol coverage + +Every Gameplane-shipped game module now has a recorded, verified coverage +status for its join-protocol E2E testing. See [`docs/game-coverage.md`](https://github.com/GameplanePanel/Gameplane/blob/master/docs/game-coverage.md) for the +canonical per-module status: + +- **2 modules** have real join coverage in CI (`minecraft-java`, `terraria`). +- **25 modules** are blocked on undocumented or partially-documented + wire-protocol formats, each with a named unblocking artifact (packet capture, + reverse-engineering session, or anti-cheat analysis). They are candidates for + future protocol work once documentation becomes available. +- **2 modules** are permanently out-of-scope-by-design due to architectural + constraints (`valheim` routes through Steam Datagram Relay; + `dayz` requires BattlEye anti-cheat validation before join completion). + +Total: 29 modules. From a4aa6151f7395d5f13d0b765df8bb459dbcc9d77 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 21:39:56 +0000 Subject: [PATCH 2/4] docs: set v0.3.0 as the current release in docs pages Version pins, template count (29), CRD count (9), telemetry default and availability wording now match the released v0.3.0. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- src/config.ts | 2 +- src/content/docs/air-gapped-installation.mdx | 28 +++++++++---------- src/content/docs/api-crds.mdx | 4 +-- .../docs/audit-observability-admin.mdx | 4 +-- src/content/docs/cluster-nodes-kubeconfig.mdx | 2 +- src/content/docs/cluster-storage.mdx | 4 +-- src/content/docs/comparison.mdx | 4 +-- src/content/docs/faq.mdx | 2 +- .../docs/gameserver-template-schema.mdx | 4 +-- src/content/docs/getting-started.mdx | 2 +- src/content/docs/helm-values-reference.mdx | 10 +++---- src/content/docs/installation.mdx | 16 +++++------ .../docs/module-authoring-quickstart.mdx | 8 +++--- src/content/docs/modules-sources.mdx | 6 ++-- src/content/docs/multi-cluster.mdx | 4 +-- src/content/docs/ownership-danger-zone.mdx | 2 +- .../docs/platform-disaster-recovery.mdx | 4 +-- src/content/docs/production-installation.mdx | 6 ++-- src/content/docs/remote-agent-gateway.mdx | 4 +-- src/content/docs/repository-components.mdx | 2 +- .../docs/supported-versions-matrix.mdx | 4 +-- src/content/docs/upgrades-migrations.mdx | 8 +++--- src/content/docs/users-auth-rbac.mdx | 4 +-- 23 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/config.ts b/src/config.ts index 4067f26..e3326e3 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,4 +9,4 @@ export const SITE = CUSTOM_DOMAIN ?? "https://gameplanepanel.github.io"; export const BASE = CUSTOM_DOMAIN ? "/" : "/website"; export const GITHUB_URL = "https://github.com/GameplanePanel/Gameplane"; -export const VERSION = "v0.2.0-beta.8"; +export const VERSION = "v0.3.0"; diff --git a/src/content/docs/air-gapped-installation.mdx b/src/content/docs/air-gapped-installation.mdx index 39e5681..4d031b0 100644 --- a/src/content/docs/air-gapped-installation.mdx +++ b/src/content/docs/air-gapped-installation.mdx @@ -78,11 +78,11 @@ Every image and the chart are signed with cosign. Before mirroring, verify the s ```sh # Verify operator image cosign verify --key cosign.pub \ - ghcr.io/valgulnecron/gameplane/operator:0.2.0-beta.8 + ghcr.io/valgulnecron/gameplane/operator:0.3.0 # Verify chart cosign verify --key cosign.pub \ - ghcr.io/valgulnecron/charts/gameplane:0.2.0-beta.8 + ghcr.io/valgulnecron/charts/gameplane:0.3.0 # Game modules are signed the same way cosign verify --key cosign.pub \ @@ -98,20 +98,20 @@ Use `crane` (Google's OCI tool) or your registry vendor's mirror command to copy ```sh # Mirror operator image to private registry crane copy \ - ghcr.io/valgulnecron/gameplane/operator:0.2.0-beta.8 \ - registry.internal.corp/gameplane/operator:0.2.0-beta.8 + ghcr.io/valgulnecron/gameplane/operator:0.3.0 \ + registry.internal.corp/gameplane/operator:0.3.0 # Mirror Helm chart crane copy \ - ghcr.io/valgulnecron/charts/gameplane:0.2.0-beta.8 \ - registry.internal.corp/gameplane/charts-gameplane:0.2.0-beta.8 + ghcr.io/valgulnecron/charts/gameplane:0.3.0 \ + registry.internal.corp/gameplane/charts-gameplane:0.3.0 ``` Mirrors must preserve the digest — verify the copied artifacts have the same digest as the source: ```sh -crane digest ghcr.io/valgulnecron/gameplane/operator:0.2.0-beta.8 -crane digest registry.internal.corp/gameplane/operator:0.2.0-beta.8 +crane digest ghcr.io/valgulnecron/gameplane/operator:0.3.0 +crane digest registry.internal.corp/gameplane/operator:0.3.0 # Both must print the same sha256:... ``` @@ -190,7 +190,7 @@ Configure Helm to use it: ```sh helm upgrade --install gameplane oci://registry.internal.corp/gameplane/charts-gameplane \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --namespace gameplane-system --create-namespace \ --set image.pullSecrets[0].name=registry-creds ``` @@ -203,18 +203,18 @@ For every image in the chart values, rewrite the registry hostname but **never c # Default image: registry: ghcr.io/valgulnecron - tag: "0.2.0-beta.8" + tag: "0.3.0" # Rewritten for internal registry (same tag, different registry) image: registry: registry.internal.corp/gameplane - tag: "0.2.0-beta.8" + tag: "0.3.0" # Override optional image pulls operator: configInitImage: registry.internal.corp/busybox # instead of busybox resticImage: registry.internal.corp/restic:latest # instead of restic/restic - sentinelImage: registry.internal.corp/gameplane/sentinel:0.2.0-beta.8 + sentinelImage: registry.internal.corp/gameplane/sentinel:0.3.0 # Mirror the CRD-apply hook's kubectl image (needed at upgrade time and on # an install over leftover CRDs) @@ -246,7 +246,7 @@ Before disconnecting from the public internet, render the final manifest to conf ```sh helm template gameplane oci://registry.internal.corp/gameplane/charts-gameplane \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --namespace gameplane-system \ -f values-offline.yaml \ > manifests.yaml @@ -264,7 +264,7 @@ Apply the rendered manifest or use Helm with your internal registry: ```sh helm upgrade --install gameplane oci://registry.internal.corp/gameplane/charts-gameplane \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --namespace gameplane-system --create-namespace \ -f values-offline.yaml ``` diff --git a/src/content/docs/api-crds.mdx b/src/content/docs/api-crds.mdx index 9698c3e..9e311ea 100644 --- a/src/content/docs/api-crds.mdx +++ b/src/content/docs/api-crds.mdx @@ -22,8 +22,8 @@ import DocsQuickReference from "../../components/docs/DocsQuickReference.astro"; GameServer, GameTemplate, Module, ModuleSource, Backup, BackupSchedule, Cluster, and Restore encode the platform's declarative contracts. These eight resources form the core API surface. - -NetworkCapture, the ninth core CRD (packet capture), ships in v0.3.0 and is not available in beta.8. + +NetworkCapture, the ninth core CRD (packet capture), is available since v0.3.0. Telemetry. When enabled, the telemetry-receiver collects anonymous cluster usage (server counts, resource requests, uptime) but does not capture game data, player information, or audit events. Audit telemetry settings in Platform Settings so all cluster operators are aware of what is being transmitted. ## Notifications and platform settings @@ -71,4 +71,4 @@ Each sink is tested independently via the Dashboard form before saving. The API - [Production Observability](../production-observability/) — Prometheus, dashboards, and fleet-wide metrics - [Metrics, Alerts & Dashboards](../metrics-alerts-dashboards/) — Scraping, alerting rules, and Grafana sinks - [Notification Sinks](../notification-sinks/) — Configuring webhooks, ntfy, Slack, and SMTP -- [Platform Settings & Telemetry](../platform-settings-telemetry/) — Instance identity, update channels, and opt-in telemetry +- [Platform Settings & Telemetry](../platform-settings-telemetry/) — Instance identity, update channels, and telemetry settings diff --git a/src/content/docs/cluster-nodes-kubeconfig.mdx b/src/content/docs/cluster-nodes-kubeconfig.mdx index 7280299..c0bc918 100644 --- a/src/content/docs/cluster-nodes-kubeconfig.mdx +++ b/src/content/docs/cluster-nodes-kubeconfig.mdx @@ -100,7 +100,7 @@ Then redeploy: ```bash helm upgrade gameplane oci://ghcr.io/valgulnecron/charts/gameplane \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --set clusterOps.enabled=true ``` diff --git a/src/content/docs/cluster-storage.mdx b/src/content/docs/cluster-storage.mdx index 67af590..8900e58 100644 --- a/src/content/docs/cluster-storage.mdx +++ b/src/content/docs/cluster-storage.mdx @@ -50,8 +50,8 @@ Match access modes, reclaim policy, expansion, topology, and backup strategy to - **Use a default StorageClass or select one explicitly during creation.** Select a StorageClass explicitly per server or template via `spec.storage.storageClassName`; if none is set, the cluster's default StorageClass is used. Verify one exists and matches your needs (e.g., SSD for high-IOPS games, networked storage for multi-pod backups). - - An install-time Helm default (`operator.gameDataStorage.storageClassName`) is coming in v0.3.0 and is not yet available in beta.8. + + An install-time Helm default (`operator.gameDataStorage.storageClassName`) is available since v0.3.0. - **Confirm `allowVolumeExpansion` before increasing a server PVC.** Game worlds grow; if you plan to increase PVC size later, ensure the StorageClass allows expansion. Check with `kubectl get storageclass -o wide` — the `ALLOWVOLUMEEXPANSION` column should be `true`. You can edit a GameServer's `spec.storage.size` to trigger a resize (the Kubernetes CSI driver and underlying storage backend must support it). - **Understand whether deletion retains or removes the underlying volume.** StorageClass `reclaimPolicy` is `Delete` (volume deleted on PVC deletion) or `Retain` (volume kept for manual recovery). For production game servers, consider `Retain` to preserve world data even if a GameServer CRD is deleted. Consult your storage provider's documentation on reclaim semantics. diff --git a/src/content/docs/comparison.mdx b/src/content/docs/comparison.mdx index c49d7f4..a3e9550 100644 --- a/src/content/docs/comparison.mdx +++ b/src/content/docs/comparison.mdx @@ -11,12 +11,12 @@ Pterodactyl and CubeCoders AMP are control panels; Agones is a Kubernetes operat | Dimension | Gameplane | Pterodactyl | CubeCoders AMP | Agones | | --- | --- | --- | --- | --- | -| Deployment/runtime model | Kubernetes-native CRDs and controller-runtime operator; scales from k3s homelab to multi-node clusters. [BETA] | Self-hosted Panel with PHP/MySQL/Redis dependencies; Wings backend manages Docker containers. | Web-based control panel supporting Windows (native) and Linux (Debian 10+). | Kubernetes-native library extending K8s with GameServer/Fleet CRDs. | +| Deployment/runtime model | Kubernetes-native CRDs and controller-runtime operator; scales from k3s homelab to multi-node clusters. | Self-hosted Panel with PHP/MySQL/Redis dependencies; Wings backend manages Docker containers. | Web-based control panel supporting Windows (native) and Linux (Debian 10+). | Kubernetes-native library extending K8s with GameServer/Fleet CRDs. | | Scaling & auto-sleep | Opt-in idle auto-sleep with configurable wake windows, manual wake button, or wake-on-connect. Minecraft/Terraria full protocol support; others use packet heuristics. [optional] | Multi-node support with cron-based power scheduling; no dedicated idle/auto-sleep feature. | Instance Automatic Sleep feature; multi-server architecture with controller managing instances. | Fleet autoscaling via buffer/webhook strategies; no idle/sleep state. | | Inbound connectivity (NAT traversal, relay) | Integrated frp, Tailscale, playit relays (a separate tunnel pod per server); playit mappings user-managed via playit.gg account. [optional; disabled by default] | No integrated relay sidecars; manual proxy/port forwarding configuration required. | not publicly documented (checked 2026-09-02) | No relay or NAT traversal features documented. | | Backup and restore | Restic snapshots to S3-compatible storage; on-demand or cron-scheduled via BackupSchedule; one-click restore. | Wings (local, default) or S3-compatible backup drivers; cron scheduling and on-demand backups. | not publicly documented (checked 2026-09-02) | not applicable (Agones is a Kubernetes operator library) | | Access control & authentication | Local argon2id + OIDC (Keycloak/Google/GitHub); three built-in roles (admin/operator/viewer); custom roles supported. | 2FA configurable per account or admin-only; subuser management via Artisan CLI. | Role-based access control; OIDC single-sign-on in Advanced Edition. | not applicable (Agones is a Kubernetes operator library) | -| Game template distribution | OCI bundles via ModuleSource (git/http/oci/local/upload); optional cosign signature verification per source. 30 ready-to-use templates on master (16 in v0.2.0-beta.8; the other 14 arrive in v0.3.0). | Community eggs repository (eggs.pterodactyl.io) with nests and custom egg creation support. | Customizable templates framework; community-contributed templates available via external repositories. | not applicable (Agones is a Kubernetes operator library) | +| Game template distribution | OCI bundles via ModuleSource (git/http/oci/local/upload); optional cosign signature verification per source. 29 ready-to-use templates on master (16 in v0.2.0-beta.8; 13 arrive in v0.3.0; Hell Let Loose withdrawn). | Community eggs repository (eggs.pterodactyl.io) with nests and custom egg creation support. | Customizable templates framework; community-contributed templates available via external repositories. | not applicable (Agones is a Kubernetes operator library) | | Multi-tenancy & multi-cluster | Cluster CRD for remote registration and health checks; in v0.2.0-beta.8 console/log streaming is local-cluster only. From v0.3.0: remote Pod logs/PTY, an optional private gateway for console, files, players, mods and UID-bound capture downloads/cleanup, modpack and ID-list configuration on the selected cluster, and a unified dashboard with location filters. Requires matching gateway, operator, agent and capture-sidecar versions. | Single Panel managing multiple nodes; no documented remote cluster or cross-cluster streaming. | Multi-server management via controller architecture; multi-tenancy not supported in AMP 2 (planned for AMP 3). | Multi-cluster allocation via GameServerAllocationPolicy; allocator service with mTLS authentication. | | Licensing | GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). | MIT License (Panel and Wings). | Proprietary; per-instance tiers (Standard/Professional/Advanced/Enterprise). | Apache License 2.0. | | Target operator scope (self-hosted vs. managed SaaS) | Self-hosted only; runs on Kubernetes (k3s, kubeadm, managed services); no managed SaaS offering. | Self-hosted only; requires Linux system capable of running Docker containers. | Self-installed on user hardware (Windows or Linux); no managed SaaS version. | Self-hosted operator software; runs anywhere Kubernetes can run. | diff --git a/src/content/docs/faq.mdx b/src/content/docs/faq.mdx index dc3a73f..a16e204 100644 --- a/src/content/docs/faq.mdx +++ b/src/content/docs/faq.mdx @@ -35,7 +35,7 @@ import Icon from "../../components/Icon.astro";
- It's in beta ({VERSION}). Core workflows are feature-complete and tested, but not yet + It's a pre-v1 release ({VERSION}). Core workflows are feature-complete and tested, but not yet recommended for unattended production — see the Roadmap.
diff --git a/src/content/docs/gameserver-template-schema.mdx b/src/content/docs/gameserver-template-schema.mdx index fd78edb..64a4d85 100644 --- a/src/content/docs/gameserver-template-schema.mdx +++ b/src/content/docs/gameserver-template-schema.mdx @@ -185,8 +185,8 @@ When `spec.idle.enabled` is true, the operator scales the server down once it re | `wakeWindows` | []string | (none) | Cron expressions (cluster timezone) at which a sleeping server wakes up. Max 8 entries. | | `wakeOnConnect` | bool | false | Arms the wake sentinel: while asleep, a small pod holds the advertised ports and wakes the server on a genuine join attempt. | - -`spec.capture` / `status.capture` and the packet-capture sidecar are not yet available in v0.2.0-beta.8; they ship in the upcoming v0.3.0 release. + +`spec.capture` / `status.capture` and the packet-capture sidecar are available since v0.3.0. ## Capture configuration diff --git a/src/content/docs/getting-started.mdx b/src/content/docs/getting-started.mdx index 54e1c92..3118aed 100644 --- a/src/content/docs/getting-started.mdx +++ b/src/content/docs/getting-started.mdx @@ -24,7 +24,7 @@ Releases up to and including v0.3.0 are published under `ghcr.io/valgulnecron`, ```sh helm upgrade --install gameplane \ oci://ghcr.io/valgulnecron/charts/gameplane \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --namespace gameplane-system --create-namespace ``` diff --git a/src/content/docs/helm-values-reference.mdx b/src/content/docs/helm-values-reference.mdx index 9f47c00..2c56cd1 100644 --- a/src/content/docs/helm-values-reference.mdx +++ b/src/content/docs/helm-values-reference.mdx @@ -65,8 +65,8 @@ Configure local accounts and OIDC single sign-on. Local password-based accounts | `api.oidc.clientSecretRef` | object | `{name: gameplane-oidc, key: clientSecret}` | Reference to a Kubernetes Secret holding the OAuth client secret. Create the Secret first: `kubectl create secret generic gameplane-oidc --from-literal=clientSecret=`. | | `api.oidc.redirectURL` | string | *(empty)* | Explicit OAuth redirect URL. When empty, derived from `ingress.host` (e.g., `https://gameplane.local/auth/oidc/callback`). Override only if your ingress URL differs from the redirect URL your OIDC provider expects. | - -The following OIDC fields enable install-time role mapping and customization of the login UI. They are not available in v0.2.0-beta.8 — upgrade to v0.3.0 to use them. + +The following OIDC fields enable install-time role mapping and customization of the login UI. They are available since v0.3.0. | Key | Type | Default | Description | |---|---|---|---| @@ -116,7 +116,7 @@ Configure data persistence, audit logging, and telemetry. | `api.db.dsn` | string | `file:/data/gameplane.db?_pragma=journal_mode(WAL)` | Database connection string. SQLite path (only when `driver: sqlite`). For PostgreSQL, use a connection string like `postgres://gameplane:***@postgres/gameplane?sslmode=require`. | | `api.storage.size` | string | `2Gi` | Size of the SQLite PersistentVolumeClaim (only when `db.driver: sqlite`). Adjust based on audit log retention and historical data. | | `api.storage.storageClassName` | string | *(empty)* | Storage class for the SQLite PVC. When empty, uses the cluster's default storage class. | -| `api.storage.existingClaim` | string | *(empty)* | **Coming in v0.3.0** — Use an existing PersistentVolumeClaim instead of creating one. Leave empty to create a new PVC. When migrating, ensure the existing claim has the `helm.sh/resource-policy: keep` annotation. | +| `api.storage.existingClaim` | string | *(empty)* | **Available since v0.3.0** — Use an existing PersistentVolumeClaim instead of creating one. Leave empty to create a new PVC. When migrating, ensure the existing claim has the `helm.sh/resource-policy: keep` annotation. | | `api.audit.retentionDays` | integer | `0` | Audit event retention in days. `0` keeps all events indefinitely; set a positive number to prune older records daily. | | `api.audit.webhook.url` | string | *(empty)* | Outbound webhook URL for audit events. The API POSTs each event as JSON (best-effort, non-blocking). Point it at a log aggregator, SIEM, or the bundled `audit-syslog-bridge`. | @@ -165,8 +165,8 @@ Configure default-deny policies for game pods and backups. | `networkPolicies.gameIngress.fromCIDRs` | list | `["0.0.0.0/0"]` | CIDR ranges allowed to reach game ports. Set to a LAN range (e.g., `["192.168.1.0/24"]`) to restrict access. Cannot be an empty list; set `enabled: false` instead. | | `networkPolicies.apiServerCIDRs` | list | `[]` (falls back to RFC 1918 + link-local) | CIDRs holding the kube-apiserver endpoints the agent sidecar reaches for its status heartbeat, on TCP 443 and 6443. Set it to narrow that egress to your API endpoints, or when they sit outside those ranges. | - -These network capture values are not available in v0.2.0-beta.8. + +These network capture values are available since v0.3.0. | Key | Type | Default | Description | |---|---|---|---| diff --git a/src/content/docs/installation.mdx b/src/content/docs/installation.mdx index e9d8e19..99bf18b 100644 --- a/src/content/docs/installation.mdx +++ b/src/content/docs/installation.mdx @@ -157,7 +157,7 @@ networkPolicies: ### Module sources and catalog -By default, Gameplane ships with the official game catalog (16 modules in v0.2.0, 30 in v0.3.0): +By default, Gameplane ships with the official game catalog (16 modules in v0.2.0, 29 in v0.3.0): ```yaml defaultModuleSource: @@ -181,11 +181,11 @@ Deploy the pinned OCI chart, bootstrap the first administrator, then validate po ### Step 1: Install the Helm chart -Install a tagged release straight from the GitHub Container Registry (GHCR). Replace `` with a release, e.g., `0.2.0-beta.8`: +Install a tagged release straight from the GitHub Container Registry (GHCR). Replace `` with a release, e.g., `0.3.0`: ```bash helm upgrade --install gameplane oci://ghcr.io/valgulnecron/charts/gameplane \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --namespace gameplane-system --create-namespace \ --values values.override.yaml ``` @@ -240,8 +240,8 @@ modulesources.gameplane.local restores.gameplane.local ``` - - NetworkCapture (packet capture for protocol debugging) will be the 9th CRD, arriving in v0.3.0-rc.1. + + NetworkCapture (packet capture for protocol debugging) is the 9th CRD, available since v0.3.0. ### Step 4: Access the dashboard @@ -260,7 +260,7 @@ Create a simple test GameServer to verify the operator is reconciling correctly: / ]} /> - - The `gp-module init` CLI scaffolds modules with archetype templates (`steamcmd`, `java`, `generic`) and live DNS-1123 validation. For beta.8, create files manually or adapt an existing module from the submodule's `modules/` directory. + + The `gp-module init` CLI scaffolds modules with archetype templates (`steamcmd`, `java`, `generic`) and live DNS-1123 validation. On v0.2.0-beta.8 and earlier, create files manually or adapt an existing module from the submodule's `modules/` directory. ### Example module.yaml @@ -141,8 +141,8 @@ bin/gp-module validate modules/minecraft-java --strict This checks metadata syntax, CRD schema compliance, image digests, port ranges, and configuration types. - - The `gp-module validate` tool provides instant offline linting with source-line diagnostics. For beta.8, review your YAML files against the [GameTemplate schema](../gametemplate-schema/) and [module.yaml spec](../module-authoring/) manually. + + The `gp-module validate` tool provides instant offline linting with source-line diagnostics. On v0.2.0-beta.8 and earlier, review your YAML files against the [GameTemplate schema](../gametemplate-schema/) and [module.yaml spec](../module-authoring/) manually. ### 2. Push to local registry diff --git a/src/content/docs/modules-sources.mdx b/src/content/docs/modules-sources.mdx index 1e9945f..b5f8772 100644 --- a/src/content/docs/modules-sources.mdx +++ b/src/content/docs/modules-sources.mdx @@ -84,8 +84,8 @@ Disable the default if you manage ModuleSource resources via GitOps, or create a ## Author and publish modules - -Module authoring features (`gp-module` CLI, web Module Builder, and related APIs) will be available in v0.3.0. For v0.2.0, import pre-built modules from official registries or upload bundles directly. + +Module authoring features (`gp-module` CLI, web Module Builder, and related APIs) are available since v0.3.0. For v0.2.0, import pre-built modules from official registries or upload bundles directly. Package metadata, templates, assets, and compatibility as versioned OCI content with a reproducible release process. @@ -99,7 +99,7 @@ Package metadata, templates, assets, and compatibility as versioned OCI content ]} /> -In v0.3.0, Gameplane will ship a unified toolkit for authoring and publishing: +Since v0.3.0, Gameplane ships a unified toolkit for authoring and publishing: - **`gp-module` CLI** — scaffold, validate offline, preview runtime config, and package modules for distribution. - **Web Dashboard Module Builder** — a visual 3-step wizard for building modules directly in the cluster. diff --git a/src/content/docs/multi-cluster.mdx b/src/content/docs/multi-cluster.mdx index c5c2fa8..fce36c5 100644 --- a/src/content/docs/multi-cluster.mdx +++ b/src/content/docs/multi-cluster.mdx @@ -19,8 +19,8 @@ import DocsQuickReference from "../../components/docs/DocsQuickReference.astro"; Share policy through GitOps and SSO; do not share live databases, controller state, or repository credentials across boundaries. - - The optional agent gateway and the unified cross-cluster dashboard described below arrive in v0.3.0. In v0.2.0-beta.8 you can register clusters and manage their resources from one dashboard, but console and log streaming is scoped to the local control-plane cluster. + + The optional agent gateway and the unified cross-cluster dashboard described below are available since v0.3.0. In v0.2.0-beta.8 you can register clusters and manage their resources from one dashboard, but console and log streaming is scoped to the local control-plane cluster. ## Manage independent clusters from one dashboard diff --git a/src/content/docs/ownership-danger-zone.mdx b/src/content/docs/ownership-danger-zone.mdx index c024bf7..331f3a3 100644 --- a/src/content/docs/ownership-danger-zone.mdx +++ b/src/content/docs/ownership-danger-zone.mdx @@ -14,7 +14,7 @@ import DocsCallout from "../../components/docs/DocsCallout.astro"; import DocsSectionList from "../../components/docs/DocsSectionList.astro"; import DocsQuickReference from "../../components/docs/DocsQuickReference.astro"; - + Ownership, collaborators, transfer, wipe, and delete are available in v0.2.0-beta.8, where operator-role users can also run them on servers they don't own. From v0.3.0, transferring ownership, editing collaborators, wiping data and deleting a server need the server's owner or an admin. Servers with no recorded owner (for example created with kubectl or GitOps) can then be transferred, wiped or deleted only by an admin. diff --git a/src/content/docs/platform-disaster-recovery.mdx b/src/content/docs/platform-disaster-recovery.mdx index 6872216..95c3714 100644 --- a/src/content/docs/platform-disaster-recovery.mdx +++ b/src/content/docs/platform-disaster-recovery.mdx @@ -47,7 +47,7 @@ Capture every versioned artifact, platform state source, credential, trust root, A disaster recovery manifest should document and preserve: -- **Release and configuration:** Gameplane version (e.g., `v0.2.0-beta.8`), Helm values (including `api.db.driver`, ingress hostname, OIDC settings, storage class defaults), cluster Kubernetes version, and all base-image versions (restic, busybox, kubectl). +- **Release and configuration:** Gameplane version (e.g., `v0.3.0`), Helm values (including `api.db.driver`, ingress hostname, OIDC settings, storage class defaults), cluster Kubernetes version, and all base-image versions (restic, busybox, kubectl). - **CRD and operator state:** All GameServer, GameTemplate, Module, ModuleSource, and Cluster CRD definitions; the operator's RBAC role and ClusterRole; and the operator's audit/observability configuration. - **Platform database:** SQLite file or PostgreSQL backup dump, including all tables for users, roles, permissions, audit logs, RBAC overrides, and platform settings. - **Secrets and certificates:** All platform Secrets (backup repository credentials, OIDC client secrets, API signing keys, TLS certificates, image registry credentials, database credentials, webhook auth tokens), stored securely off-cluster with access controls. @@ -78,7 +78,7 @@ A platform-wide rebuild must follow this sequence: ```bash helm upgrade --install gameplane oci://ghcr.io/valgulnecron/charts/gameplane \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --namespace gameplane-system \ --create-namespace \ --values /path/to/recorded-values.yaml diff --git a/src/content/docs/production-installation.mdx b/src/content/docs/production-installation.mdx index f05ed5f..77c8687 100644 --- a/src/content/docs/production-installation.mdx +++ b/src/content/docs/production-installation.mdx @@ -29,7 +29,7 @@ Gameplane's Helm chart is distributed as an OCI artifact on GitHub Container Reg - **Optional component images** — `audit-syslog-bridge`, `telemetry-receiver`, `sentinel`, `tunnel-frp`, `tunnel-tailscale`, `tunnel-playit`, `mcp-server` and `capture-sidecar` — are pulled only when the optional component they belong to is enabled (and, for `sentinel` and `capture-sidecar`, only for GameServers that opt in). A default install pulls four images: `operator`, `api`, `web` and `agent`. - **GameServer agent images** are pulled per-server, on-demand, so pre-staging is not required. -Before your first production install, document and approve the release you intend to deploy: the specific chart version (e.g., `0.2.0-beta.8`) and any image tag or pull secret overrides in your values file. +Before your first production install, document and approve the release you intend to deploy: the specific chart version (e.g., `0.3.0`) and any image tag or pull secret overrides in your values file. ## Render and review @@ -81,7 +81,7 @@ Gameplane requires: - **A default StorageClass** for game-server data PVCs (any RWO CSI driver works) - **Optional: an ingress controller** (nginx-ingress by default) and cert-manager for TLS -The current stable release is **v0.2.0-beta.8**. Install by specifying the version explicitly to ensure reproducibility. +The current release is **v0.3.0** (pre-v1). Install by specifying the version explicitly to ensure reproducibility. ## Image signature verification @@ -89,7 +89,7 @@ All released images, the chart, and official game modules are signed with cosign ```sh cosign verify --key cosign.pub \ - ghcr.io/valgulnecron/gameplane/operator:0.2.0-beta.8 + ghcr.io/valgulnecron/gameplane/operator:0.3.0 ``` Pre-rotation releases (v0.2.0-beta.7 and earlier) used the retired Ed25519 key and lack transparency log entries — verify those with `cosign-legacy.pub` and `--insecure-ignore-tlog=true`. diff --git a/src/content/docs/remote-agent-gateway.mdx b/src/content/docs/remote-agent-gateway.mdx index 263fbdb..27fb500 100644 --- a/src/content/docs/remote-agent-gateway.mdx +++ b/src/content/docs/remote-agent-gateway.mdx @@ -17,8 +17,8 @@ import DocsQuickReference from "../../components/docs/DocsQuickReference.astro"; Run one central Gameplane API and dashboard, plus an operator and an optional gateway in each remote cluster. The gateway proxies approved agent operations over mTLS so the central dashboard can reach consoles, files, players and captures in clusters it does not run in. - - The agent gateway ships in v0.3.0 and is not available in v0.2.0-beta.8. + + The agent gateway is available since v0.3.0. diff --git a/src/content/docs/repository-components.mdx b/src/content/docs/repository-components.mdx index 19fee0d..ac28bb4 100644 --- a/src/content/docs/repository-components.mdx +++ b/src/content/docs/repository-components.mdx @@ -49,7 +49,7 @@ The repository joins runtime components, shared libraries, optional services, pa | Module | Purpose | |--------|---------| -| `operator/` | controller-runtime Kubernetes operator; reconciles 8 CRDs in v0.2.0-beta.8 (GameServer, GameTemplate, Cluster, Backup, BackupSchedule, Restore, Module, ModuleSource) — a 9th, NetworkCapture, is coming in v0.3.0 | +| `operator/` | controller-runtime Kubernetes operator; reconciles 9 CRDs in v0.3.0 (GameServer, GameTemplate, Cluster, Backup, BackupSchedule, Restore, Module, ModuleSource, NetworkCapture) | | `api/` | REST and WebSocket gateway; authentication, RBAC, audit logging; SQLite or PostgreSQL backend | | `agent/` | In-pod sidecar managing console (RCON/PTY), files, logs, and heartbeats | | `netguard/` | SSRF dial-guard protecting against injection attacks | diff --git a/src/content/docs/supported-versions-matrix.mdx b/src/content/docs/supported-versions-matrix.mdx index 068a407..386e953 100644 --- a/src/content/docs/supported-versions-matrix.mdx +++ b/src/content/docs/supported-versions-matrix.mdx @@ -43,8 +43,8 @@ Baseline tool versions for building, extending, and testing Gameplane. Gameplane follows semantic versioning. Beta releases (`v0.x.0-betaY`) include significant features and are suitable for testing and non-critical deployments. Stable releases (`v1.0.0+`) are production-ready with long-term support. -**Current stable release:** v0.2.0-beta.8 (latest published) -**Development release:** v0.3.0-rc.1 (tagged, not published as a release; see [Changelog](../changelog/) for v0.3.0 features) +**Current release:** v0.3.0 (latest published, pre-v1) +**Unreleased:** changes since v0.3.0 are listed under Unreleased in the [Changelog](../changelog/) Deprecation notices for upcoming major or breaking changes appear in release notes and this reference page. diff --git a/src/content/docs/upgrades-migrations.mdx b/src/content/docs/upgrades-migrations.mdx index 5bb2854..cc6fd9f 100644 --- a/src/content/docs/upgrades-migrations.mdx +++ b/src/content/docs/upgrades-migrations.mdx @@ -32,7 +32,7 @@ Read release notes and compatibility constraints. Export your current configurat { icon: "file-code", label: "Release Notes", - text: "Review the Changelog and any upgrade notes for your target version. Unreleased features marked as 'Coming in v0.3.0' require `v0.3.0-rc.1` or later.", + text: "Review the Changelog and any upgrade notes for your target version. Features marked as 'Available since v0.3.0' require `v0.3.0` or later.", }, { icon: "database", @@ -110,10 +110,10 @@ Upgrade a non-production or canary environment first. Watch the rollout, check m Once you have verified your values and backups, apply the upgrade to your cluster: ```bash -# Upgrade to a specific version (e.g., 0.2.0-beta.8) +# Upgrade to a specific version (e.g., 0.3.0) helm upgrade gameplane oci://ghcr.io/valgulnecron/charts/gameplane \ --namespace gameplane-system \ - --version 0.2.0-beta.8 \ + --version 0.3.0 \ --values gameplane-values-backup.yaml \ --wait @@ -214,7 +214,7 @@ kubectl apply --server-side -f charts/gameplane/crds/ helm install gameplane charts/gameplane -n gameplane-system --create-namespace --force-conflicts ``` - + The Helm 4 field-manager behavior and the hook-on-reinstall behavior above are part of v0.3.0. diff --git a/src/content/docs/users-auth-rbac.mdx b/src/content/docs/users-auth-rbac.mdx index 4632f4d..999646b 100644 --- a/src/content/docs/users-auth-rbac.mdx +++ b/src/content/docs/users-auth-rbac.mdx @@ -112,8 +112,8 @@ When a user logs in via OIDC for the first time, Gameplane creates a user row wi ### Install-time role mappings - - Install-time role mappings are not available in v0.2.0-beta.8. + + Install-time role mappings are available since v0.3.0. Helm role mappings eliminate the need for a `bootstrap-admin` account in OIDC-only deployments. Operators configure group mappings at install time, and the first user to log in receives the correct role immediately based on their IdP group membership. From 0af3046a84335bbca821451870a96bcabfcb91d9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 21:40:56 +0000 Subject: [PATCH 3/4] docs: add Features page mirroring FEATURES.md Same areas, capabilities, maturity and default as the main repo catalog, under Reference, Releases & Roadmap. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- src/content/docs/features.mdx | 387 ++++++++++++++++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 src/content/docs/features.mdx diff --git a/src/content/docs/features.mdx b/src/content/docs/features.mdx new file mode 100644 index 0000000..de70aaa --- /dev/null +++ b/src/content/docs/features.mdx @@ -0,0 +1,387 @@ +--- +title: Features +description: Every Gameplane capability with its maturity and default. +section: reference +group: releases-roadmap +order: 0 +icon: list +eyebrow: DOCUMENTATION +--- + +Every Gameplane capability, grouped by area. The same list lives in the main repository as [FEATURES.md](https://github.com/GameplanePanel/Gameplane/blob/master/FEATURES.md), and a CI check keeps the two in step. + +Maturity labels: **stable** (shipped, on by default, and exercised by a bucketed end-to-end test), **beta** (shipped with caveats or without a bucketed end-to-end test), **experimental** (shipped but the docs say so), **planned** (not started), **in progress** (started, not yet released). + +Default column: **on** (enabled by the chart or the product), **off** (opt-in, ships disabled), or **n/a** (planned, in progress, or tooling with no install default). + +Notification rows take effect once a notification sink is configured. + +Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what is planned and in progress. + +## Servers and lifecycle + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Create a game server from a module template | stable | on | Creates a GameServer from an installed module template through the create wizard or the API. | [create a server](./create-a-server/) | +| Start a stopped server | stable | on | Clears spec.suspend so the operator scales the pod back up. | [server operations](./server-operations/) | +| Stop a server | stable | on | Sets spec.suspend so the operator scales the pod to zero after the stop sequence. | [server operations](./server-operations/) | +| Restart a server | stable | on | Stamps a restart annotation so the pod restarts without changing desired state. | [server operations](./server-operations/) | +| Show server phase and conditions | stable | on | Shows the server phase, such as Running or Suspended, with the reason conditions behind each. | [server operations](./server-operations/) | +| Clone a server into a new GameServer | stable | on | Copies the spec of a server into a new GameServer. | [server operations](./server-operations/) | +| Switch game version on a running server | stable | on | Changes the template version of an existing server so the operator rolls it out. | [server operations](./server-operations/) | +| Delete a server | stable | on | Deletes a GameServer and its owned child objects. | [server operations](./server-operations/) | +| Transfer server ownership | beta | on | Lets the owner or an admin hand a server to another user. | [ownership danger zone](./ownership-danger-zone/) | +| Manage server collaborators | stable | on | Lets the owner set collaborator users who can use start, stop, restart, wake and clone. | [ownership danger zone](./ownership-danger-zone/) | +| Graceful stop with the game's native shutdown sequence | beta | on | Runs the template stop sequence over RCON, telnet or stdin before the pod scales to zero so world saves finish. | [server operations](./server-operations/) | +| Wipe world data with typed confirmation | beta | on | Suspends the server, erases the world volume and resumes, for owners or admins only. | [ownership danger zone](./ownership-danger-zone/) | +| Filter the server list by Running or Stopped | beta | on | Filters the server list with All, Running and Stopped tabs. | [server overview](./server-overview/) | +| List servers across all readable namespaces | beta | on | The Servers page lists servers from every namespace the viewer may read. | [server overview](./server-overview/) | +| Set an install-time default storage class for game data | beta | off | Applies the Helm default storage class to new game data volumes when neither the template nor the server names one. | - | +| Report a missing game-data storage class as PVCProvisioningFailed | stable | on | Sets the GameServer Ready condition to False with reason PVCProvisioningFailed when its storage class does not exist. | - | +| Keep game data on a PVC when the game pod is deleted | stable | on | Game data stays on its PVC when the game pod is deleted. | - | +| Edit game configuration from the Settings tab | in progress | n/a | Lets an operator change a server game configuration from its Settings tab, with validation. | [roadmap](./roadmap/) | + +## Console and admin actions + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Live console stream for PTY-mode games | stable | on | Attaches the browser to the container stdin and stdout through the pod attach API for templates with consoleMode pty. | [console events logs](./console-events-logs/) | +| Run template quick actions | stable | on | Runs template-defined admin actions such as save, broadcast, time, weather and reload from buttons. | [server operations](./server-operations/) | +| Live game log tail | stable | on | Streams the game log file over a WebSocket from the agent sidecar. | [console events logs](./console-events-logs/) | +| RCON command console | beta | on | Sends line-based commands to the game RCON protocol and shows responses as log lines. | [console protocols](./console-protocols/) | +| Pick a console protocol from the full rcon.protocol set | beta | on | A template selects one of ten console protocols for its console, including REST and CLI. | [console protocols](./console-protocols/) | +| Run a console without a password with rcon.authentication false | beta | off | Lets a console with no authentication, such as a loopback-only port, run without a password Secret. | [console protocols](./console-protocols/) | +| Console command history | beta | on | Recalls the last 100 sent commands with the arrow keys, kept only while the Console tab stays open. | [console events logs](./console-events-logs/) | +| Clear, download and fullscreen console controls | beta | on | Toolbar buttons clear the terminal, download its buffer and toggle fullscreen without stopping the stream. | [console events logs](./console-events-logs/) | +| Schema-validated action input with injection guard | beta | on | Validates action parameters against the template schema and escapes them before they reach the game console. | [console protocols](./console-protocols/) | +| Stdin action transport for PTY-only games | beta | on | Runs actions on PTY-console games by writing lines to the container stdin through pods attach. | [console protocols](./console-protocols/) | +| Kubernetes events timeline for a server | beta | on | Shows the 50 most recent Kubernetes events for the server pod and its parent objects. | [console events logs](./console-events-logs/) | +| Container startup output stream | beta | on | Streams the game container stdout through the pod log API before the game log file exists. | [console events logs](./console-events-logs/) | +| Log replay on tab open | beta | on | Replays up to the last 500 game-log lines before following new output, capped by the agent at 20,000 lines and 4 MiB. | [console events logs](./console-events-logs/) | +| Download the full game log | beta | on | Downloads the whole game log file without interrupting the live stream. | [console events logs](./console-events-logs/) | + +## Files + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Browse the exposed server filesystem | stable | on | Lists directories under the exposed data root with a breadcrumb. | [file manager](./file-manager/) | +| Save text file contents through the write endpoint | stable | on | Saves text content to a file through the agent write endpoint, which the in-browser editor uses. | [file manager](./file-manager/) | +| Create a file through the write endpoint | stable | on | Creates a new file in the open directory through the write endpoint. | [file manager](./file-manager/) | +| Download a file | stable | on | Downloads one file from the server through the agent, including large files that stream past the request timeout. | [file manager](./file-manager/) | +| Delete a file | stable | on | Removes one file through the delete endpoint after confirmation. | [file manager](./file-manager/) | +| Create a folder | beta | on | Creates a folder in the open directory through the mkdir endpoint. | [file manager](./file-manager/) | +| Upload files | beta | on | Uploads files into the open directory through the upload endpoint, writing them group-readable for the game process. | [file manager](./file-manager/) | +| Delete a folder recursively | beta | on | Removes a folder and everything inside it after confirmation, and refuses folders that hold dot-prefixed entries. | [file manager](./file-manager/) | +| Confine file access to the exposed root | beta | on | Rejects path traversal and symlink escapes outside the exposed data root. | [file manager](./file-manager/) | + +## Players + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| View online players and capacity | stable | on | Shows the online count, the maximum and the player list, refreshed every 5 seconds, for templates that declare a player source. | [player administration](./player-administration/) | +| View the whitelist and add or remove entries | beta | on | Lists whitelist entries and adds or removes names through the whitelist endpoints. | [player administration](./player-administration/) | +| Kick a player | beta | on | Disconnects an online player through the template kick command, and returns HTTP 501 when the template does not declare it. | [player administration](./player-administration/) | +| Ban and unban a player | beta | on | Adds or removes a persistent ban through the template ban and unban commands. | [player administration](./player-administration/) | +| View the banned players list | beta | on | Shows the banned players reported by the game through the banned endpoint. | [player administration](./player-administration/) | +| Steam display names on player lists | beta | off | Resolves Steam IDs to display names through the Steam Web API once a Secret is configured. | - | + +## Mods + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Install a mod from a download URL with registry metadata in the mod manifest | stable | on | Installs a mod file from a download URL and records its registry metadata in the per-volume mod manifest. | [mods modpacks](./mods-modpacks/) | +| Upgrade an installed mod in place and remove it from the manifest | stable | on | Replaces an installed mod with a new file and removes the old file and its manifest entry, or removes the mod entirely. | [mods modpacks](./mods-modpacks/) | +| Upload a mod file directly from the dashboard | stable | on | Accepts a multipart mod file upload for a server and installs it as a file-drop mod. | [mods modpacks](./mods-modpacks/) | +| Reject path-traversal and symlink-escape mod archives | stable | on | Extracts valid mod archives while rejecting zip-slip paths and symlinks that escape the target directory. | [mods modpacks](./mods-modpacks/) | +| Install mods by launch-parameter ID | beta | on | Projects selected mod IDs into the launch environment for games that fetch mods at startup. | [mods modpacks](./mods-modpacks/) | +| Browse and install from Modrinth | beta | on | Searches and installs Modrinth mods scoped to the server game version and loader, with no key needed. | [mods modpacks](./mods-modpacks/) | +| Browse and install from Thunderstore | beta | on | Searches and installs Thunderstore packages for templates that set a community, with no key needed. | [mods modpacks](./mods-modpacks/) | +| Browse and install from Hangar | beta | on | Searches and installs Hangar plugins, with no key needed. | [mods modpacks](./mods-modpacks/) | +| Browse and install from the Factorio Mod Portal | beta | on | Installs Factorio mods from the mod portal using the user's factorio.com credentials entered in the install form. | [mods modpacks](./mods-modpacks/) | +| Browse and install from SpigotMC | beta | on | Searches and installs SpigotMC resources, with no key needed. | [mods modpacks](./mods-modpacks/) | +| Browse and install from GitHub Releases | beta | on | Installs release assets from a GitHub owner and repository set on the template, with no key needed. | [mods modpacks](./mods-modpacks/) | +| Browse and install from uMod | beta | on | Searches and installs uMod plugins, with no key needed. | [mods modpacks](./mods-modpacks/) | +| Store and replace registry API keys from Settings | beta | on | Saves, replaces and removes registry keys under Settings, Mod registries, kept in Kubernetes Secrets or the standalone database. | [mod registry credentials](./mod-registry-credentials/) | +| Check installed mods for newer versions | beta | on | Reports available updates for mods installed from a provider that has a resolvable version. | [mods modpacks](./mods-modpacks/) | +| Install a modpack from a provider | beta | on | Installs a modpack either by pinning it into a server env (env-mode) or by installing its dependency mods (deps-mode). | [mods modpacks](./mods-modpacks/) | +| Browse and install from CurseForge | beta | off | Searches and installs CurseForge mods once a CurseForge API key is configured. | [mod registry credentials](./mod-registry-credentials/) | +| Browse and install from Steam Workshop | beta | off | Searches and installs Steam Workshop items once a Steam Web API key is configured. | [mod registry credentials](./mod-registry-credentials/) | +| Browse Nexus Mods | beta | off | Browses Nexus Mods once an API key is configured; downloads are not supported. | [mod registry credentials](./mod-registry-credentials/) | + +## Backups and restore + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Create an on-demand restic-snapshot backup of a server | stable | on | Starts a Backup that runs restic against the server data volume and records the snapshot ID. | [backups recovery](./backups-recovery/) | +| Connect a restic repository through a labelled Secret | stable | on | Reads the restic repository and credentials from a labelled Kubernetes Secret referenced by repoRef. | [backup destinations](./backup-destinations/) | +| Store restic backups in S3-compatible storage | beta | on | Points a restic repository at an S3-compatible endpoint through the repository URL in the labelled Secret. | [backup destinations](./backup-destinations/) | +| Report a Failed backup for a missing PVC or bad credentials | stable | on | Sets a Backup to Failed with a message when its data volume is missing or its repository credentials are rejected. | [backups recovery](./backups-recovery/) | +| Delete a backup and forget its restic snapshot with prune | stable | on | Deleting a Backup runs restic forget with prune so the snapshot is removed from the repository. | [backups recovery](./backups-recovery/) | +| Run backups on a cron schedule | stable | on | A BackupSchedule creates Backup resources on its cron expression and records last and next schedule times. | [backup restore crds](./backup-restore-crds/) | +| Suspend a backup schedule | stable | on | Setting suspend on a BackupSchedule stops it from creating new backups. | [backup restore crds](./backup-restore-crds/) | +| Trim old backups with keep-last retention | stable | on | Applies keepLast retention after each scheduled backup; an empty policy keeps everything. | [backups recovery](./backups-recovery/) | +| Forbid overlapping scheduled backups | stable | on | A schedule with concurrencyPolicy Forbid does not start a new backup while one is still active. | [backup restore crds](./backup-restore-crds/) | +| Restore a restic snapshot into an existing server | stable | on | Suspends the target GameServer, overwrites its data volume from a snapshot, and resumes it. | [backups recovery](./backups-recovery/) | +| Reject a restore whose source backup is missing or not Succeeded | stable | on | Sets a Restore to Failed when its Backup does not exist or has no successful snapshot. | [backups recovery](./backups-recovery/) | +| Quiesce game writes before each backup | beta | on | Asks the game to flush and pause writes before the snapshot when quiesce is true, which is the default on Backups. | [backups recovery](./backups-recovery/) | +| Tune backup and restore Job retry limit and deadline | beta | on | Sets the retry count and wall-clock deadline for restic backup and restore Jobs through Helm values. | [helm values reference](./helm-values-reference/) | +| Browse backups and restores on the dashboard Backups page | beta | on | Lists per-server and global backups and restores with location, server and phase filters and a detail drawer. | [backups recovery](./backups-recovery/) | +| Create volume-snapshot CSI backups | beta | off | Captures a Kubernetes CSI VolumeSnapshot of the data volume instead of running restic, when a volume snapshot class is set. | [backup restore crds](./backup-restore-crds/) | +| Restore a CSI volume-snapshot backup into a new GameServer | beta | off | Provisions a new GameServer seeded from a volume snapshot; the original server is not touched. | [backup restore crds](./backup-restore-crds/) | +| Backup and restore drill runbook | planned | n/a | A documented runbook for periodic restore drills; the restore test exists but the runbook does not. | [roadmap](./roadmap/) | + +## Game modules and catalog + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Discover modules from an OCI module source | stable | on | The operator indexes an OCI module source and lists its modules and versions in ModuleSource status. | [modules sources](./modules-sources/) | +| Install a Module to materialize a GameTemplate | stable | on | Applying a Module CR makes the operator create the cluster-scoped GameTemplate for that module. | [modules sources](./modules-sources/) | +| Block deleting a Module or GameTemplate that a server uses | stable | on | A finalizer keeps a Module or GameTemplate in place while a GameServer still uses its template. | [modules sources](./modules-sources/) | +| Reject module source URLs that resolve to unsafe targets | stable | on | Module source fetches go through the SSRF dial guard, which refuses unsafe destinations. | [modules sources](./modules-sources/) | +| Report an unreachable module registry on the Module | stable | on | A Module reports a failure when its source registry cannot be reached. | [modules sources](./modules-sources/) | +| Upload module bundles to the upload source | stable | on | Bundles uploaded through the API are stored in an upload ModuleSource and indexed like any other source. | [upload a module](./upload-a-module/) | +| Switch a running server to another module version | stable | on | Changes a GameServer to another catalog version and loader, keeping each version and loader on its own data volume. | [modules sources](./modules-sources/) | +| Official game module catalog | beta | on | The official OCI catalog holds 29 game modules in the module repository, and the chart enables 16 of them by default. | [modules sources](./modules-sources/) | +| Browse the merged module catalog with install and verification states | beta | on | The Modules page shows available, installed, verified, failed and update states across all configured sources. | [modules sources](./modules-sources/) | +| Pin a Module to a bundle digest | beta | off | Sets Module spec digest so the operator installs only that exact bundle content. | [modules sources](./modules-sources/) | +| Verify cosign signatures on module bundles | beta | off | Checks a bundle signature against a configured public key before installing it. | [modules sources](./modules-sources/) | +| Verify keyless Sigstore identity signatures on module bundles | beta | off | Checks a bundle signed with a Fulcio identity and an optional transparency-log requirement. | [modules sources](./modules-sources/) | +| Use a Git repository as a module source | beta | off | Reads module directories from a Git repository at a pinned ref and optional subPath. | [module authoring](./module-authoring/) | +| Use an HTTP archive as a module source | beta | off | Reads module directories from a tar.gz or zip archive served over HTTP or HTTPS. | [module authoring](./module-authoring/) | +| Use a local directory as a module source | beta | off | Reads module directories from a path mounted into the operator pod. | [module authoring](./module-authoring/) | +| Complete specs.md for all 29 game modules | planned | n/a | Each game module carries a specs.md documenting its template configuration; 26 of 29 have one today. | [roadmap](./roadmap/) | +| Nuclear Option join through a load-balancer IP pool override | in progress | n/a | Lets Nuclear Option clients join through a load-balancer IP pool override; blocked until the server binding on UDP 7777 is documented. | [roadmap](./roadmap/) | + +## Module authoring + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Declare a mods capability in a GameTemplate | stable | on | A template declares file-drop paths or an ID list so the mod install flow knows where mods go. | [module authoring](./module-authoring/) | +| Render an install wizard from a config schema | beta | on | A template config schema generates the install and settings form for a server. | [module authoring](./module-authoring/) | +| Declare admin actions with typed inputs | beta | on | A template lists admin actions with input definitions that the console and API render and validate. | [module authoring](./module-authoring/) | +| Author modules in the dashboard Modules builder | beta | on | The dashboard offers a builder that creates module content without the CLI. | [module authoring quickstart](./module-authoring-quickstart/) | +| Scaffold a new module with gp-module init | beta | n/a | Generates a module directory with module.yaml, template.yaml and README.md for a chosen archetype. | [module authoring quickstart](./module-authoring-quickstart/) | +| Validate a module offline with gp-module validate | beta | n/a | Checks a module directory offline and can emit machine-readable JSON for CI. | [module authoring quickstart](./module-authoring-quickstart/) | +| Dry-run a template config with gp-module preview | beta | n/a | Shows the runtime config a template would produce for a given memory limit and user configuration. | [module authoring quickstart](./module-authoring-quickstart/) | +| Package a module bundle with gp-module package | beta | n/a | Builds a local tar.gz bundle from a module directory, with package size limits applied. | [module authoring quickstart](./module-authoring-quickstart/) | +| Push a module bundle to an OCI registry | beta | n/a | Publishes a packaged module bundle as an OCI artifact for a module source to index. | [module authoring](./module-authoring/) | +| Sign module bundles with cosign in the release pipeline | beta | n/a | Signs official bundles with a cosign key held in CI secrets so verifying sources can check them. | [module authoring](./module-authoring/) | +| Editor JSON schemas for module.yaml and template.yaml | beta | n/a | Provides yaml-language-server schemas so editors validate and autocomplete module and template files. | [gametemplate schema](./gametemplate-schema/) | + +## Networking and tunnels + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Expose a server through a ClusterIP Service | stable | on | The default expose mode fronts the game pod with a Service reachable only inside the cluster. | [network automation](./network-automation/) | +| Apply a per-server egress NetworkPolicy for the tunnel pod | beta | on | Creates an egress policy for a tunnel-enabled server that admits DNS, advertised ports and provider relay ports. | [server networking tunnels](./server-networking-tunnels/) | +| Expose a server through a NodePort Service | beta | off | An opt-in expose mode publishes game ports on node ports, with an optional pinned port number. | [network automation](./network-automation/) | +| Expose a server through a LoadBalancer Service | beta | off | An opt-in expose mode asks the cluster load-balancer address manager for an external address. | [network automation](./network-automation/) | +| Expose a server through a Hostport mapping | beta | off | An opt-in expose mode binds game ports on the node host, which the wake sentinel cannot hold. | [network automation](./network-automation/) | +| Request a named address pool for a server | beta | off | Writes a MetalLB or Cilium pool preference onto a LoadBalancer Service, recorded as unhonored when no address manager is set. | [network automation](./network-automation/) | +| Request a specific external IP address for a server | beta | off | Sets spec.networking.address so the address manager assigns that IP. | [network automation](./network-automation/) | +| Report address assignment progress on the AddressAssignment condition | beta | off | Shows Assigned, AssignmentPending, ServiceNotReady, IgnoredForExposureMode and other reasons on the server status. | [network automation](./network-automation/) | +| Refuse an address already held by another GameServer | beta | off | Reports AddressInUse when another GameServer in the cluster already reports the same address. | [network automation](./network-automation/) | +| Report a missing or exhausted address pool | beta | off | Reports PoolNotFound or AllocationFailed when the requested pool is absent or has no free addresses. | [network automation](./network-automation/) | +| Change the address pool of a running server | beta | off | Updates pool metadata on a running server, while whether the IP changes depends on the load balancer. | [network automation](./network-automation/) | +| Relay players through an frp tunnel | beta | off | Runs an frpc tunnel pod that dials your own frps server and advertises serverAddr:remotePort. | [server networking tunnels](./server-networking-tunnels/) | +| Relay players through a Tailscale tailnet | beta | off | Joins the game pod to your tailnet with an auth key so only tailnet devices can reach it. | [server networking tunnels](./server-networking-tunnels/) | +| Relay players through a playit.gg tunnel | beta | off | Runs a playit tunnel and reports its assigned public address into status.endpoints, rechecked every 30 seconds. | [server networking tunnels](./server-networking-tunnels/) | +| Store tunnel credentials as owned Secrets | beta | off | Accepts relay credentials from the dashboard or the tunnel-credentials API and refuses Secrets without a matching ownerReference. | [server networking tunnels](./server-networking-tunnels/) | +| Keep the tunnel pod running while the game sleeps | beta | off | The tunnel Deployment keeps the relay connection and public address up while the game pod is asleep. | [server networking tunnels](./server-networking-tunnels/) | +| Restrict game ingress with a sourceRanges allowlist | beta | off | Limits Service-port traffic to listed source ranges, and does not gate traffic arriving through a tunnel. | [network automation](./network-automation/) | +| Report conflicting networking options as a status condition | planned | n/a | Would flag redundant settings such as a public LoadBalancer plus a tunnel as an informational condition. | [roadmap](./roadmap/) | + +## Idle sleep and wake + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Wake a sleeping server with the wake verb | beta | on | POST /servers/\{name\}:wake clears the operator sleep marker so the game pod comes back. | [server operations](./server-operations/) | +| Show slept servers as Asleep with a Wake button in the dashboard | beta | on | The dashboard labels a slept server Asleep and offers Wake instead of Start. | [server operations](./server-operations/) | +| Opt in to idle auto-sleep after a set number of empty minutes | beta | off | Opt-in spec.idle lets the operator scale a server to zero after it reports no players for afterMinutes, with a 5-minute floor. | [server operations](./server-operations/) | +| Sleep an idle server through the module stop sequence | beta | off | Sleep runs the same softStop path as a manual stop, then reads Suspended with an IdleAsleep reason. | [server operations](./server-operations/) | +| Wake a sleeping server on a cron wake window | beta | off | spec.idle.wakeWindows cron expressions in the cluster timezone clear the sleep marker at each tick. | [server operations](./server-operations/) | +| Show why a server will not sleep | beta | off | status.idle.reason and the dashboard explain when idle time is not accruing. | [server operations](./server-operations/) | +| Freeze the idle clock on stale heartbeats or missing player counts | beta | off | A stale agent heartbeat or absent playersOnline pauses idle time, so unknown is never read as empty. | [server operations](./server-operations/) | +| Report idle sleep state in the gameplane_gameservers_idle metric | beta | off | An operator gauge labelled asleep or awake for idle-enabled servers. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Arm wake-on-connect for a server | beta | off | spec.idle.wakeOnConnect makes the operator run a sentinel pod that holds advertised ports while the game is asleep. | [server operations](./server-operations/) | +| Wake on a Minecraft join but not on a server-list ping | beta | off | The Minecraft parser answers status pings in place and wakes the game only for a real join. | [server operations](./server-operations/) | +| Wake on a Terraria join through the Terraria parser | beta | off | Terraria and tModLoader modules declare the Terraria handshake parser. | [server operations](./server-operations/) | +| Wake other games with a packets-in-window heuristic | beta | off | Games without a parser wake on traffic and drop the first client, which must retry. | [server operations](./server-operations/) | +| Send a try-again disconnect when a held join misses the deadline | beta | off | Minecraft and Terraria clients receive a protocol-native waking-up message after the 25-second default deadline. | [server operations](./server-operations/) | +| Choose a wake protocol per game port | beta | off | GamePort.wakeProtocol selects minecraft, terraria, generic or none for each advertised port. | [server operations](./server-operations/) | +| Hold advertised ports by switching Service endpoints during sleep | beta | off | While asleep the Service points at the sentinel, and on wake it points back at the game pod. | [server operations](./server-operations/) | +| Bounce held clients on Hostport servers instead of holding them | beta | off | Hostport cannot be held by the sentinel, so it bounces clients and exits on wake. | [network automation](./network-automation/) | + +## Multi-cluster + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Register a remote cluster with its kubeconfig | stable | on | The Clusters page or POST /clusters stores a remote Kubernetes target that requests are routed to. | [multi cluster](./multi-cluster/) | +| Create a server on a chosen registered cluster | stable | on | A create request with ?cluster=<id> places the GameServer on that cluster's own Kubernetes API. | [multi cluster](./multi-cluster/) | +| Read servers from a selected cluster with ?cluster= dispatch | stable | on | Listing and reads resolve the requested cluster, reject unknown cluster ids with 400, and keep remote servers out of the local listing. | [multi cluster](./multi-cluster/) | +| Enforce per-cluster RBAC grants on remote servers | stable | on | A viewer bound only to the local cluster is forbidden from reading remote servers. | [multi cluster](./multi-cluster/) | +| Require a cluster-wide grant for remote module catalog access | beta | on | Catalog reads and writes on a remote cluster need a cluster-wide modules:read or modules:manage grant there. | - | +| Refuse fallback to a same-named local server when a remote target is missing | stable | on | A missing remote server never resolves to the home namesake, including registry, modpack and capture routes. | [multi cluster](./multi-cluster/) | +| Keep node join tokens and kubeconfig issuance local to the central cluster | stable | on | Node join token and kubeconfig endpoints are available only for the local cluster. | [cluster nodes kubeconfig](./cluster-nodes-kubeconfig/) | +| Add nodes and download kubeconfig from the Cluster page | beta | off | With clusterOps enabled, the Cluster page mints a node join command and a downloaded kubeconfig, which grants kube-system and CSR-approval RBAC. | - | +| Remove a registered cluster and its kubeconfig Secret | stable | on | Removing a registration deletes the kubeconfig Secret the API created for it. | [multi cluster](./multi-cluster/) | +| Rotate a registered kubeconfig in place | beta | on | PUT /clusters/\{name\}/kubeconfig replaces the credential, keeps identity and grants, and reloads the client. | - | +| Show Kubernetes API health per registered cluster | beta | on | The Clusters page shows API health, version and last check, but not gateway or game health. | [multi cluster](./multi-cluster/) | +| Browse node inventory for a selected cluster | beta | on | The Cluster page lists nodes and capacity for the chosen cluster, and a failed remote read shows an error rather than local data. | [cluster nodes kubeconfig](./cluster-nodes-kubeconfig/) | +| Show combined server and player counts across authorized sites | beta | on | The dashboard totals authorized sites and labels unavailable or truncated scopes next to partial totals. | [dashboard tour](./dashboard-tour/) | +| Filter servers, backups and schedules by location | beta | on | Location filters in the existing popovers narrow combined lists without a global cluster switcher. | [dashboard tour](./dashboard-tour/) | +| Search servers across sites without identity collisions | beta | on | One search covers authorized servers from every site, keeping cluster, namespace and name on each result. | [dashboard tour](./dashboard-tour/) | +| Open canonical server links that carry cluster and namespace | beta | on | Direct links and fresh tabs target the named cluster and namespace, ignoring stored cluster selections. | - | +| Route registry, modpack and mod-ID writes to the selected cluster | beta | on | Mod and modpack configuration writes go to the selected cluster with resource-version and UID protection. | - | +| Block unsafe address classes for remote Kubernetes and gateway dials | beta | on | Dial-time checks reject loopback, link-local, metadata, unspecified and multicast destinations. | - | +| Run remote agent operations through the gateway | beta | off | The optional private gateway carries agent operations such as files, mods and player data to a registered cluster over mTLS. | [remote agent gateway](./remote-agent-gateway/) | +| Register gateway URL and mTLS credentials per cluster | beta | off | Cluster.spec.agentGateway (combined) or PUT /clusters/\{name\}/gateway (standalone) stores the gateway endpoint and labelled credentials. | [remote agent gateway](./remote-agent-gateway/) | +| Check gateway capabilities and refuse older agents | beta | off | The gateway advertises protocol and capture support, and agents without the UID route fail closed. | [remote agent gateway](./remote-agent-gateway/) | +| Download and delete remote capture files through the gateway | beta | off | Capture files are fetched and removed over a UID-bound gateway route, and unbound older files fail closed. | [remote agent gateway](./remote-agent-gateway/) | +| Rotate gateway trust and revoke gateway access | beta | off | Repeated PUT rotates gateway credentials, and DELETE removes gateway access while keeping the cluster registration. | [remote agent gateway](./remote-agent-gateway/) | +| Keep games running when the gateway is down | beta | off | A gateway outage stops remote agent access but not games or the local operator. | [remote agent gateway](./remote-agent-gateway/) | +| Run the central panel without a local Kubernetes cluster | beta | off | api.standalone runs the dashboard and API with no operator, and the central host never runs games. | - | +| Install the standalone panel with Docker Compose | beta | off | deploy/standalone/compose.yaml runs the API and dashboard without a Kubernetes install, bound to 127.0.0.1:8080. | - | +| Store standalone remote credentials encrypted with a persistent panel key | beta | off | Remote credentials are encrypted in SQL with a key file that must be backed up with the database. | - | +| Rotate the panel master encryption key offline | beta | off | rotate-panel-key re-encrypts management credentials under a new key file in one transaction. | - | +| Run standalone with a provisioned panel key that is never generated | beta | off | The provisioned-key option requires an existing 32-byte key and refuses to create one. | - | +| Restrict remote destinations with an allowed CIDR list | beta | off | GAMEPLANE_REMOTE_ALLOWED_CIDRS limits Kubernetes API and gateway destinations to the listed networks. | - | +| Select a remote cluster for module installs and sources in standalone panels | beta | off | Standalone modules and module sources act on an explicitly selected registered cluster. | - | + +## Users, auth and access + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Sign in with local username and password accounts | stable | on | Local accounts sign in with argon2id-hashed passwords and receive an HttpOnly, Secure, SameSite=Lax session cookie. | [users auth rbac](./users-auth-rbac/) | +| Log out and end the session on the server | stable | on | Logging out invalidates the session so the old cookie no longer authenticates. | [users auth rbac](./users-auth-rbac/) | +| End existing sessions on dashboard password reset | stable | on | A dashboard password reset invalidates every existing session of that account. | [user administration](./user-administration/) | +| Throttle login attempts per client IP address | stable | on | Wrong-password login attempts are rate limited per source IP and return 429 once the bucket is exhausted. | [security](./security/) | +| Show generic login errors with no cluster or account details | stable | on | The login page and other unauthenticated views show only generic messages such as invalid credentials. | [security](./security/) | +| Disable or re-enable the local sign-in provider from auth settings | stable | on | Admins can disable local login from Authentication settings, after which the login endpoint refuses with a neutral response until it is re-enabled. | [users auth rbac](./users-auth-rbac/) | +| Check every API route against a fixed permission catalog | stable | on | Each route maps to one resource:action permission from the server-defined catalog, and unmatched routes fail closed. | [permission catalog](./permission-catalog/) | +| Use the built-in admin, operator and viewer roles | stable | on | Three seeded roles give admin full access, operators server control without user management, and viewers read-only access. | [users auth rbac](./users-auth-rbac/) | +| Create custom roles from permission catalog subsets | stable | on | Admins create, edit and delete custom roles holding any subset of the catalog, never the wildcard. | [users auth rbac](./users-auth-rbac/) | +| Keep built-in roles immutable and block deleting assigned roles | stable | on | The admin role is immutable, built-in roles cannot be deleted, and any role still assigned to a user cannot be deleted. | [users auth rbac](./users-auth-rbac/) | +| Bind a role to a user within one namespace | stable | on | Per-namespace role bindings grant a role in a single namespace, while the wildcard namespace gives cluster-wide access. | [users auth rbac](./users-auth-rbac/) | +| Restrict destructive server actions to the owner or an admin | stable | on | Delete, wipe, ownership transfer and collaborator edits require the server's owner or an admin. | [ownership danger zone](./ownership-danger-zone/) | +| Remove a user account with all linked data | stable | on | Deleting a user removes SSO links, preferences, sessions, API tokens and role bindings and revokes the share links that account created. | [user administration](./user-administration/) | +| Save personal dashboard theme preferences | stable | on | Any signed-in user can read and save their own dashboard theme preferences. | [dashboard tour](./dashboard-tour/) | +| Customize the dashboard theme with presets, custom colors, a CSS overlay and safe mode | beta | on | Settings, Theme & Appearance offers preset themes, custom colors with a contrast check, a CSS overlay, safe mode, and import and export. | [dashboard tour](./dashboard-tour/) | +| Require the CSRF header on mutating requests | beta | on | Mutating requests must echo the CSRF cookie value in the X-Gameplane-CSRF header (double-submit). | [security](./security/) | +| Refuse an auth config save that leaves no sign-in provider enabled | beta | on | The API rejects an auth config save with zero enabled providers, counting the Helm provider as always enabled. | [sign in recovery](./sign-in-recovery/) | +| Refuse to demote or delete the last user manager | beta | on | The API refuses to demote or delete the last user who can manage users and refuses self-demotion below users:manage. | [users auth rbac](./users-auth-rbac/) | +| Require a cluster-wide binding for cluster-scoped permissions | beta | on | Cluster-scoped permissions such as users:manage need a cluster-wide binding, the same Role versus ClusterRole split Kubernetes uses. | [users auth rbac](./users-auth-rbac/) | +| Create and edit dashboard user accounts | beta | on | Admins create users, change a user's primary role and manage per-namespace bindings from the Users page. | [user administration](./user-administration/) | +| Share a read-only status link for one GameServer | beta | on | A token in a share link gives unauthenticated access to one GameServer's status and connection address, optionally with permission to wake it. | - | +| Reset an admin password from the API pod with bootstrap-admin | beta | n/a | Running bootstrap-admin with --force resets a named account's password, promotes it to admin and ends its existing sessions. | [sign in recovery](./sign-in-recovery/) | +| Re-enable local login from the API pod with bootstrap-admin | beta | n/a | Running bootstrap-admin with --enable-local-login force-enables the local provider so a locked-out admin can sign in. | [sign in recovery](./sign-in-recovery/) | +| Sign in with dashboard-managed OIDC providers | beta | off | Admins add OIDC providers from Authentication settings, store the client secret in a labelled Secret, and apply changes without restart. | [users auth rbac](./users-auth-rbac/) | +| Sign in with the Helm-configured OIDC provider | beta | off | The api.oidc Helm values add a read-only helm provider that the dashboard cannot edit, disable or delete. | [users auth rbac](./users-auth-rbac/) | +| Follow OIDC setup guides for five identity providers | beta | n/a | Step-by-step guides cover registering Gameplane as an OIDC client in Keycloak, Authentik, Google, Okta and Entra ID. | [users auth rbac](./users-auth-rbac/) | +| Assign roles from IdP group claims at install time | beta | off | Helm-seeded group mappings for admin, operator and viewer assign the most privileged matching role, with a default role when nothing matches. | [users auth rbac](./users-auth-rbac/) | +| Re-evaluate the OIDC role on every login | beta | off | The role is recomputed from current IdP groups at each OIDC login, so a removed group lowers access on the next sign-in. | [users auth rbac](./users-auth-rbac/) | +| Override a role's IdP group list from the dashboard | beta | off | Admins replace the group list for a role in Authentication settings, effective at the next login, and reset it to the Helm value. | [users auth rbac](./users-auth-rbac/) | +| Service accounts on the Users page | planned | n/a | A Users page tab for service accounts is planned for v1.1. | [roadmap](./roadmap/) | + +## Audit and security + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Record every mutating API request in the audit log | stable | on | Each mutating API request writes an audit event to the audit_events table that the dashboard serves. | [audit observability admin](./audit-observability-admin/) | +| Page and filter the audit log | stable | on | The audit view pages through events and applies filters, backed by GET /admin/audit. | [audit observability admin](./audit-observability-admin/) | +| Encrypt agent and capture control traffic with mTLS | stable | on | Operator-managed agent and capture-sidecar control connections use mutual TLS 1.2 or newer with a verified client certificate. | [security](./security/) | +| Isolate pods with NetworkPolicies | stable | on | Applies NetworkPolicies that restrict ingress to game servers and give the API pod an egress policy that allows private ranges. | [security](./security/) | +| Export the audit trail as CSV or JSON | beta | on | GET /admin/audit/export downloads the full audit trail for offline review. | [audit observability admin](./audit-observability-admin/) | +| Verify the audit hash chain for tampering | beta | on | GET /admin/audit/verify re-walks the SHA-256 chain and reports the first broken link, catching naive in-database edits and tail truncation. | [audit observability admin](./audit-observability-admin/) | +| Resolve client IPs through trusted proxies | beta | on | The API reads X-Forwarded-For only from peers inside api.trustedProxies, so audit records and per-IP limits use the real client address. | [security](./security/) | +| Run Gameplane pods with hardened security contexts | beta | on | Operator, API, agent and optional bridge pods run as uid 65532 with read-only root filesystems, RuntimeDefault seccomp and all capabilities dropped. | [security](./security/) | +| Redact GameServer password values in API responses | beta | on | Every API response carrying a GameServer replaces non-empty password values with a redaction marker and fails closed if the template cannot be read. | [server configuration](./server-configuration/) | +| Confine dashboard-managed credentials to labelled Secrets | beta | on | The API reads and deletes only Secrets carrying its own labels for auth providers and notification sinks, so a config write cannot aim at arbitrary Secrets. | [security](./security/) | +| Prune audit events past a retention age | beta | off | api.audit.retentionDays removes events older than N days, and the default of 0 keeps events forever. | [audit observability admin](./audit-observability-admin/) | +| Mirror audit events to stdout | beta | off | api.audit.stdout emits each audit event as a structured JSON log line for a cluster log aggregator. | [audit observability admin](./audit-observability-admin/) | +| Forward audit events to a webhook | beta | off | api.audit.webhook.url POSTs each event as JSON from a bounded best-effort buffer, with an optional Authorization header read from a Secret. | [audit observability admin](./audit-observability-admin/) | +| Deploy the bundled audit-syslog-bridge from Helm | beta | off | api.audit.webhook.syslogBridge.enabled deploys the bridge and points the audit webhook at it automatically. | [audit observability admin](./audit-observability-admin/) | +| Deliver audit events to syslog over TCP, TLS or UDP | beta | off | audit-syslog-bridge turns each audit JSON document into an RFC 5424 syslog record and sends it over TCP, TCP with TLS or UDP, with TCP recommended. | [audit observability admin](./audit-observability-admin/) | +| Stream audit batches to S3-compatible storage | beta | off | api.audit.s3 batches audit events as NDJSON objects, flushed at 100 events, 1 MiB or 5 seconds, to AWS S3, MinIO or a similar endpoint. | [audit observability admin](./audit-observability-admin/) | +| Audit OIDC role assignments and mapping overrides | beta | off | Each OIDC role assignment, override and reset writes an audit event naming the provider, matched group and role transition. | [audit observability admin](./audit-observability-admin/) | +| Enforce restricted Pod Security on the games namespace | beta | off | podSecurity.enforceRestricted applies the restricted Pod Security Standard to the games namespace. | [security](./security/) | +| Verify release signatures with the current cosign key | beta | n/a | The ECDSA P-256 cosign key verifies releases from the July 2026 rotation onward, and the retired Ed25519 key verifies earlier releases. | - | +| Sign the audit chain with a keyed HMAC | planned | n/a | An HMAC-keyed audit chain with the key held outside the database is a candidate future hardening. | [roadmap](./roadmap/) | + +## Notifications + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Store sink credentials in API-created Secrets | beta | on | Entering a sink's URL, ntfy topic or SMTP settings stores them in a Secret the API creates and labels, linked through configRef. | [notification sinks](./notification-sinks/) | +| Alert when a server becomes unhealthy or recovers | beta | on | server.unhealthy fires when a GameServer fails or loses its heartbeat, and server.recovered fires when it becomes healthy again. | [notification events payloads](./notification-events-payloads/) | +| Alert when a backup or restore fails | beta | on | backup.failed and restore.failed fire when a Backup or Restore enters the Failed phase. | [notification events payloads](./notification-events-payloads/) | +| Send a test event to a saved sink | beta | on | A POST to the sink test endpoint delivers a synthetic event synchronously and returns the real delivery outcome. | [notification sinks](./notification-sinks/) | +| Retry transient delivery failures | beta | on | Network errors and 5xx responses are retried twice with 2 and 8 second backoffs, while 4xx responses are not retried. | [notification sinks](./notification-sinks/) | +| Count deliveries in Prometheus metrics | beta | on | gameplane_notify_deliveries_total counts sent, failed, dropped and skipped deliveries per sink kind. | [production observability](./production-observability/) | +| Deliver notifications without blocking reconciliation or requests | beta | on | Notifications are sent from a bounded in-memory queue, so a slow or down sink never blocks reconciliation or an API request. | [notification sinks](./notification-sinks/) | +| Guard sink dials with the SSRF policy | beta | on | Every sink dial, over HTTP or SMTP, goes through the netguard IsAllowed policy and refuses link-local, unspecified, multicast and NAT64 destinations at dial time. | [notification sinks](./notification-sinks/) | +| Keep sink URLs out of delivery errors | beta | on | Delivery errors are sanitized so the sink URL, which often embeds a capability token, never appears in them. | [notification sinks](./notification-sinks/) | +| Label alerts with the install's instance name | beta | on | The Admin Settings instance name is sent as the instance field so alerts from different installs can be told apart. | [notification events payloads](./notification-events-payloads/) | +| Post structured JSON webhook payloads | beta | on | The generic webhook receives a JSON object with type, ts, kind, name, namespace, message, instance and test fields. | [notification events payloads](./notification-events-payloads/) | +| Send alerts to Discord, Slack, ntfy, SMTP or a generic webhook | beta | off | Admins add notification sinks in Admin Settings, and each sink kind receives its own payload format. | [notification sinks](./notification-sinks/) | +| Use pre-created labelled Secrets for sinks | beta | n/a | A Secret made with kubectl or GitOps works when it carries the gameplane.local/notification-sink label and a matching configRef. | [notification sinks](./notification-sinks/) | +| Alert when a backup or restore succeeds | beta | off | backup.succeeded and restore.succeeded are opt-in events that a sink must select. | [notification events payloads](./notification-events-payloads/) | +| Send email alerts over SMTP with selectable TLS | beta | off | The smtp sink takes host, from, to and optional port, username, password and a TLS mode of starttls (default), implicit or none. | [notification sinks](./notification-sinks/) | + +## Telemetry + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Send basic usage counts once a day | stable | on | The API sends its version, GameServer count and GameTemplate count once a day, with no names, namespaces or addresses. | [platform settings telemetry](./platform-settings-telemetry/) | +| Hold reports until an admin sees the first-login notice | stable | on | On a new install no report is sent until the first admin has seen the notice listing both tiers and the destination. | [platform settings telemetry](./platform-settings-telemetry/) | +| Turn basic telemetry off from Admin Settings | stable | on | Admin Settings telemetry toggles stop reports, and turning them back on resumes reporting without sending early. | [platform settings telemetry](./platform-settings-telemetry/) | +| Hard-disable telemetry at install time | stable | on | Setting api.telemetry.enabled to false stops all sending and hides the first-login notice, overriding the admin toggles. | [platform settings telemetry](./platform-settings-telemetry/) | +| Send extended usage reports with a random install ID | stable | on | The extended tier adds a random install ID, environment bands, per-module counts, feature flags and the UI language, all from fixed sets. | [platform settings telemetry](./platform-settings-telemetry/) | +| Send reports to the project default receiver | beta | on | An empty api.telemetry.endpoint sends reports to the project default receiver at telemetry.gameplane.net, and a custom endpoint replaces it. | [platform settings telemetry](./platform-settings-telemetry/) | +| Reset the install ID from Admin Settings | beta | on | An admin resets the pseudonymous install ID, and the install then looks new to the receiver. | [platform settings telemetry](./platform-settings-telemetry/) | +| Sign extended reports with an install key | beta | on | Extended reports carry an Ed25519 signature, so forged, unsigned, tampered or replayed reports are refused without changing stored data. | [platform settings telemetry](./platform-settings-telemetry/) | +| Run a bundled telemetry receiver from Helm | beta | off | api.telemetry.receiver.enabled deploys a receiver beside the install, with a PVC for its SQLite data. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Validate and aggregate incoming reports strictly | beta | off | The receiver decodes each report strictly, folds it into daily aggregates and expiring activity records, and never stores raw reports or source addresses. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Limit accepted reports per source per day | beta | off | INGEST_SOURCE_DAILY_LIMIT caps accepted reports per source per UTC day, with a default of 20. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Publish a public summary of five counts | beta | off | GET /v1/summary returns five fixed counts without credentials when PUBLIC_SUMMARY is true. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Browse the receiver dashboard behind a token | beta | off | The receiver dashboard on port 8081 starts only when DASHBOARD_TOKEN is at least 32 characters, and unauthenticated responses reveal nothing. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Scrape receiver metrics with a bearer token | beta | off | The receiver's /metrics on the dashboard listener accepts only the Bearer token and is absent from the public port. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Require proof of work on report ingestion | beta | off | INGEST_POW makes reporters solve a challenge whose difficulty rises with request rate, to deter bulk fabricated reports. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Expire receiver data on a retention schedule | beta | off | RETENTION_DAYS (default 730) and ACTIVITY_EXPIRY_DAYS (default 90) remove old aggregates and activity records on an hourly sweep. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Pseudonymise install IDs with a pepper | beta | off | The receiver stores only an HMAC of each install ID keyed with ID_PEPPER, generated and kept in its database if unset. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Run a standalone telemetry provider | beta | n/a | A runbook covers deploying the receiver image, TLS, secrets, Cloudflare settings, metrics and backups for a provider serving other installs. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Show a version-trend view in the receiver dashboard | in progress | n/a | A version-trend view in the telemetry dashboard is in progress under the spec 022 amendment T101 to T110. | [roadmap](./roadmap/) | + +## Observability and admin + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| API Prometheus metrics on a private listener | stable | on | The API serves Prometheus metrics on a dedicated listener that the public port does not expose. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Operator controller and fleet gauges | beta | on | The operator exports controller-runtime metrics and the gameplane_gameservers and gameplane_backups phase gauges. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Per-server agent metrics | beta | on | Each game pod agent exposes gameplane_agent CPU, memory, disk and player gauges on a plain metrics port 9090. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Admin system log viewer | beta | on | Admins follow API and operator logs in separate streams, filter them, and download raw records. | [system log viewer](./system-log-viewer/) | +| ServiceMonitor and PodMonitor scrape objects | beta | off | Helm can create Prometheus Operator objects that scrape the operator, API, telemetry receiver and agents. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Operator PrometheusRule alerts | beta | off | Helm can ship operator reconcile, workqueue, GameServer Failed and Backup Failed alert rules. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Operator Grafana dashboard | beta | off | Helm can ship a Grafana operator dashboard as a ConfigMap for sidecar auto-import. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Packet capture from game pods | beta | off | Admins start opt-in, BPF-filtered PCAPNG captures on a running game pod and download the files. | [helm values reference](./helm-values-reference/) | +| Automatic deletion of expired captures | beta | off | Completed packet captures are deleted automatically after their retention window ends. | [helm values reference](./helm-values-reference/) | + +## Localization + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Localized dashboard and community language packs | in progress | n/a | Spec 019 adds app localization and community language packs; the work is on open PR #668 and is not yet on master. | [roadmap](./roadmap/) | + +## Developer and operator tooling + +| Capability | Maturity | Default | Description | Docs | +|---|---|---|---|---| +| Install the panel from the Helm chart | stable | on | One helm upgrade --install installs the operator, API and dashboard. | [installation](./installation/) | +| CRD auto-apply on helm upgrade | stable | on | A pre-upgrade hook applies the Gameplane CRDs so every helm upgrade keeps the schema current. | [upgrades migrations](./upgrades-migrations/) | +| Read-only MCP server | beta | off | An optional MCP server lets AI assistants read GameServers, pods, events and logs and propose fixes without writing. | [helm values reference](./helm-values-reference/) | +| Helper image overrides for air-gapped mirrors | beta | n/a | Helm lets operators retag the config-init and restic helper images to a private registry mirror. | [air gapped installation](./air-gapped-installation/) | +| Rolling edge images | beta | off | Setting image.tag to edge runs the rolling build published on every master push. | [installation](./installation/) | +| Local Kind development loop | beta | n/a | Make targets create a Kind cluster with a local OCI registry, load images and run the web dev server. | [local development setup](./local-development-setup/) | +| Store API data in PostgreSQL | experimental | off | Runs the API against a PostgreSQL database instead of SQLite, but only in images built with the postgres build tag. | [database configuration](./database-configuration/) | +| Reuse an existing PVC for the API database | beta | off | Mounts a pre-existing PersistentVolumeClaim for the API SQLite database instead of creating one. | - | +| Reuse an existing PVC for the standalone panel key | beta | off | Mounts a pre-existing key-only PersistentVolumeClaim for generated standalone encryption keys. | - | From db59735795648e1291c80caf32ae735ccca42590 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 10:23:33 +0000 Subject: [PATCH 4/4] docs: group the Features page to 144 rows Mirrors the grouped FEATURES.md catalog in the main repo. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- src/content/docs/features.mdx | 294 +++++++++------------------------- 1 file changed, 80 insertions(+), 214 deletions(-) diff --git a/src/content/docs/features.mdx b/src/content/docs/features.mdx index de70aaa..b8b53a5 100644 --- a/src/content/docs/features.mdx +++ b/src/content/docs/features.mdx @@ -23,22 +23,16 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| | Create a game server from a module template | stable | on | Creates a GameServer from an installed module template through the create wizard or the API. | [create a server](./create-a-server/) | -| Start a stopped server | stable | on | Clears spec.suspend so the operator scales the pod back up. | [server operations](./server-operations/) | -| Stop a server | stable | on | Sets spec.suspend so the operator scales the pod to zero after the stop sequence. | [server operations](./server-operations/) | -| Restart a server | stable | on | Stamps a restart annotation so the pod restarts without changing desired state. | [server operations](./server-operations/) | +| Start, stop and restart a server | stable | on | Start clears spec.suspend so the operator scales the pod back up, stop sets it so the pod scales to zero after the stop sequence, and restart stamps an annotation that restarts the pod without changing desired state. | [server operations](./server-operations/) | | Show server phase and conditions | stable | on | Shows the server phase, such as Running or Suspended, with the reason conditions behind each. | [server operations](./server-operations/) | | Clone a server into a new GameServer | stable | on | Copies the spec of a server into a new GameServer. | [server operations](./server-operations/) | | Switch game version on a running server | stable | on | Changes the template version of an existing server so the operator rolls it out. | [server operations](./server-operations/) | | Delete a server | stable | on | Deletes a GameServer and its owned child objects. | [server operations](./server-operations/) | -| Transfer server ownership | beta | on | Lets the owner or an admin hand a server to another user. | [ownership danger zone](./ownership-danger-zone/) | -| Manage server collaborators | stable | on | Lets the owner set collaborator users who can use start, stop, restart, wake and clone. | [ownership danger zone](./ownership-danger-zone/) | +| Hand off server ownership and manage collaborators | beta | on | The owner or an admin can transfer a server to another user, and the owner can set collaborators who may use start, stop, restart, wake and clone. | [ownership danger zone](./ownership-danger-zone/) | | Graceful stop with the game's native shutdown sequence | beta | on | Runs the template stop sequence over RCON, telnet or stdin before the pod scales to zero so world saves finish. | [server operations](./server-operations/) | | Wipe world data with typed confirmation | beta | on | Suspends the server, erases the world volume and resumes, for owners or admins only. | [ownership danger zone](./ownership-danger-zone/) | -| Filter the server list by Running or Stopped | beta | on | Filters the server list with All, Running and Stopped tabs. | [server overview](./server-overview/) | -| List servers across all readable namespaces | beta | on | The Servers page lists servers from every namespace the viewer may read. | [server overview](./server-overview/) | -| Set an install-time default storage class for game data | beta | off | Applies the Helm default storage class to new game data volumes when neither the template nor the server names one. | - | -| Report a missing game-data storage class as PVCProvisioningFailed | stable | on | Sets the GameServer Ready condition to False with reason PVCProvisioningFailed when its storage class does not exist. | - | -| Keep game data on a PVC when the game pod is deleted | stable | on | Game data stays on its PVC when the game pod is deleted. | - | +| Browse and filter the server list across namespaces | beta | on | The Servers page lists servers from every namespace the viewer may read and filters them with All, Running and Stopped tabs. | [server overview](./server-overview/) | +| Keep game data on a PVC with clear storage errors | beta | on | Game data stays on its PVC when the game pod is deleted, and a missing storage class sets Ready to False with reason PVCProvisioningFailed; an install-time default storage class is opt-in. | - | | Edit game configuration from the Settings tab | in progress | n/a | Lets an operator change a server game configuration from its Settings tab, with validation. | [roadmap](./roadmap/) | ## Console and admin actions @@ -46,32 +40,21 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| | Live console stream for PTY-mode games | stable | on | Attaches the browser to the container stdin and stdout through the pod attach API for templates with consoleMode pty. | [console events logs](./console-events-logs/) | +| Container startup output stream | beta | on | Streams the game container stdout through the pod log API before the game log file exists. | [console events logs](./console-events-logs/) | | Run template quick actions | stable | on | Runs template-defined admin actions such as save, broadcast, time, weather and reload from buttons. | [server operations](./server-operations/) | +| Validate action input and run actions on PTY-only games | beta | on | Validates action parameters against the template schema and escapes them before they reach the game console, and runs actions on PTY-console games by writing lines to the container stdin. | [console protocols](./console-protocols/) | | Live game log tail | stable | on | Streams the game log file over a WebSocket from the agent sidecar. | [console events logs](./console-events-logs/) | -| RCON command console | beta | on | Sends line-based commands to the game RCON protocol and shows responses as log lines. | [console protocols](./console-protocols/) | -| Pick a console protocol from the full rcon.protocol set | beta | on | A template selects one of ten console protocols for its console, including REST and CLI. | [console protocols](./console-protocols/) | -| Run a console without a password with rcon.authentication false | beta | off | Lets a console with no authentication, such as a loopback-only port, run without a password Secret. | [console protocols](./console-protocols/) | -| Console command history | beta | on | Recalls the last 100 sent commands with the arrow keys, kept only while the Console tab stays open. | [console events logs](./console-events-logs/) | -| Clear, download and fullscreen console controls | beta | on | Toolbar buttons clear the terminal, download its buffer and toggle fullscreen without stopping the stream. | [console events logs](./console-events-logs/) | -| Schema-validated action input with injection guard | beta | on | Validates action parameters against the template schema and escapes them before they reach the game console. | [console protocols](./console-protocols/) | -| Stdin action transport for PTY-only games | beta | on | Runs actions on PTY-console games by writing lines to the container stdin through pods attach. | [console protocols](./console-protocols/) | +| Replay and download the full game log | beta | on | Replays up to the last 500 game-log lines when a tab opens, capped by the agent at 20,000 lines and 4 MiB, and downloads the whole log file without interrupting the live stream. | [console events logs](./console-events-logs/) | +| Send commands over RCON and ten console protocols | beta | on | Sends line-based commands over RCON or any of the ten console protocols a template selects, including REST and CLI; running without a password (rcon.authentication false) is opt-in. | [console protocols](./console-protocols/) | +| Console toolbar with history, clear, download and fullscreen | beta | on | Recalls the last 100 sent commands with the arrow keys, kept only while the Console tab stays open, and toolbar buttons clear the terminal, download its buffer and toggle fullscreen without stopping the stream. | [console events logs](./console-events-logs/) | | Kubernetes events timeline for a server | beta | on | Shows the 50 most recent Kubernetes events for the server pod and its parent objects. | [console events logs](./console-events-logs/) | -| Container startup output stream | beta | on | Streams the game container stdout through the pod log API before the game log file exists. | [console events logs](./console-events-logs/) | -| Log replay on tab open | beta | on | Replays up to the last 500 game-log lines before following new output, capped by the agent at 20,000 lines and 4 MiB. | [console events logs](./console-events-logs/) | -| Download the full game log | beta | on | Downloads the whole game log file without interrupting the live stream. | [console events logs](./console-events-logs/) | ## Files | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Browse the exposed server filesystem | stable | on | Lists directories under the exposed data root with a breadcrumb. | [file manager](./file-manager/) | -| Save text file contents through the write endpoint | stable | on | Saves text content to a file through the agent write endpoint, which the in-browser editor uses. | [file manager](./file-manager/) | -| Create a file through the write endpoint | stable | on | Creates a new file in the open directory through the write endpoint. | [file manager](./file-manager/) | -| Download a file | stable | on | Downloads one file from the server through the agent, including large files that stream past the request timeout. | [file manager](./file-manager/) | -| Delete a file | stable | on | Removes one file through the delete endpoint after confirmation. | [file manager](./file-manager/) | -| Create a folder | beta | on | Creates a folder in the open directory through the mkdir endpoint. | [file manager](./file-manager/) | -| Upload files | beta | on | Uploads files into the open directory through the upload endpoint, writing them group-readable for the game process. | [file manager](./file-manager/) | -| Delete a folder recursively | beta | on | Removes a folder and everything inside it after confirmation, and refuses folders that hold dot-prefixed entries. | [file manager](./file-manager/) | +| Browse, edit, create, download and delete files | stable | on | Lists directories under the exposed data root, saves and creates text files through the agent write endpoint, and downloads or deletes one file, including large downloads that stream past the request timeout. | [file manager](./file-manager/) | +| Upload files and manage folders | beta | on | Uploads files into the open directory, writing them group-readable for the game process, creates folders, and removes a folder and its contents after confirmation, refusing folders that hold dot-prefixed entries. | [file manager](./file-manager/) | | Confine file access to the exposed root | beta | on | Rejects path traversal and symlink escapes outside the exposed data root. | [file manager](./file-manager/) | ## Players @@ -79,76 +62,48 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| | View online players and capacity | stable | on | Shows the online count, the maximum and the player list, refreshed every 5 seconds, for templates that declare a player source. | [player administration](./player-administration/) | -| View the whitelist and add or remove entries | beta | on | Lists whitelist entries and adds or removes names through the whitelist endpoints. | [player administration](./player-administration/) | -| Kick a player | beta | on | Disconnects an online player through the template kick command, and returns HTTP 501 when the template does not declare it. | [player administration](./player-administration/) | -| Ban and unban a player | beta | on | Adds or removes a persistent ban through the template ban and unban commands. | [player administration](./player-administration/) | -| View the banned players list | beta | on | Shows the banned players reported by the game through the banned endpoint. | [player administration](./player-administration/) | +| Manage the whitelist, kick, ban and banned list | beta | on | Edits whitelist entries, kicks online players, adds or removes persistent bans and lists the banned players the game reports, through the template commands; kick returns HTTP 501 when the template does not declare it. | [player administration](./player-administration/) | | Steam display names on player lists | beta | off | Resolves Steam IDs to display names through the Steam Web API once a Secret is configured. | - | ## Mods | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Install a mod from a download URL with registry metadata in the mod manifest | stable | on | Installs a mod file from a download URL and records its registry metadata in the per-volume mod manifest. | [mods modpacks](./mods-modpacks/) | -| Upgrade an installed mod in place and remove it from the manifest | stable | on | Replaces an installed mod with a new file and removes the old file and its manifest entry, or removes the mod entirely. | [mods modpacks](./mods-modpacks/) | -| Upload a mod file directly from the dashboard | stable | on | Accepts a multipart mod file upload for a server and installs it as a file-drop mod. | [mods modpacks](./mods-modpacks/) | +| Install, upgrade and upload mods | stable | on | Installs a mod file from a download URL with registry metadata in the per-volume mod manifest, replaces or removes an installed mod in place, and installs a multipart file upload as a file-drop mod. | [mods modpacks](./mods-modpacks/) | | Reject path-traversal and symlink-escape mod archives | stable | on | Extracts valid mod archives while rejecting zip-slip paths and symlinks that escape the target directory. | [mods modpacks](./mods-modpacks/) | | Install mods by launch-parameter ID | beta | on | Projects selected mod IDs into the launch environment for games that fetch mods at startup. | [mods modpacks](./mods-modpacks/) | -| Browse and install from Modrinth | beta | on | Searches and installs Modrinth mods scoped to the server game version and loader, with no key needed. | [mods modpacks](./mods-modpacks/) | -| Browse and install from Thunderstore | beta | on | Searches and installs Thunderstore packages for templates that set a community, with no key needed. | [mods modpacks](./mods-modpacks/) | -| Browse and install from Hangar | beta | on | Searches and installs Hangar plugins, with no key needed. | [mods modpacks](./mods-modpacks/) | -| Browse and install from the Factorio Mod Portal | beta | on | Installs Factorio mods from the mod portal using the user's factorio.com credentials entered in the install form. | [mods modpacks](./mods-modpacks/) | -| Browse and install from SpigotMC | beta | on | Searches and installs SpigotMC resources, with no key needed. | [mods modpacks](./mods-modpacks/) | -| Browse and install from GitHub Releases | beta | on | Installs release assets from a GitHub owner and repository set on the template, with no key needed. | [mods modpacks](./mods-modpacks/) | -| Browse and install from uMod | beta | on | Searches and installs uMod plugins, with no key needed. | [mods modpacks](./mods-modpacks/) | +| Browse and install from seven public registries | beta | on | Searches and installs mods from Modrinth, Thunderstore, Hangar, the Factorio Mod Portal, SpigotMC, GitHub Releases and uMod with no API key; Factorio asks for the user's factorio.com login in the install form, and Thunderstore and GitHub Releases need the template to name a community or an owner and repository. | [mods modpacks](./mods-modpacks/) | +| Browse CurseForge, Steam Workshop and Nexus Mods | beta | off | Searches and installs CurseForge mods and Steam Workshop items once an API key is set under Settings, Mod registries; Nexus Mods is browse-only, and downloads are not supported. | [mod registry credentials](./mod-registry-credentials/) | | Store and replace registry API keys from Settings | beta | on | Saves, replaces and removes registry keys under Settings, Mod registries, kept in Kubernetes Secrets or the standalone database. | [mod registry credentials](./mod-registry-credentials/) | | Check installed mods for newer versions | beta | on | Reports available updates for mods installed from a provider that has a resolvable version. | [mods modpacks](./mods-modpacks/) | | Install a modpack from a provider | beta | on | Installs a modpack either by pinning it into a server env (env-mode) or by installing its dependency mods (deps-mode). | [mods modpacks](./mods-modpacks/) | -| Browse and install from CurseForge | beta | off | Searches and installs CurseForge mods once a CurseForge API key is configured. | [mod registry credentials](./mod-registry-credentials/) | -| Browse and install from Steam Workshop | beta | off | Searches and installs Steam Workshop items once a Steam Web API key is configured. | [mod registry credentials](./mod-registry-credentials/) | -| Browse Nexus Mods | beta | off | Browses Nexus Mods once an API key is configured; downloads are not supported. | [mod registry credentials](./mod-registry-credentials/) | ## Backups and restore | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Create an on-demand restic-snapshot backup of a server | stable | on | Starts a Backup that runs restic against the server data volume and records the snapshot ID. | [backups recovery](./backups-recovery/) | -| Connect a restic repository through a labelled Secret | stable | on | Reads the restic repository and credentials from a labelled Kubernetes Secret referenced by repoRef. | [backup destinations](./backup-destinations/) | -| Store restic backups in S3-compatible storage | beta | on | Points a restic repository at an S3-compatible endpoint through the repository URL in the labelled Secret. | [backup destinations](./backup-destinations/) | -| Report a Failed backup for a missing PVC or bad credentials | stable | on | Sets a Backup to Failed with a message when its data volume is missing or its repository credentials are rejected. | [backups recovery](./backups-recovery/) | -| Delete a backup and forget its restic snapshot with prune | stable | on | Deleting a Backup runs restic forget with prune so the snapshot is removed from the repository. | [backups recovery](./backups-recovery/) | -| Run backups on a cron schedule | stable | on | A BackupSchedule creates Backup resources on its cron expression and records last and next schedule times. | [backup restore crds](./backup-restore-crds/) | -| Suspend a backup schedule | stable | on | Setting suspend on a BackupSchedule stops it from creating new backups. | [backup restore crds](./backup-restore-crds/) | -| Trim old backups with keep-last retention | stable | on | Applies keepLast retention after each scheduled backup; an empty policy keeps everything. | [backups recovery](./backups-recovery/) | -| Forbid overlapping scheduled backups | stable | on | A schedule with concurrencyPolicy Forbid does not start a new backup while one is still active. | [backup restore crds](./backup-restore-crds/) | +| Run on-demand and scheduled restic backups | stable | on | Starts a Backup that runs restic against the server data volume and records the snapshot ID; a BackupSchedule creates Backups on its cron expression, records last and next times, can be suspended, and with a Forbid concurrency policy does not start a backup while one is active. | [backups recovery](./backups-recovery/) | +| Trim backups with keep-last retention and prune on delete | stable | on | Applies keepLast retention after each scheduled backup, where an empty policy keeps everything, and deleting a Backup runs restic forget with prune so its snapshot is removed. | [backups recovery](./backups-recovery/) | +| Connect a restic repository through a labelled Secret | beta | on | Reads the restic repository and credentials from a labelled Kubernetes Secret referenced by repoRef, and points it at S3-compatible storage through the repository URL in that Secret. | [backup destinations](./backup-destinations/) | +| Report failed backups and rejected restores | stable | on | Sets a Backup to Failed when its data volume is missing or its repository credentials are rejected, and sets a Restore to Failed when its Backup is missing or has no successful snapshot. | [backups recovery](./backups-recovery/) | | Restore a restic snapshot into an existing server | stable | on | Suspends the target GameServer, overwrites its data volume from a snapshot, and resumes it. | [backups recovery](./backups-recovery/) | -| Reject a restore whose source backup is missing or not Succeeded | stable | on | Sets a Restore to Failed when its Backup does not exist or has no successful snapshot. | [backups recovery](./backups-recovery/) | | Quiesce game writes before each backup | beta | on | Asks the game to flush and pause writes before the snapshot when quiesce is true, which is the default on Backups. | [backups recovery](./backups-recovery/) | | Tune backup and restore Job retry limit and deadline | beta | on | Sets the retry count and wall-clock deadline for restic backup and restore Jobs through Helm values. | [helm values reference](./helm-values-reference/) | | Browse backups and restores on the dashboard Backups page | beta | on | Lists per-server and global backups and restores with location, server and phase filters and a detail drawer. | [backups recovery](./backups-recovery/) | -| Create volume-snapshot CSI backups | beta | off | Captures a Kubernetes CSI VolumeSnapshot of the data volume instead of running restic, when a volume snapshot class is set. | [backup restore crds](./backup-restore-crds/) | -| Restore a CSI volume-snapshot backup into a new GameServer | beta | off | Provisions a new GameServer seeded from a volume snapshot; the original server is not touched. | [backup restore crds](./backup-restore-crds/) | +| Create and restore CSI volume-snapshot backups | beta | off | Captures a CSI VolumeSnapshot of the data volume instead of running restic when a volume snapshot class is set, and restores one into a new GameServer without touching the original server. | [backup restore crds](./backup-restore-crds/) | | Backup and restore drill runbook | planned | n/a | A documented runbook for periodic restore drills; the restore test exists but the runbook does not. | [roadmap](./roadmap/) | ## Game modules and catalog | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Discover modules from an OCI module source | stable | on | The operator indexes an OCI module source and lists its modules and versions in ModuleSource status. | [modules sources](./modules-sources/) | -| Install a Module to materialize a GameTemplate | stable | on | Applying a Module CR makes the operator create the cluster-scoped GameTemplate for that module. | [modules sources](./modules-sources/) | -| Block deleting a Module or GameTemplate that a server uses | stable | on | A finalizer keeps a Module or GameTemplate in place while a GameServer still uses its template. | [modules sources](./modules-sources/) | -| Reject module source URLs that resolve to unsafe targets | stable | on | Module source fetches go through the SSRF dial guard, which refuses unsafe destinations. | [modules sources](./modules-sources/) | -| Report an unreachable module registry on the Module | stable | on | A Module reports a failure when its source registry cannot be reached. | [modules sources](./modules-sources/) | -| Upload module bundles to the upload source | stable | on | Bundles uploaded through the API are stored in an upload ModuleSource and indexed like any other source. | [upload a module](./upload-a-module/) | +| Discover modules from OCI and upload sources | stable | on | The operator indexes an OCI module source and lists its modules and versions in ModuleSource status, and bundles uploaded through the API are stored in an upload source and indexed the same way. | [modules sources](./modules-sources/) | +| Install modules and block deleting ones a server uses | stable | on | Applying a Module CR makes the operator create the cluster-scoped GameTemplate for that module, and a finalizer keeps a Module or GameTemplate in place while a GameServer still uses its template. | [modules sources](./modules-sources/) | +| Reject unsafe or unreachable module sources | stable | on | Module source fetches go through the SSRF dial guard, which refuses unsafe destinations, and a Module reports a failure when its source registry cannot be reached. | [modules sources](./modules-sources/) | | Switch a running server to another module version | stable | on | Changes a GameServer to another catalog version and loader, keeping each version and loader on its own data volume. | [modules sources](./modules-sources/) | -| Official game module catalog | beta | on | The official OCI catalog holds 29 game modules in the module repository, and the chart enables 16 of them by default. | [modules sources](./modules-sources/) | -| Browse the merged module catalog with install and verification states | beta | on | The Modules page shows available, installed, verified, failed and update states across all configured sources. | [modules sources](./modules-sources/) | -| Pin a Module to a bundle digest | beta | off | Sets Module spec digest so the operator installs only that exact bundle content. | [modules sources](./modules-sources/) | -| Verify cosign signatures on module bundles | beta | off | Checks a bundle signature against a configured public key before installing it. | [modules sources](./modules-sources/) | -| Verify keyless Sigstore identity signatures on module bundles | beta | off | Checks a bundle signed with a Fulcio identity and an optional transparency-log requirement. | [modules sources](./modules-sources/) | -| Use a Git repository as a module source | beta | off | Reads module directories from a Git repository at a pinned ref and optional subPath. | [module authoring](./module-authoring/) | -| Use an HTTP archive as a module source | beta | off | Reads module directories from a tar.gz or zip archive served over HTTP or HTTPS. | [module authoring](./module-authoring/) | -| Use a local directory as a module source | beta | off | Reads module directories from a path mounted into the operator pod. | [module authoring](./module-authoring/) | +| Browse the official catalog and merged module states | beta | on | The official OCI catalog holds 29 game modules and the chart enables 16 by default, and the Modules page shows available, installed, verified, failed and update states across all configured sources. | [modules sources](./modules-sources/) | +| Pin or verify module bundles with digests and signatures | beta | off | Sets a Module digest so only that exact bundle installs, and checks bundle signatures against a cosign public key or a keyless Sigstore identity before installing. | [modules sources](./modules-sources/) | +| Use a Git repository, HTTP archive or local directory as a module source | beta | off | Reads module directories from a Git repository at a pinned ref, from a tar.gz or zip archive served over HTTP or HTTPS, or from a path mounted into the operator pod. | [module authoring](./module-authoring/) | | Complete specs.md for all 29 game modules | planned | n/a | Each game module carries a specs.md documenting its template configuration; 26 of 29 have one today. | [roadmap](./roadmap/) | | Nuclear Option join through a load-balancer IP pool override | in progress | n/a | Lets Nuclear Option clients join through a load-balancer IP pool override; blocked until the server binding on UDP 7777 is documented. | [roadmap](./roadmap/) | @@ -157,15 +112,10 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| | Declare a mods capability in a GameTemplate | stable | on | A template declares file-drop paths or an ID list so the mod install flow knows where mods go. | [module authoring](./module-authoring/) | -| Render an install wizard from a config schema | beta | on | A template config schema generates the install and settings form for a server. | [module authoring](./module-authoring/) | -| Declare admin actions with typed inputs | beta | on | A template lists admin actions with input definitions that the console and API render and validate. | [module authoring](./module-authoring/) | +| Render an install wizard and declare typed admin actions | beta | on | A template config schema generates the install and settings form for a server, and admin actions with typed input definitions are rendered and validated by the console and API. | [module authoring](./module-authoring/) | | Author modules in the dashboard Modules builder | beta | on | The dashboard offers a builder that creates module content without the CLI. | [module authoring quickstart](./module-authoring-quickstart/) | -| Scaffold a new module with gp-module init | beta | n/a | Generates a module directory with module.yaml, template.yaml and README.md for a chosen archetype. | [module authoring quickstart](./module-authoring-quickstart/) | -| Validate a module offline with gp-module validate | beta | n/a | Checks a module directory offline and can emit machine-readable JSON for CI. | [module authoring quickstart](./module-authoring-quickstart/) | -| Dry-run a template config with gp-module preview | beta | n/a | Shows the runtime config a template would produce for a given memory limit and user configuration. | [module authoring quickstart](./module-authoring-quickstart/) | -| Package a module bundle with gp-module package | beta | n/a | Builds a local tar.gz bundle from a module directory, with package size limits applied. | [module authoring quickstart](./module-authoring-quickstart/) | -| Push a module bundle to an OCI registry | beta | n/a | Publishes a packaged module bundle as an OCI artifact for a module source to index. | [module authoring](./module-authoring/) | -| Sign module bundles with cosign in the release pipeline | beta | n/a | Signs official bundles with a cosign key held in CI secrets so verifying sources can check them. | [module authoring](./module-authoring/) | +| Scaffold, validate, preview and package modules with gp-module | beta | n/a | gp-module init generates a module directory for a chosen archetype, validate checks it offline with JSON output for CI, preview dry-runs the runtime config for a memory limit and user configuration, and package builds a local tar.gz bundle with size limits. | [module authoring quickstart](./module-authoring-quickstart/) | +| Push and sign module bundles for OCI sources | beta | n/a | Publishes a packaged module bundle as an OCI artifact for a module source to index, and signs official bundles with a cosign key held in CI secrets. | [module authoring](./module-authoring/) | | Editor JSON schemas for module.yaml and template.yaml | beta | n/a | Provides yaml-language-server schemas so editors validate and autocomplete module and template files. | [gametemplate schema](./gametemplate-schema/) | ## Networking and tunnels @@ -174,19 +124,10 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what |---|---|---|---|---| | Expose a server through a ClusterIP Service | stable | on | The default expose mode fronts the game pod with a Service reachable only inside the cluster. | [network automation](./network-automation/) | | Apply a per-server egress NetworkPolicy for the tunnel pod | beta | on | Creates an egress policy for a tunnel-enabled server that admits DNS, advertised ports and provider relay ports. | [server networking tunnels](./server-networking-tunnels/) | -| Expose a server through a NodePort Service | beta | off | An opt-in expose mode publishes game ports on node ports, with an optional pinned port number. | [network automation](./network-automation/) | -| Expose a server through a LoadBalancer Service | beta | off | An opt-in expose mode asks the cluster load-balancer address manager for an external address. | [network automation](./network-automation/) | -| Expose a server through a Hostport mapping | beta | off | An opt-in expose mode binds game ports on the node host, which the wake sentinel cannot hold. | [network automation](./network-automation/) | -| Request a named address pool for a server | beta | off | Writes a MetalLB or Cilium pool preference onto a LoadBalancer Service, recorded as unhonored when no address manager is set. | [network automation](./network-automation/) | -| Request a specific external IP address for a server | beta | off | Sets spec.networking.address so the address manager assigns that IP. | [network automation](./network-automation/) | -| Report address assignment progress on the AddressAssignment condition | beta | off | Shows Assigned, AssignmentPending, ServiceNotReady, IgnoredForExposureMode and other reasons on the server status. | [network automation](./network-automation/) | -| Refuse an address already held by another GameServer | beta | off | Reports AddressInUse when another GameServer in the cluster already reports the same address. | [network automation](./network-automation/) | -| Report a missing or exhausted address pool | beta | off | Reports PoolNotFound or AllocationFailed when the requested pool is absent or has no free addresses. | [network automation](./network-automation/) | -| Change the address pool of a running server | beta | off | Updates pool metadata on a running server, while whether the IP changes depends on the load balancer. | [network automation](./network-automation/) | -| Relay players through an frp tunnel | beta | off | Runs an frpc tunnel pod that dials your own frps server and advertises serverAddr:remotePort. | [server networking tunnels](./server-networking-tunnels/) | -| Relay players through a Tailscale tailnet | beta | off | Joins the game pod to your tailnet with an auth key so only tailnet devices can reach it. | [server networking tunnels](./server-networking-tunnels/) | -| Relay players through a playit.gg tunnel | beta | off | Runs a playit tunnel and reports its assigned public address into status.endpoints, rechecked every 30 seconds. | [server networking tunnels](./server-networking-tunnels/) | -| Store tunnel credentials as owned Secrets | beta | off | Accepts relay credentials from the dashboard or the tunnel-credentials API and refuses Secrets without a matching ownerReference. | [server networking tunnels](./server-networking-tunnels/) | +| Expose a server through NodePort, LoadBalancer or Hostport | beta | off | Opt-in expose modes publish game ports on node ports with an optional pinned number, ask the cluster load-balancer address manager for an external address, or bind game ports on the node host, which the wake sentinel cannot hold. | [network automation](./network-automation/) | +| Request or change a named address pool or specific external IP | beta | off | Writes a MetalLB or Cilium pool preference or a specific address onto a LoadBalancer Service, recorded as unhonored when no address manager is set, and updates pool metadata on a running server, while whether the IP changes depends on the load balancer. | [network automation](./network-automation/) | +| Report address assignment, conflicts and pool errors | beta | off | Shows Assigned, AssignmentPending, ServiceNotReady and other reasons on the AddressAssignment condition, reports AddressInUse when another GameServer holds the address, and reports PoolNotFound or AllocationFailed when the pool is absent or exhausted. | [network automation](./network-automation/) | +| Relay players through frp, Tailscale or playit.gg | beta | off | Runs an frpc tunnel to your own frps server, joins the game pod to your tailnet with an auth key, or runs a playit tunnel whose public address is reported in status, with relay credentials stored as owned Secrets. | [server networking tunnels](./server-networking-tunnels/) | | Keep the tunnel pod running while the game sleeps | beta | off | The tunnel Deployment keeps the relay connection and public address up while the game pod is asleep. | [server networking tunnels](./server-networking-tunnels/) | | Restrict game ingress with a sourceRanges allowlist | beta | off | Limits Service-port traffic to listed source ranges, and does not gate traffic arriving through a tunnel. | [network automation](./network-automation/) | | Report conflicting networking options as a status condition | planned | n/a | Would flag redundant settings such as a public LoadBalancer plus a tunnel as an informational condition. | [roadmap](./roadmap/) | @@ -195,116 +136,68 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Wake a sleeping server with the wake verb | beta | on | POST /servers/\{name\}:wake clears the operator sleep marker so the game pod comes back. | [server operations](./server-operations/) | -| Show slept servers as Asleep with a Wake button in the dashboard | beta | on | The dashboard labels a slept server Asleep and offers Wake instead of Start. | [server operations](./server-operations/) | -| Opt in to idle auto-sleep after a set number of empty minutes | beta | off | Opt-in spec.idle lets the operator scale a server to zero after it reports no players for afterMinutes, with a 5-minute floor. | [server operations](./server-operations/) | -| Sleep an idle server through the module stop sequence | beta | off | Sleep runs the same softStop path as a manual stop, then reads Suspended with an IdleAsleep reason. | [server operations](./server-operations/) | +| Wake a sleeping server from the dashboard or wake verb | beta | on | POST /servers/\{name\}:wake clears the operator sleep marker so the game pod comes back, and the dashboard labels a slept server Asleep and offers Wake instead of Start. | [server operations](./server-operations/) | +| Sleep idle servers after empty minutes | beta | off | Opt-in spec.idle lets the operator scale a server to zero after it reports no players for afterMinutes, with a 5-minute floor, running the module stop sequence first. | [server operations](./server-operations/) | +| Explain and monitor idle sleep | beta | off | status.idle.reason and the dashboard explain why idle time is not accruing, a stale heartbeat or missing player count freezes the idle clock, and the gameplane_gameservers_idle gauge reports asleep or awake. | [server operations](./server-operations/) | | Wake a sleeping server on a cron wake window | beta | off | spec.idle.wakeWindows cron expressions in the cluster timezone clear the sleep marker at each tick. | [server operations](./server-operations/) | -| Show why a server will not sleep | beta | off | status.idle.reason and the dashboard explain when idle time is not accruing. | [server operations](./server-operations/) | -| Freeze the idle clock on stale heartbeats or missing player counts | beta | off | A stale agent heartbeat or absent playersOnline pauses idle time, so unknown is never read as empty. | [server operations](./server-operations/) | -| Report idle sleep state in the gameplane_gameservers_idle metric | beta | off | An operator gauge labelled asleep or awake for idle-enabled servers. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | -| Arm wake-on-connect for a server | beta | off | spec.idle.wakeOnConnect makes the operator run a sentinel pod that holds advertised ports while the game is asleep. | [server operations](./server-operations/) | -| Wake on a Minecraft join but not on a server-list ping | beta | off | The Minecraft parser answers status pings in place and wakes the game only for a real join. | [server operations](./server-operations/) | -| Wake on a Terraria join through the Terraria parser | beta | off | Terraria and tModLoader modules declare the Terraria handshake parser. | [server operations](./server-operations/) | -| Wake other games with a packets-in-window heuristic | beta | off | Games without a parser wake on traffic and drop the first client, which must retry. | [server operations](./server-operations/) | -| Send a try-again disconnect when a held join misses the deadline | beta | off | Minecraft and Terraria clients receive a protocol-native waking-up message after the 25-second default deadline. | [server operations](./server-operations/) | -| Choose a wake protocol per game port | beta | off | GamePort.wakeProtocol selects minecraft, terraria, generic or none for each advertised port. | [server operations](./server-operations/) | -| Hold advertised ports by switching Service endpoints during sleep | beta | off | While asleep the Service points at the sentinel, and on wake it points back at the game pod. | [server operations](./server-operations/) | -| Bounce held clients on Hostport servers instead of holding them | beta | off | Hostport cannot be held by the sentinel, so it bounces clients and exits on wake. | [network automation](./network-automation/) | +| Arm wake-on-connect and hold advertised ports while asleep | beta | off | spec.idle.wakeOnConnect makes the operator run a sentinel pod that holds advertised ports by switching Service endpoints during sleep, and Hostport servers bounce clients and exit on wake instead of holding them. | [server operations](./server-operations/) | +| Wake on game joins with per-port protocols and try-again disconnects | beta | off | Minecraft server-list pings are answered without waking, Terraria joins wake through the Terraria parser, other games wake on traffic and drop the first client, and held joins past the 25-second deadline get a protocol-native try-again disconnect, with the protocol chosen per port. | [server operations](./server-operations/) | ## Multi-cluster | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Register a remote cluster with its kubeconfig | stable | on | The Clusters page or POST /clusters stores a remote Kubernetes target that requests are routed to. | [multi cluster](./multi-cluster/) | -| Create a server on a chosen registered cluster | stable | on | A create request with ?cluster=<id> places the GameServer on that cluster's own Kubernetes API. | [multi cluster](./multi-cluster/) | -| Read servers from a selected cluster with ?cluster= dispatch | stable | on | Listing and reads resolve the requested cluster, reject unknown cluster ids with 400, and keep remote servers out of the local listing. | [multi cluster](./multi-cluster/) | +| Register, rotate and remove remote clusters | beta | on | Registering stores a remote Kubernetes target with its kubeconfig through the Clusters page or POST /clusters, PUT /clusters/\{name\}/kubeconfig rotates the credential in place, and removing a registration deletes the kubeconfig Secret the API created for it. | [multi cluster](./multi-cluster/) | +| Create and read servers on a chosen registered cluster | stable | on | A create or read request with ?cluster=<id> targets that cluster's own Kubernetes API, rejects unknown cluster ids with 400, and never falls back to a same-named local server when a remote target is missing. | [multi cluster](./multi-cluster/) | | Enforce per-cluster RBAC grants on remote servers | stable | on | A viewer bound only to the local cluster is forbidden from reading remote servers. | [multi cluster](./multi-cluster/) | -| Require a cluster-wide grant for remote module catalog access | beta | on | Catalog reads and writes on a remote cluster need a cluster-wide modules:read or modules:manage grant there. | - | -| Refuse fallback to a same-named local server when a remote target is missing | stable | on | A missing remote server never resolves to the home namesake, including registry, modpack and capture routes. | [multi cluster](./multi-cluster/) | +| Route module, registry and mod-ID writes to the selected cluster | beta | on | Mod and modpack configuration writes go to the selected cluster with resource-version and UID protection, and remote module catalog reads and writes need a cluster-wide modules:read or modules:manage grant there. | - | | Keep node join tokens and kubeconfig issuance local to the central cluster | stable | on | Node join token and kubeconfig endpoints are available only for the local cluster. | [cluster nodes kubeconfig](./cluster-nodes-kubeconfig/) | | Add nodes and download kubeconfig from the Cluster page | beta | off | With clusterOps enabled, the Cluster page mints a node join command and a downloaded kubeconfig, which grants kube-system and CSR-approval RBAC. | - | -| Remove a registered cluster and its kubeconfig Secret | stable | on | Removing a registration deletes the kubeconfig Secret the API created for it. | [multi cluster](./multi-cluster/) | -| Rotate a registered kubeconfig in place | beta | on | PUT /clusters/\{name\}/kubeconfig replaces the credential, keeps identity and grants, and reloads the client. | - | -| Show Kubernetes API health per registered cluster | beta | on | The Clusters page shows API health, version and last check, but not gateway or game health. | [multi cluster](./multi-cluster/) | -| Browse node inventory for a selected cluster | beta | on | The Cluster page lists nodes and capacity for the chosen cluster, and a failed remote read shows an error rather than local data. | [cluster nodes kubeconfig](./cluster-nodes-kubeconfig/) | -| Show combined server and player counts across authorized sites | beta | on | The dashboard totals authorized sites and labels unavailable or truncated scopes next to partial totals. | [dashboard tour](./dashboard-tour/) | -| Filter servers, backups and schedules by location | beta | on | Location filters in the existing popovers narrow combined lists without a global cluster switcher. | [dashboard tour](./dashboard-tour/) | -| Search servers across sites without identity collisions | beta | on | One search covers authorized servers from every site, keeping cluster, namespace and name on each result. | [dashboard tour](./dashboard-tour/) | +| Show API health and node inventory per registered cluster | beta | on | The Clusters page shows Kubernetes API health, version and last check, and the Cluster page lists nodes and capacity for the chosen cluster, showing an error rather than local data when a remote read fails. | [multi cluster](./multi-cluster/) | +| Combined counts, search and location filters across sites | beta | on | The dashboard totals authorized sites and labels partial totals, one search covers authorized servers from every site without identity collisions, and location filters narrow servers, backups and schedules. | [dashboard tour](./dashboard-tour/) | | Open canonical server links that carry cluster and namespace | beta | on | Direct links and fresh tabs target the named cluster and namespace, ignoring stored cluster selections. | - | -| Route registry, modpack and mod-ID writes to the selected cluster | beta | on | Mod and modpack configuration writes go to the selected cluster with resource-version and UID protection. | - | -| Block unsafe address classes for remote Kubernetes and gateway dials | beta | on | Dial-time checks reject loopback, link-local, metadata, unspecified and multicast destinations. | - | -| Run remote agent operations through the gateway | beta | off | The optional private gateway carries agent operations such as files, mods and player data to a registered cluster over mTLS. | [remote agent gateway](./remote-agent-gateway/) | -| Register gateway URL and mTLS credentials per cluster | beta | off | Cluster.spec.agentGateway (combined) or PUT /clusters/\{name\}/gateway (standalone) stores the gateway endpoint and labelled credentials. | [remote agent gateway](./remote-agent-gateway/) | -| Check gateway capabilities and refuse older agents | beta | off | The gateway advertises protocol and capture support, and agents without the UID route fail closed. | [remote agent gateway](./remote-agent-gateway/) | -| Download and delete remote capture files through the gateway | beta | off | Capture files are fetched and removed over a UID-bound gateway route, and unbound older files fail closed. | [remote agent gateway](./remote-agent-gateway/) | +| Block unsafe remote dial addresses, with an optional CIDR allowlist | beta | on | Dial-time checks reject loopback, link-local, metadata, unspecified and multicast destinations for remote Kubernetes and gateway dials; limiting destinations to listed networks with GAMEPLANE_REMOTE_ALLOWED_CIDRS is opt-in. | - | +| Run remote agent operations through the mTLS gateway | beta | off | The optional private gateway carries files, mods, player data and capture files to a registered cluster over mTLS, stores the gateway URL and labelled credentials per cluster, and refuses agents too old for the UID route. | [remote agent gateway](./remote-agent-gateway/) | | Rotate gateway trust and revoke gateway access | beta | off | Repeated PUT rotates gateway credentials, and DELETE removes gateway access while keeping the cluster registration. | [remote agent gateway](./remote-agent-gateway/) | | Keep games running when the gateway is down | beta | off | A gateway outage stops remote agent access but not games or the local operator. | [remote agent gateway](./remote-agent-gateway/) | -| Run the central panel without a local Kubernetes cluster | beta | off | api.standalone runs the dashboard and API with no operator, and the central host never runs games. | - | -| Install the standalone panel with Docker Compose | beta | off | deploy/standalone/compose.yaml runs the API and dashboard without a Kubernetes install, bound to 127.0.0.1:8080. | - | -| Store standalone remote credentials encrypted with a persistent panel key | beta | off | Remote credentials are encrypted in SQL with a key file that must be backed up with the database. | - | -| Rotate the panel master encryption key offline | beta | off | rotate-panel-key re-encrypts management credentials under a new key file in one transaction. | - | -| Run standalone with a provisioned panel key that is never generated | beta | off | The provisioned-key option requires an existing 32-byte key and refuses to create one. | - | -| Restrict remote destinations with an allowed CIDR list | beta | off | GAMEPLANE_REMOTE_ALLOWED_CIDRS limits Kubernetes API and gateway destinations to the listed networks. | - | -| Select a remote cluster for module installs and sources in standalone panels | beta | off | Standalone modules and module sources act on an explicitly selected registered cluster. | - | +| Run the central panel without a local Kubernetes cluster | beta | off | api.standalone runs the dashboard and API with no operator and the central host never runs games; Docker Compose installs it bound to 127.0.0.1:8080, and module installs act on a selected registered cluster. | - | +| Manage the standalone panel encryption key | beta | off | Remote credentials are encrypted in SQL with a key file that must be backed up with the database; rotate-panel-key re-encrypts them offline, and a provisioned-key option requires an existing 32-byte key and never generates one. | - | ## Users, auth and access | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Sign in with local username and password accounts | stable | on | Local accounts sign in with argon2id-hashed passwords and receive an HttpOnly, Secure, SameSite=Lax session cookie. | [users auth rbac](./users-auth-rbac/) | -| Log out and end the session on the server | stable | on | Logging out invalidates the session so the old cookie no longer authenticates. | [users auth rbac](./users-auth-rbac/) | -| End existing sessions on dashboard password reset | stable | on | A dashboard password reset invalidates every existing session of that account. | [user administration](./user-administration/) | -| Throttle login attempts per client IP address | stable | on | Wrong-password login attempts are rate limited per source IP and return 429 once the bucket is exhausted. | [security](./security/) | -| Show generic login errors with no cluster or account details | stable | on | The login page and other unauthenticated views show only generic messages such as invalid credentials. | [security](./security/) | -| Disable or re-enable the local sign-in provider from auth settings | stable | on | Admins can disable local login from Authentication settings, after which the login endpoint refuses with a neutral response until it is re-enabled. | [users auth rbac](./users-auth-rbac/) | -| Check every API route against a fixed permission catalog | stable | on | Each route maps to one resource:action permission from the server-defined catalog, and unmatched routes fail closed. | [permission catalog](./permission-catalog/) | -| Use the built-in admin, operator and viewer roles | stable | on | Three seeded roles give admin full access, operators server control without user management, and viewers read-only access. | [users auth rbac](./users-auth-rbac/) | -| Create custom roles from permission catalog subsets | stable | on | Admins create, edit and delete custom roles holding any subset of the catalog, never the wildcard. | [users auth rbac](./users-auth-rbac/) | -| Keep built-in roles immutable and block deleting assigned roles | stable | on | The admin role is immutable, built-in roles cannot be deleted, and any role still assigned to a user cannot be deleted. | [users auth rbac](./users-auth-rbac/) | -| Bind a role to a user within one namespace | stable | on | Per-namespace role bindings grant a role in a single namespace, while the wildcard namespace gives cluster-wide access. | [users auth rbac](./users-auth-rbac/) | +| Sign in with local accounts and disable or re-enable local login | stable | on | Local accounts sign in with argon2id-hashed passwords and receive an HttpOnly, Secure, SameSite=Lax session cookie, logging out or a dashboard password reset ends the sessions on the server, and admins can disable local login from Authentication settings until it is re-enabled. | [users auth rbac](./users-auth-rbac/) | +| Throttle login attempts and show generic login errors | stable | on | Wrong-password attempts are rate limited per source IP and return 429 once the bucket is exhausted, and the login page and other unauthenticated views show only generic messages such as invalid credentials. | [security](./security/) | +| Enforce a fixed permission catalog with built-in and custom roles | stable | on | Each API route maps to one permission from a fixed catalog and unmatched routes fail closed, the admin, operator and viewer roles are seeded, admins build custom roles from catalog subsets, and built-in roles are immutable. | [users auth rbac](./users-auth-rbac/) | +| Bind roles per namespace and require cluster-wide grants for cluster permissions | beta | on | Per-namespace role bindings grant a role in one namespace while the wildcard namespace gives cluster-wide access, and cluster-scoped permissions such as users:manage need a cluster-wide binding. | [users auth rbac](./users-auth-rbac/) | | Restrict destructive server actions to the owner or an admin | stable | on | Delete, wipe, ownership transfer and collaborator edits require the server's owner or an admin. | [ownership danger zone](./ownership-danger-zone/) | -| Remove a user account with all linked data | stable | on | Deleting a user removes SSO links, preferences, sessions, API tokens and role bindings and revokes the share links that account created. | [user administration](./user-administration/) | -| Save personal dashboard theme preferences | stable | on | Any signed-in user can read and save their own dashboard theme preferences. | [dashboard tour](./dashboard-tour/) | -| Customize the dashboard theme with presets, custom colors, a CSS overlay and safe mode | beta | on | Settings, Theme & Appearance offers preset themes, custom colors with a contrast check, a CSS overlay, safe mode, and import and export. | [dashboard tour](./dashboard-tour/) | +| Manage dashboard user accounts and remove users with their linked data | beta | on | Admins create users, change a primary role and manage per-namespace bindings from the Users page, and deleting a user removes SSO links, preferences, sessions, API tokens and role bindings and revokes the share links that account created. | [user administration](./user-administration/) | +| Refuse changes that would lock out every admin | beta | on | The API refuses an auth config save that leaves no sign-in provider enabled, counting the Helm provider as always enabled, and refuses to demote or delete the last user who can manage users. | [sign in recovery](./sign-in-recovery/) | +| Save and customize dashboard theme preferences | beta | on | Any signed-in user can save personal theme preferences, and Settings, Theme and Appearance offers preset themes, custom colors with a contrast check, a CSS overlay, safe mode, and import and export. | [dashboard tour](./dashboard-tour/) | | Require the CSRF header on mutating requests | beta | on | Mutating requests must echo the CSRF cookie value in the X-Gameplane-CSRF header (double-submit). | [security](./security/) | -| Refuse an auth config save that leaves no sign-in provider enabled | beta | on | The API rejects an auth config save with zero enabled providers, counting the Helm provider as always enabled. | [sign in recovery](./sign-in-recovery/) | -| Refuse to demote or delete the last user manager | beta | on | The API refuses to demote or delete the last user who can manage users and refuses self-demotion below users:manage. | [users auth rbac](./users-auth-rbac/) | -| Require a cluster-wide binding for cluster-scoped permissions | beta | on | Cluster-scoped permissions such as users:manage need a cluster-wide binding, the same Role versus ClusterRole split Kubernetes uses. | [users auth rbac](./users-auth-rbac/) | -| Create and edit dashboard user accounts | beta | on | Admins create users, change a user's primary role and manage per-namespace bindings from the Users page. | [user administration](./user-administration/) | | Share a read-only status link for one GameServer | beta | on | A token in a share link gives unauthenticated access to one GameServer's status and connection address, optionally with permission to wake it. | - | -| Reset an admin password from the API pod with bootstrap-admin | beta | n/a | Running bootstrap-admin with --force resets a named account's password, promotes it to admin and ends its existing sessions. | [sign in recovery](./sign-in-recovery/) | -| Re-enable local login from the API pod with bootstrap-admin | beta | n/a | Running bootstrap-admin with --enable-local-login force-enables the local provider so a locked-out admin can sign in. | [sign in recovery](./sign-in-recovery/) | -| Sign in with dashboard-managed OIDC providers | beta | off | Admins add OIDC providers from Authentication settings, store the client secret in a labelled Secret, and apply changes without restart. | [users auth rbac](./users-auth-rbac/) | -| Sign in with the Helm-configured OIDC provider | beta | off | The api.oidc Helm values add a read-only helm provider that the dashboard cannot edit, disable or delete. | [users auth rbac](./users-auth-rbac/) | +| Recover an admin with bootstrap-admin | beta | n/a | Running bootstrap-admin with --force resets a named account's password, promotes it to admin and ends its existing sessions, and --enable-local-login force-enables the local provider so a locked-out admin can sign in. | [sign in recovery](./sign-in-recovery/) | +| Sign in with dashboard-managed or Helm-configured OIDC providers | beta | off | Admins add OIDC providers from Authentication settings with the client secret in a labelled Secret, applied without restart, and the api.oidc Helm values add a read-only provider that the dashboard cannot edit, disable or delete. | [users auth rbac](./users-auth-rbac/) | +| Map IdP group claims to dashboard roles | beta | off | Helm-seeded group mappings assign the most privileged matching role at install time, the role is recomputed at every OIDC login, and admins can override a role's group list from Authentication settings, effective at the next login. | [users auth rbac](./users-auth-rbac/) | | Follow OIDC setup guides for five identity providers | beta | n/a | Step-by-step guides cover registering Gameplane as an OIDC client in Keycloak, Authentik, Google, Okta and Entra ID. | [users auth rbac](./users-auth-rbac/) | -| Assign roles from IdP group claims at install time | beta | off | Helm-seeded group mappings for admin, operator and viewer assign the most privileged matching role, with a default role when nothing matches. | [users auth rbac](./users-auth-rbac/) | -| Re-evaluate the OIDC role on every login | beta | off | The role is recomputed from current IdP groups at each OIDC login, so a removed group lowers access on the next sign-in. | [users auth rbac](./users-auth-rbac/) | -| Override a role's IdP group list from the dashboard | beta | off | Admins replace the group list for a role in Authentication settings, effective at the next login, and reset it to the Helm value. | [users auth rbac](./users-auth-rbac/) | | Service accounts on the Users page | planned | n/a | A Users page tab for service accounts is planned for v1.1. | [roadmap](./roadmap/) | ## Audit and security | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Record every mutating API request in the audit log | stable | on | Each mutating API request writes an audit event to the audit_events table that the dashboard serves. | [audit observability admin](./audit-observability-admin/) | -| Page and filter the audit log | stable | on | The audit view pages through events and applies filters, backed by GET /admin/audit. | [audit observability admin](./audit-observability-admin/) | +| Record and page through the audit log | stable | on | Each mutating API request writes an audit event to the audit_events table that the dashboard serves, and GET /admin/audit pages and filters the events. | [audit observability admin](./audit-observability-admin/) | +| Export the audit trail and verify its hash chain | beta | on | GET /admin/audit/export downloads the full trail as CSV or JSON, and GET /admin/audit/verify re-walks the SHA-256 chain and reports the first broken link. | [audit observability admin](./audit-observability-admin/) | +| Forward audit events to stdout or a webhook | beta | off | Mirrors each event as a structured JSON log line when api.audit.stdout is set, and POSTs each event as JSON from a bounded best-effort buffer when api.audit.webhook.url is set, with an optional Authorization header read from a Secret. | [audit observability admin](./audit-observability-admin/) | +| Ship audit events to syslog or S3-compatible storage | beta | off | The bundled audit-syslog-bridge turns events into RFC 5424 records sent over TCP, TCP with TLS or UDP, with TCP recommended, and api.audit.s3 batches NDJSON objects flushed at 100 events, 1 MiB or 5 seconds. | [audit observability admin](./audit-observability-admin/) | +| Prune audit events past a retention age | beta | off | api.audit.retentionDays removes events older than N days, and the default of 0 keeps events forever. | [audit observability admin](./audit-observability-admin/) | +| Resolve client IPs through trusted proxies | beta | on | The API reads X-Forwarded-For only from peers inside api.trustedProxies, so audit records and per-IP limits use the real client address. | [security](./security/) | +| Run Gameplane pods hardened and optionally enforce restricted Pod Security | beta | on | Operator, API, agent and optional bridge pods run as uid 65532 with read-only root filesystems, RuntimeDefault seccomp and all capabilities dropped, and podSecurity.enforceRestricted, off by default, applies the restricted Pod Security Standard to the games namespace. | [security](./security/) | +| Redact password values and confine credentials to labelled Secrets | beta | on | API responses replace non-empty GameServer password values with a redaction marker and fail closed if the template cannot be read, and the API reads and deletes only Secrets carrying its own labels for auth providers and notification sinks. | [security](./security/) | | Encrypt agent and capture control traffic with mTLS | stable | on | Operator-managed agent and capture-sidecar control connections use mutual TLS 1.2 or newer with a verified client certificate. | [security](./security/) | | Isolate pods with NetworkPolicies | stable | on | Applies NetworkPolicies that restrict ingress to game servers and give the API pod an egress policy that allows private ranges. | [security](./security/) | -| Export the audit trail as CSV or JSON | beta | on | GET /admin/audit/export downloads the full audit trail for offline review. | [audit observability admin](./audit-observability-admin/) | -| Verify the audit hash chain for tampering | beta | on | GET /admin/audit/verify re-walks the SHA-256 chain and reports the first broken link, catching naive in-database edits and tail truncation. | [audit observability admin](./audit-observability-admin/) | -| Resolve client IPs through trusted proxies | beta | on | The API reads X-Forwarded-For only from peers inside api.trustedProxies, so audit records and per-IP limits use the real client address. | [security](./security/) | -| Run Gameplane pods with hardened security contexts | beta | on | Operator, API, agent and optional bridge pods run as uid 65532 with read-only root filesystems, RuntimeDefault seccomp and all capabilities dropped. | [security](./security/) | -| Redact GameServer password values in API responses | beta | on | Every API response carrying a GameServer replaces non-empty password values with a redaction marker and fails closed if the template cannot be read. | [server configuration](./server-configuration/) | -| Confine dashboard-managed credentials to labelled Secrets | beta | on | The API reads and deletes only Secrets carrying its own labels for auth providers and notification sinks, so a config write cannot aim at arbitrary Secrets. | [security](./security/) | -| Prune audit events past a retention age | beta | off | api.audit.retentionDays removes events older than N days, and the default of 0 keeps events forever. | [audit observability admin](./audit-observability-admin/) | -| Mirror audit events to stdout | beta | off | api.audit.stdout emits each audit event as a structured JSON log line for a cluster log aggregator. | [audit observability admin](./audit-observability-admin/) | -| Forward audit events to a webhook | beta | off | api.audit.webhook.url POSTs each event as JSON from a bounded best-effort buffer, with an optional Authorization header read from a Secret. | [audit observability admin](./audit-observability-admin/) | -| Deploy the bundled audit-syslog-bridge from Helm | beta | off | api.audit.webhook.syslogBridge.enabled deploys the bridge and points the audit webhook at it automatically. | [audit observability admin](./audit-observability-admin/) | -| Deliver audit events to syslog over TCP, TLS or UDP | beta | off | audit-syslog-bridge turns each audit JSON document into an RFC 5424 syslog record and sends it over TCP, TCP with TLS or UDP, with TCP recommended. | [audit observability admin](./audit-observability-admin/) | -| Stream audit batches to S3-compatible storage | beta | off | api.audit.s3 batches audit events as NDJSON objects, flushed at 100 events, 1 MiB or 5 seconds, to AWS S3, MinIO or a similar endpoint. | [audit observability admin](./audit-observability-admin/) | | Audit OIDC role assignments and mapping overrides | beta | off | Each OIDC role assignment, override and reset writes an audit event naming the provider, matched group and role transition. | [audit observability admin](./audit-observability-admin/) | -| Enforce restricted Pod Security on the games namespace | beta | off | podSecurity.enforceRestricted applies the restricted Pod Security Standard to the games namespace. | [security](./security/) | | Verify release signatures with the current cosign key | beta | n/a | The ECDSA P-256 cosign key verifies releases from the July 2026 rotation onward, and the retired Ed25519 key verifies earlier releases. | - | | Sign the audit chain with a keyed HMAC | planned | n/a | An HMAC-keyed audit chain with the key held outside the database is a candidate future hardening. | [roadmap](./roadmap/) | @@ -313,42 +206,22 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| | Store sink credentials in API-created Secrets | beta | on | Entering a sink's URL, ntfy topic or SMTP settings stores them in a Secret the API creates and labels, linked through configRef. | [notification sinks](./notification-sinks/) | -| Alert when a server becomes unhealthy or recovers | beta | on | server.unhealthy fires when a GameServer fails or loses its heartbeat, and server.recovered fires when it becomes healthy again. | [notification events payloads](./notification-events-payloads/) | -| Alert when a backup or restore fails | beta | on | backup.failed and restore.failed fire when a Backup or Restore enters the Failed phase. | [notification events payloads](./notification-events-payloads/) | -| Send a test event to a saved sink | beta | on | A POST to the sink test endpoint delivers a synthetic event synchronously and returns the real delivery outcome. | [notification sinks](./notification-sinks/) | -| Retry transient delivery failures | beta | on | Network errors and 5xx responses are retried twice with 2 and 8 second backoffs, while 4xx responses are not retried. | [notification sinks](./notification-sinks/) | -| Count deliveries in Prometheus metrics | beta | on | gameplane_notify_deliveries_total counts sent, failed, dropped and skipped deliveries per sink kind. | [production observability](./production-observability/) | -| Deliver notifications without blocking reconciliation or requests | beta | on | Notifications are sent from a bounded in-memory queue, so a slow or down sink never blocks reconciliation or an API request. | [notification sinks](./notification-sinks/) | -| Guard sink dials with the SSRF policy | beta | on | Every sink dial, over HTTP or SMTP, goes through the netguard IsAllowed policy and refuses link-local, unspecified, multicast and NAT64 destinations at dial time. | [notification sinks](./notification-sinks/) | -| Keep sink URLs out of delivery errors | beta | on | Delivery errors are sanitized so the sink URL, which often embeds a capability token, never appears in them. | [notification sinks](./notification-sinks/) | -| Label alerts with the install's instance name | beta | on | The Admin Settings instance name is sent as the instance field so alerts from different installs can be told apart. | [notification events payloads](./notification-events-payloads/) | -| Post structured JSON webhook payloads | beta | on | The generic webhook receives a JSON object with type, ts, kind, name, namespace, message, instance and test fields. | [notification events payloads](./notification-events-payloads/) | -| Send alerts to Discord, Slack, ntfy, SMTP or a generic webhook | beta | off | Admins add notification sinks in Admin Settings, and each sink kind receives its own payload format. | [notification sinks](./notification-sinks/) | | Use pre-created labelled Secrets for sinks | beta | n/a | A Secret made with kubectl or GitOps works when it carries the gameplane.local/notification-sink label and a matching configRef. | [notification sinks](./notification-sinks/) | -| Alert when a backup or restore succeeds | beta | off | backup.succeeded and restore.succeeded are opt-in events that a sink must select. | [notification events payloads](./notification-events-payloads/) | -| Send email alerts over SMTP with selectable TLS | beta | off | The smtp sink takes host, from, to and optional port, username, password and a TLS mode of starttls (default), implicit or none. | [notification sinks](./notification-sinks/) | +| Alert on unhealthy servers, failed backups and restores | beta | on | server.unhealthy fires when a GameServer fails or loses its heartbeat and server.recovered when it becomes healthy again, backup.failed and restore.failed fire when a Backup or Restore enters the Failed phase, and backup.succeeded and restore.succeeded are opt-in events that a sink must select. | [notification events payloads](./notification-events-payloads/) | +| Deliver alerts through a bounded queue with retries, test sends and metrics | beta | on | Notifications are sent from a bounded in-memory queue so a slow sink never blocks reconciliation or a request, network errors and 5xx responses are retried twice with 2 and 8 second backoffs, a POST to the sink test endpoint delivers a synthetic event, and gameplane_notify_deliveries_total counts sent, failed, dropped and skipped deliveries. | [notification sinks](./notification-sinks/) | +| Guard sink dials and keep sink URLs out of errors | beta | on | Every sink dial goes through the netguard IsAllowed policy and refuses link-local, unspecified, multicast and NAT64 destinations at dial time, and delivery errors are sanitized so a sink URL carrying a capability token never appears in them. | [notification sinks](./notification-sinks/) | +| Label alerts with the instance name and post JSON webhook payloads | beta | on | The Admin Settings instance name is sent as the instance field of each alert, and the generic webhook receives a JSON object with type, ts, kind, name, namespace, message, instance and test fields. | [notification events payloads](./notification-events-payloads/) | +| Send alerts to Discord, Slack, ntfy, SMTP or a generic webhook | beta | off | Admins add sinks in Admin Settings, each with its own payload format (Discord embed, Slack text, ntfy headers, SMTP plain text, webhook JSON), and SMTP takes a TLS mode of starttls (default), implicit or none; none only works for unauthenticated relays. | [notification sinks](./notification-sinks/) | ## Telemetry | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Send basic usage counts once a day | stable | on | The API sends its version, GameServer count and GameTemplate count once a day, with no names, namespaces or addresses. | [platform settings telemetry](./platform-settings-telemetry/) | -| Hold reports until an admin sees the first-login notice | stable | on | On a new install no report is sent until the first admin has seen the notice listing both tiers and the destination. | [platform settings telemetry](./platform-settings-telemetry/) | -| Turn basic telemetry off from Admin Settings | stable | on | Admin Settings telemetry toggles stop reports, and turning them back on resumes reporting without sending early. | [platform settings telemetry](./platform-settings-telemetry/) | -| Hard-disable telemetry at install time | stable | on | Setting api.telemetry.enabled to false stops all sending and hides the first-login notice, overriding the admin toggles. | [platform settings telemetry](./platform-settings-telemetry/) | -| Send extended usage reports with a random install ID | stable | on | The extended tier adds a random install ID, environment bands, per-module counts, feature flags and the UI language, all from fixed sets. | [platform settings telemetry](./platform-settings-telemetry/) | -| Send reports to the project default receiver | beta | on | An empty api.telemetry.endpoint sends reports to the project default receiver at telemetry.gameplane.net, and a custom endpoint replaces it. | [platform settings telemetry](./platform-settings-telemetry/) | -| Reset the install ID from Admin Settings | beta | on | An admin resets the pseudonymous install ID, and the install then looks new to the receiver. | [platform settings telemetry](./platform-settings-telemetry/) | -| Sign extended reports with an install key | beta | on | Extended reports carry an Ed25519 signature, so forged, unsigned, tampered or replayed reports are refused without changing stored data. | [platform settings telemetry](./platform-settings-telemetry/) | -| Run a bundled telemetry receiver from Helm | beta | off | api.telemetry.receiver.enabled deploys a receiver beside the install, with a PVC for its SQLite data. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Validate and aggregate incoming reports strictly | beta | off | The receiver decodes each report strictly, folds it into daily aggregates and expiring activity records, and never stores raw reports or source addresses. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Limit accepted reports per source per day | beta | off | INGEST_SOURCE_DAILY_LIMIT caps accepted reports per source per UTC day, with a default of 20. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Publish a public summary of five counts | beta | off | GET /v1/summary returns five fixed counts without credentials when PUBLIC_SUMMARY is true. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Browse the receiver dashboard behind a token | beta | off | The receiver dashboard on port 8081 starts only when DASHBOARD_TOKEN is at least 32 characters, and unauthenticated responses reveal nothing. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Scrape receiver metrics with a bearer token | beta | off | The receiver's /metrics on the dashboard listener accepts only the Bearer token and is absent from the public port. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Require proof of work on report ingestion | beta | off | INGEST_POW makes reporters solve a challenge whose difficulty rises with request rate, to deter bulk fabricated reports. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Expire receiver data on a retention schedule | beta | off | RETENTION_DAYS (default 730) and ACTIVITY_EXPIRY_DAYS (default 90) remove old aggregates and activity records on an hourly sweep. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | -| Pseudonymise install IDs with a pepper | beta | off | The receiver stores only an HMAC of each install ID keyed with ID_PEPPER, generated and kept in its database if unset. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Send daily usage counts with admin and install-time off switches | stable | on | The API sends its version, GameServer count and GameTemplate count once a day with no names, namespaces or addresses, holds reports until the first admin sees the first-login notice, and stops when turned off in Admin Settings or hard-disabled at install time. | [platform settings telemetry](./platform-settings-telemetry/) | +| Send extended usage reports with a resettable, signed install ID | beta | on | Extended reports add a random install ID, environment bands, per-module counts, feature flags and UI language from fixed sets, are signed with an Ed25519 install key, and go to the project default receiver unless a custom endpoint is set; admins can reset the install ID. | [platform settings telemetry](./platform-settings-telemetry/) | +| Run a bundled telemetry receiver from Helm | beta | off | api.telemetry.receiver.enabled deploys a receiver beside the install with a PVC for its SQLite data, which decodes reports strictly and keeps only daily aggregates and expiring activity records, expires old data on a retention schedule, and pseudonymises install IDs with a pepper. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Limit and proof-of-work gate report ingestion on the receiver | beta | off | INGEST_SOURCE_DAILY_LIMIT caps accepted reports per source per UTC day, with a default of 20, and INGEST_POW makes reporters solve a challenge whose difficulty rises with request rate. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | +| Expose receiver summary, dashboard and metrics | beta | off | GET /v1/summary returns five fixed counts without credentials when PUBLIC_SUMMARY is true, the receiver dashboard on port 8081 starts only when DASHBOARD_TOKEN is at least 32 characters, and /metrics accepts only the Bearer token. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | | Run a standalone telemetry provider | beta | n/a | A runbook covers deploying the receiver image, TLS, secrets, Cloudflare settings, metrics and backups for a provider serving other installs. | [telemetry provider kubernetes](./telemetry-provider-kubernetes/) | | Show a version-trend view in the receiver dashboard | in progress | n/a | A version-trend view in the telemetry dashboard is in progress under the spec 022 amendment T101 to T110. | [roadmap](./roadmap/) | @@ -356,15 +229,10 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| API Prometheus metrics on a private listener | stable | on | The API serves Prometheus metrics on a dedicated listener that the public port does not expose. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | -| Operator controller and fleet gauges | beta | on | The operator exports controller-runtime metrics and the gameplane_gameservers and gameplane_backups phase gauges. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | -| Per-server agent metrics | beta | on | Each game pod agent exposes gameplane_agent CPU, memory, disk and player gauges on a plain metrics port 9090. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Serve API, operator and agent Prometheus metrics | beta | on | The API serves Prometheus metrics on a private listener the public port does not expose, the operator exports controller-runtime metrics with the gameplane_gameservers and gameplane_backups phase gauges, and each game pod agent exposes gameplane_agent gauges on a plain metrics port 9090. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | | Admin system log viewer | beta | on | Admins follow API and operator logs in separate streams, filter them, and download raw records. | [system log viewer](./system-log-viewer/) | -| ServiceMonitor and PodMonitor scrape objects | beta | off | Helm can create Prometheus Operator objects that scrape the operator, API, telemetry receiver and agents. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | -| Operator PrometheusRule alerts | beta | off | Helm can ship operator reconcile, workqueue, GameServer Failed and Backup Failed alert rules. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | -| Operator Grafana dashboard | beta | off | Helm can ship a Grafana operator dashboard as a ConfigMap for sidecar auto-import. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | -| Packet capture from game pods | beta | off | Admins start opt-in, BPF-filtered PCAPNG captures on a running game pod and download the files. | [helm values reference](./helm-values-reference/) | -| Automatic deletion of expired captures | beta | off | Completed packet captures are deleted automatically after their retention window ends. | [helm values reference](./helm-values-reference/) | +| Ship ServiceMonitor, PrometheusRule and Grafana objects from Helm | beta | off | Helm can create Prometheus Operator ServiceMonitor and PodMonitor objects that scrape the operator, API, telemetry receiver and agents, ship operator reconcile, workqueue, GameServer Failed and Backup Failed alert rules, and ship a Grafana operator dashboard ConfigMap for sidecar auto-import. | [metrics alerts dashboards](./metrics-alerts-dashboards/) | +| Capture game pod packets and expire captures automatically | beta | off | Admins start opt-in, BPF-filtered PCAPNG captures on a running game pod and download the files, and completed captures are deleted automatically after their retention window ends. | [helm values reference](./helm-values-reference/) | ## Localization @@ -376,12 +244,10 @@ Status date: 2026-10-14 (v0.3.0, pre-v1). See the [roadmap](./roadmap/) for what | Capability | Maturity | Default | Description | Docs | |---|---|---|---|---| -| Install the panel from the Helm chart | stable | on | One helm upgrade --install installs the operator, API and dashboard. | [installation](./installation/) | -| CRD auto-apply on helm upgrade | stable | on | A pre-upgrade hook applies the Gameplane CRDs so every helm upgrade keeps the schema current. | [upgrades migrations](./upgrades-migrations/) | +| Install and upgrade the panel from the Helm chart | stable | on | One helm upgrade --install installs the operator, API and dashboard, and a pre-upgrade hook applies the Gameplane CRDs so every upgrade keeps the schema current. | [installation](./installation/) | | Read-only MCP server | beta | off | An optional MCP server lets AI assistants read GameServers, pods, events and logs and propose fixes without writing. | [helm values reference](./helm-values-reference/) | | Helper image overrides for air-gapped mirrors | beta | n/a | Helm lets operators retag the config-init and restic helper images to a private registry mirror. | [air gapped installation](./air-gapped-installation/) | | Rolling edge images | beta | off | Setting image.tag to edge runs the rolling build published on every master push. | [installation](./installation/) | | Local Kind development loop | beta | n/a | Make targets create a Kind cluster with a local OCI registry, load images and run the web dev server. | [local development setup](./local-development-setup/) | | Store API data in PostgreSQL | experimental | off | Runs the API against a PostgreSQL database instead of SQLite, but only in images built with the postgres build tag. | [database configuration](./database-configuration/) | -| Reuse an existing PVC for the API database | beta | off | Mounts a pre-existing PersistentVolumeClaim for the API SQLite database instead of creating one. | - | -| Reuse an existing PVC for the standalone panel key | beta | off | Mounts a pre-existing key-only PersistentVolumeClaim for generated standalone encryption keys. | - | +| Reuse an existing PVC for the API database or standalone panel key | beta | off | Mounts a pre-existing PersistentVolumeClaim for the API SQLite database, or a pre-existing key-only PersistentVolumeClaim for generated standalone encryption keys, instead of creating one. | - |