111 lines
8.8 KiB
Markdown
111 lines
8.8 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
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`: 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 components, default `https://scum.npc0.com/`.
|
|
|
|
Build the dedicated toolchain image before enabling distribution generation:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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 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.
|