Files
browser/platform
npc0-hue a822e9250a Store SCUM facts in typed platform tables
Run pushes typed SCUM facts through POST /api/v1/run/scum/facts, but the
production router rejected that path before the signature middleware because
runServiceRequest listed individual Run channel prefixes, and MySQL kept SCUM
rows inside the whole metadata snapshot instead of platform tables.

- /api/v1/run/ is now the signed machine channel space while
  /api/v1/run/endpoints keeps normal bearer/admin authorization.
- MySQL gets real scum_user, scum_user_trajectory, scum_vehicle,
  scum_vehicle_trajectory and scum_vehicle_lock tables with parameterized
  per-row repositories instead of full snapshot rewrites. Snapshot-shaped
  tables from the unreleased interim build are replaced, and SCUM rows still
  inside a metadata snapshot are migrated once.
- Facts ingest verifies the target server plugin type and converges stale
  online users to offline after SCUMUserOfflineAfter.
- The plugin page and browser read one bounded /scum/surface response instead
  of five list calls per refresh.

Call-count budget for one server: per 5s facts batch, one SELECT plus one
INSERT/UPDATE per reported user and vehicle, one INSERT per moved trajectory
sample or new lock row, one bounded stale-user SELECT, and a trajectory
retention DELETE at most once per hour. One browser refresh issues one surface
request every 15s instead of five list requests.
2026-09-15 12:12:11 +08:00
..
2026-07-11 14:56:10 +08:00
2026-09-14 13:41:44 +08:00
2026-07-11 14:56:10 +08:00
2026-09-07 20:26:20 +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-09-07 20:26:20 +08:00

platform

Backend control plane for the game server management platform.

Responsibilities

  • Users, roles, permissions, and sessions.
  • 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; high-frequency Run endpoint/session state uses a sibling runtime snapshot to avoid rewriting the full metadata file on every heartbeat.
  • 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: persistent Run checkout location used by the platform builder. The checkout may be absent at startup; each Run build creates it when needed, fetches PLATFORM_BUILDER_SOURCE_REVISION, exports that revision into the isolated job workspace, injects package configuration, and then compiles.
  • PLATFORM_BUILDER_SOURCE_REPOSITORY: Run Git repository used when the checkout is absent or needs a build-time refresh.
  • PLATFORM_BUILDER_SOURCE_REVISION: branch, tag, or commit fetched for each Run build; defaults to main.
  • PLATFORM_BUILDER_WORKSPACE_DIR: private per-plugin/per-job build workspace, default <PLATFORM_DATA_DIR>/distribution-builds.
  • PLATFORM_BUILDER_CACHE_DIR: persistent Go build/module cache, default <PLATFORM_DATA_DIR>/distribution-build-cache; it contains no job inputs or component keys.
  • PLATFORM_BUILDER_TIMEOUT_SECONDS: positive build deadline, default 1800.
  • PLATFORM_RUN_RELEASE_URL: public platform URL embedded into generated Run packages, default https://scum.npc0.com/. It must be reachable from the target server; loopback and unspecified addresses are rejected.

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/run-checkout
export PLATFORM_BUILDER_SOURCE_REPOSITORY=git@git.npc0.com:admin343/run.git
export PLATFORM_BUILDER_SOURCE_REVISION=main
export PLATFORM_BUILDER_IMAGE=browser-platform-distribution-builder:1.0.0
go run ./cmd/platform

Each build runs in a separate read-only container. For Run, the platform first exports the fetched revision into a clean per-job source directory; source and per-job input are mounted read-only, only the job build/output directories are writable, and the component auth key is passed 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/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.

Validated plugin runtime profiles and per-server runtime bindings are part of durable metadata for advanced logical transports. Server creation requires only the plugin type and server name, and plugin-declared deployment/lifecycle actions must be enough for user-facing start/stop and generated Run package flows without forcing operators through a manual runtime-profile binding screen. 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-held per-job input. This change uses scoped 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, plugin lifecycle dispatch, and transactional Run self-update are implemented. Production signing/fleet rollout, external provider/storage adapters, and real AI-provider integration remain separate tasks.