Files
browser/platform
..
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00
2026-07-11 14:56:10 +08:00

platform

Backend control plane for the game server management platform.

Responsibilities

  • Users, roles, permissions, sessions, and audit.
  • Game management plugin installation metadata and marketplace views.
  • Server instance records and lifecycle orchestration.
  • AI provider configuration and platform-mediated AI invocation.
  • Run registration, capabilities, jobs, artifacts, log stream metadata, and storage adapters.

Required Directory Plan

Implementation should use dedicated directories for:

  • api/: route wiring and HTTP/gRPC adapters.
  • dto/: request and response structures.
  • domain/: business types and aggregates.
  • model/: database models only.
  • repo/: repository interfaces and persistence implementations.
  • service/: use cases and orchestration.
  • protocol/: run, plugin, artifact, log, and AI contracts.
  • validator/: validation rules.
  • config/: configuration structures and loading.
  • shared/: small shared helpers.

Do not put DTOs, database models, or protocol structs inside handlers or service functions.

Development Baseline

Tooling:

  • Go 1.25.1.
  • Module: browser.local/platform.

Commands:

go test ./...
go run ./cmd/platform

Runtime configuration:

  • PLATFORM_ADDR: local listen address, default :8080.
  • PLATFORM_STORAGE_BACKEND: storage backend, default file; use memory only for tests or disposable local runs.
  • PLATFORM_MYSQL_DSN: MySQL DSN used when PLATFORM_STORAGE_BACKEND=mysql, for example platform:platform@tcp(127.0.0.1:3306)/platform?parseTime=true.
  • PLATFORM_DATA_DIR: default platform data directory, default .platform-data.
  • PLATFORM_METADATA_PATH: file-backed metadata snapshot path, default .platform-data/metadata.json.
  • PLATFORM_LOG_BODY_BACKEND: log body backend, default follows metadata backend except MySQL uses file; supported values are file and memory.
  • PLATFORM_LOG_DIR: segmented log body directory, default .platform-data/logs.
  • PLATFORM_ARTIFACT_DIR: private durable artifact body/transfer directory, default .platform-data/artifacts.
  • PLATFORM_BOOTSTRAP_ADMIN_EMAIL: optional initial platform administrator email.
  • PLATFORM_BOOTSTRAP_ADMIN_PASSWORD: optional one-time bootstrap password; the platform applies no default and persists only a password verifier.
  • PLATFORM_SECRET_ENVELOPE_KEY: external secret used to derive the AES-GCM component-key envelope key; use at least 32 random characters and keep it stable across restarts.
  • PLATFORM_BUILDER_DOCKER_BINARY: Docker-compatible CLI used by the platform builder, default docker.
  • PLATFORM_BUILDER_IMAGE: prebuilt, explicitly versioned or digest-pinned builder image, default browser-platform-distribution-builder:1.0.0; floating tags such as latest are rejected.
  • PLATFORM_BUILDER_SOURCE_DIR: read-only Run source snapshot containing go.mod; this is required for builder readiness.
  • PLATFORM_BUILDER_WORKSPACE_DIR: private per-plugin/per-job build workspace, default <PLATFORM_DATA_DIR>/distribution-builds.
  • PLATFORM_BUILDER_TIMEOUT_SECONDS: positive build deadline, default 1800.
  • PLATFORM_RUN_RELEASE_URL: public platform URL embedded into generated components, default https://scum.npc0.com.

Build the dedicated toolchain image before enabling distribution generation:

docker build --pull -t browser-platform-distribution-builder:1.0.0 distribution-builder
export PLATFORM_BUILDER_SOURCE_DIR=/absolute/path/to/read-only/run-source-snapshot
export PLATFORM_BUILDER_IMAGE=browser-platform-distribution-builder:1.0.0
go run ./cmd/platform

Each build runs in a separate read-only container. The platform mounts source and per-job input read-only, mounts only the job build/output directories writable, and passes the component auth key through a mode-0600 input file. The key is not sent through the machine-side job channel or Docker arguments. Production deployments may use an internal-registry image@sha256:... reference; the selected image must already exist in the Docker daemon because builds run with --pull never.

MySQL configuration example:

export PLATFORM_STORAGE_BACKEND=mysql
export PLATFORM_MYSQL_DSN='platform:platform@tcp(127.0.0.1:3306)/platform?parseTime=true'
export PLATFORM_LOG_BODY_BACKEND=file
export PLATFORM_LOG_DIR=.platform-data/logs
go run ./cmd/platform

MySQL is the platform metadata database here. It stores the platform metadata snapshot table and should later hold normalized users/plugins/servers/jobs/audit/log stream indexes. It is not the high-volume log body store; keep log bodies in segmented files locally, or add a future ClickHouse/Loki/OpenSearch/object-storage LogBodyStore adapter for production scale.

For local direct debugging, copy platform/.env.example to platform/.env, edit the values, and run:

go run ./cmd/platform

The platform process automatically reads root .env and platform/.env before loading configuration. Explicitly exported process environment values still take precedence over values in those files.

For Docker, the root docker-compose.yml sets platform data under /data/platform and mounts it through the platform-data named volume.

Current executable behavior includes the platform API, durable hashed auth/Run sessions with expiry/revocation/rotation, strict production route authorization, durable file-backed metadata, segmented log bodies, authenticated run control/job/log/artifact routes, plugin bridge dispatch, platform-mediated AI invocation, real typed dependency execution orchestration with reviewed plan digests, and target-fenced transactional Run self-update staging/health/rollback projections.

Client Manager lifecycle

Client Manager installations are durable aggregates separate from Run distributions and sessions. Their safe state projection is requested -> building -> available -> deploying -> installed -> registering -> online, with degraded, offline, updating, rolling_back, stopping, failed, and uninstalled recovery states. Deploy, control, update, rollback, revoke-session, retry, and uninstall are typed jobs; Platform persists intent before dispatch and gates each action by actor/server ownership, plugin profile, binding, endpoint capability, artifact target/revision, key generation, and lifecycle state.

Component registration uses the current client-manager key generation, a timestamped nonce, and a short-lived hashed component session. It never reuses a Run session or job lease. Key reset revokes old sessions/artifacts and marks the installation for current-generation rebuild/redeploy. Run reports only logical health, phase, and bounded execution evidence; host paths, PIDs, sockets, raw keys, and credential material are not operator or plugin projections. Production KMS/code-signing, private source credentials, and fleet rollout remain explicit non-goals.

Validated plugin runtime profiles and per-server runtime bindings are part of durable metadata. Server creation requires only the plugin type and server name; operators set a declared profile and complete logical bindings after creation, before any gated lifecycle/runtime action. Browser and plugin-facing responses expose readiness only, not binding values. Platform-owned Docker builds need no registered Run endpoint with distribution.build; component keys remain in platform-controlled per-job input. This change uses controlled secret references and an injectable AES-GCM component-key envelope. The built-in envelope key is a disposable-development compatibility fallback; deployments must set PLATFORM_SECRET_ENVELOPE_KEY. This is not a production vault/KMS or machine-side runtime resolver. Durable scheduling, process supervision, durable log/artifact bodies, bounded metrics/backups, declaration-backed remote adapter envelopes, typed dependency installation, and transactional Run self-update are implemented. Client-manager lifecycle, production signing/fleet rollout, external provider/storage adapters, production scaling/alerts, plugin lifecycle, and real AI-provider integration remain separate tasks.