feat: 完整游戏运维功能
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-07-17
|
||||
@@ -0,0 +1,75 @@
|
||||
## Context
|
||||
|
||||
The plugin JSON schema and TypeScript SDK already define discovery probes, lifecycle profiles, dependency probes/install plans, log sources, transports, and client-manager profiles. Platform manifest DTOs do not decode `runtimeProfiles`, `GamePlugin` does not store them, and durable snapshots omit `RuntimeBinding`, so those declarations and bindings disappear before they can drive a server workflow. The existing action gate also reports complete when no binding rows exist.
|
||||
|
||||
The platform uses typed domain/model records behind repository interfaces. File and MySQL backends durably serialize the same `StoreSnapshot`, while tests use `MemoryStore`. The web console consumes platform-owned safe DTOs and must never receive raw host paths, direct sockets, credentials, or secret storage values.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Preserve every supported safe runtime-profile declaration during manifest registration and durable reload.
|
||||
- Select exactly one declared lifecycle profile per server runtime binding and derive its required logical keys deterministically.
|
||||
- Create or update bindings through owner/admin-authorized APIs, persist them in every durable store, and expose only redacted readiness metadata.
|
||||
- Require a complete binding before lifecycle and runtime actions whose execution depends on the selected profile.
|
||||
- Make profile selection and binding completion available in the create-server and server-detail workflows.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- Storing raw credentials, direct sockets, or host filesystem paths in platform metadata.
|
||||
- Implementing a general secret vault, run-side path resolver, durable scheduler, process supervisor, log/artifact backend, dependency installer, self-update system, or client-manager deployment lifecycle.
|
||||
- Changing the independent run repository or declaring the wider production-readiness roadmap complete.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: Persist typed profiles on the installed plugin record
|
||||
|
||||
Platform will mirror the existing manifest/SDK runtime profile structures in domain, DTO, and model packages and copy them into `GamePlugin` at registration. File/MySQL snapshots already persist plugin records, so this preserves the immutable installed-version contract without reaching across repository roots or storing arbitrary manifest JSON.
|
||||
|
||||
Alternative considered: keep only the manifest artifact reference and re-read the artifact for every request. This was rejected because artifact availability is a separate lifecycle, it makes validation/reload behavior non-deterministic, and it leaves action gating dependent on external content.
|
||||
|
||||
### Decision 2: One server-scoped binding aggregate selects one lifecycle profile
|
||||
|
||||
Each server has one `RuntimeBinding` identified deterministically from its server ID. It records the plugin ID/version contract, selected lifecycle `profileKey`, profile mode, logical binding refs, derived missing keys, and readiness status. Required keys are derived from the selected lifecycle profile and the referenced discovery, dependency, log, transport, and client-manager declarations; callers cannot self-assert `complete` or `missingKeys`.
|
||||
|
||||
Alternative considered: one row per logical key. This was rejected for now because profile changes need atomic validation and readiness projection, while the existing repository abstraction has aggregate create/update semantics.
|
||||
|
||||
### Decision 3: Accept safe opaque values, return redacted metadata
|
||||
|
||||
Write requests accept logical references and `secret://` references only. Values containing raw absolute paths, URI sockets/DSNs, inline credentials, traversal, or other unsafe material are rejected. Read responses return each logical key with a `configured` boolean and `secret` boolean, never the stored value or internal secret-storage location. Missing reasons name only declared logical keys.
|
||||
|
||||
Alternative considered: return stored logical refs directly. This was rejected because even non-secret refs can encode topology or storage details and the browser does not need them to review readiness.
|
||||
|
||||
### Decision 4: Create workflow persists the binding before dispatch
|
||||
|
||||
Server creation requires a declared profile key and optional initial binding values. The service validates the plugin/profile, creates the server and its binding, verifies completeness, and only then queues install. If required keys are missing, the request fails with logical missing-key details and no install job is dispatched. Repository rollback is limited by the current non-transactional abstraction; validation is therefore completed before the first write, and a binding persistence failure prevents dispatch and is surfaced explicitly.
|
||||
|
||||
Existing stored servers without a binding remain readable but are action-gated with a safe `runtime profile is not configured` reason until an owner or platform admin configures one.
|
||||
|
||||
### Decision 5: Authorization reuses server ownership rules
|
||||
|
||||
Listing a binding uses server visibility; changing it requires server ownership or platform-admin authority. Plugin pages receive no direct binding mutation surface. Lifecycle services independently check binding readiness so bypassing the UI or runtime-action projection cannot dispatch work.
|
||||
|
||||
### Decision 6: Web forms use declared contract data
|
||||
|
||||
`GamePluginResponse` exposes safe runtime-profile declarations required for selection and labels. The create form renders the selected plugin's lifecycle profiles and declared logical keys, submits the real profile and bindings, and avoids path/socket/credential terminology. The server detail view loads the redacted binding, supports profile changes and logical-key updates, and shows safe missing reasons.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Snapshot writes are aggregate and not transactional across server and binding repositories] -> Perform all validation before writes, persist the binding before job dispatch, and add failure/reload tests; a later durable-job change can introduce transactions.
|
||||
- [Profile key derivation can over-require unrelated declarations] -> Scope derivation to the selected lifecycle profile and directly referenced transports/client manager, plus required global discovery/dependency/log targets.
|
||||
- [Opaque safe refs cannot prove run-side resolvability] -> Treat platform completeness as contract completeness only; run-side resolution/health remains a later lifecycle responsibility.
|
||||
- [Existing servers become gated after upgrade] -> Keep them readable and return a safe configuration-required reason; operators can select a profile in server detail.
|
||||
- [Changing an active server profile could invalidate running work] -> Reject binding updates while the server is installing or running; require a stable non-active state.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Deploy profile-aware decoding and snapshot fields with backward-compatible empty defaults.
|
||||
2. Existing plugin records without persisted profiles remain listable but cannot configure a runtime binding until the manifest is re-registered.
|
||||
3. Existing servers without bindings remain visible with lifecycle/runtime actions disabled.
|
||||
4. Re-register manifests, then configure each server binding through the authorized detail workflow.
|
||||
5. Rollback can ignore the additive JSON fields; no raw secret values are introduced by this change.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Transactional multi-resource creation and encrypted secret material persistence are deferred to the next security/persistence task rather than being represented as complete here.
|
||||
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
Plugin manifests already describe runtime profiles, but platform registration discards those declarations and runtime bindings live only in an in-memory repository that is absent from durable snapshots. As a result, server creation cannot select a real profile or persist its logical bindings, and action gating incorrectly treats a server with no bindings as complete.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Persist the complete safe runtime-profile contract from plugin manifest registration through domain, DTO, model, repositories, and durable file/MySQL snapshots.
|
||||
- Add authorized server runtime-binding APIs and service operations for listing and updating one selected profile with validated logical values or secret references.
|
||||
- Extend server creation to select a declared lifecycle profile and submit its initial logical bindings atomically with the instance workflow.
|
||||
- Gate lifecycle and distribution actions on the selected profile and its required binding keys, returning only safe logical missing reasons.
|
||||
- Add server creation and detail UI for choosing, reviewing, completing, and changing runtime bindings without displaying raw host paths, sockets, credentials, or secret storage details.
|
||||
- Add plugin, platform, persistence, API, and frontend regression coverage for manifest projection, reload durability, invalid/missing binding rejection, action gating, and non-disclosure.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `runtime-profile-bindings`: Persist plugin-declared runtime profiles and provide server-scoped profile selection, logical binding management, secure projections, and action readiness.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
|
||||
## Impact
|
||||
|
||||
- `plugins/`: manifest/SDK validation and fixtures remain the source contract and gain persistence-oriented regression coverage where needed.
|
||||
- `platform/`: runtime profile domain/DTO/model validation, store snapshots, server lifecycle creation, binding services/routes, authorization, and action gating.
|
||||
- `platform_web/`: API contracts, create-server form, server-detail binding workflow, and focused tests.
|
||||
- Public platform API requests and responses gain runtime profile and binding fields/routes; no raw machine location or credential data crosses into the web or plugin page boundary.
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Platform persists plugin runtime profiles
|
||||
The platform SHALL decode, validate, store, and return safe plugin runtime profiles covering server discovery, lifecycle, dependencies and install plans, log sources, transports, and client-manager declarations.
|
||||
|
||||
#### Scenario: Manifest registration survives reload
|
||||
- **WHEN** an operator registers a valid plugin manifest with runtime profiles and the durable store is reopened
|
||||
- **THEN** the installed plugin retains the same validated runtime-profile contract
|
||||
|
||||
#### Scenario: Unsafe runtime declaration is rejected
|
||||
- **WHEN** a manifest runtime profile includes a raw host path, direct socket, credential, secret value, or arbitrary shell content
|
||||
- **THEN** registration fails without persisting the unsafe declaration
|
||||
|
||||
### Requirement: Server selects a declared runtime profile
|
||||
Each server runtime binding SHALL select a lifecycle profile declared by its installed plugin and SHALL derive required logical keys from that profile and its referenced runtime declarations.
|
||||
|
||||
#### Scenario: Valid profile selection
|
||||
- **WHEN** an authorized operator selects a declared lifecycle profile for a server
|
||||
- **THEN** the platform stores the server, plugin, profile, mode, derived required keys, and readiness state
|
||||
|
||||
#### Scenario: Undeclared profile is rejected
|
||||
- **WHEN** a caller selects a profile key or logical binding key not declared by the server's plugin
|
||||
- **THEN** the platform rejects the request without changing the stored binding
|
||||
|
||||
### Requirement: Runtime bindings are durable and authorized
|
||||
The platform SHALL persist runtime bindings in memory, file, and MySQL-backed repository contracts and SHALL authorize server-scoped reads and owner/admin-scoped changes.
|
||||
|
||||
#### Scenario: Binding survives durable reload
|
||||
- **WHEN** a valid binding is written through a durable store and the store is reopened
|
||||
- **THEN** the selected profile and readiness metadata remain available for that server
|
||||
|
||||
#### Scenario: Unauthorized binding update
|
||||
- **WHEN** a user who is neither platform admin nor server owner attempts to change a server binding
|
||||
- **THEN** the platform denies the update and leaves the binding unchanged
|
||||
|
||||
### Requirement: Binding projections do not disclose runtime details
|
||||
Runtime binding responses SHALL expose only profile metadata, declared logical keys, configured/secret flags, missing keys, status, and timestamps; they MUST NOT expose stored values, raw host paths, direct sockets, credentials, DSNs, or internal secret-storage locations.
|
||||
|
||||
#### Scenario: Secret reference is configured
|
||||
- **WHEN** a stored logical binding uses a secret reference
|
||||
- **THEN** the API reports that the logical key is configured and secret-backed without returning the reference value
|
||||
|
||||
#### Scenario: Missing logical binding is reviewed
|
||||
- **WHEN** a required logical key is absent
|
||||
- **THEN** the API and web console display the logical key and a safe configuration reason without storage details
|
||||
|
||||
### Requirement: Actions require a complete runtime binding
|
||||
The platform SHALL gate lifecycle and runtime-dependent actions on the presence of a valid, complete runtime binding for the server's current plugin and selected profile.
|
||||
|
||||
#### Scenario: No binding is not complete
|
||||
- **WHEN** a server has no runtime binding
|
||||
- **THEN** lifecycle and runtime-dependent actions are disabled or rejected with a safe profile-not-configured reason
|
||||
|
||||
#### Scenario: Missing binding blocks dispatch
|
||||
- **WHEN** a selected profile has one or more missing required logical keys
|
||||
- **THEN** the platform does not dispatch the requested action and reports only the missing logical keys
|
||||
|
||||
#### Scenario: Complete binding permits normal validation
|
||||
- **WHEN** the selected profile has all required logical keys configured
|
||||
- **THEN** action handling proceeds to existing permission, endpoint capability, state, and idempotency checks
|
||||
|
||||
### Requirement: Server creation submits a real profile and bindings
|
||||
The server creation workflow SHALL require a declared runtime profile and SHALL persist validated initial bindings before dispatching the install job.
|
||||
|
||||
#### Scenario: Complete create request
|
||||
- **WHEN** an operator submits a server, declared profile, and all required logical bindings
|
||||
- **THEN** the platform persists the server and binding and queues the install job with the selected profile context
|
||||
|
||||
#### Scenario: Incomplete create request
|
||||
- **WHEN** a create request omits a required logical binding
|
||||
- **THEN** the platform rejects creation before dispatch and identifies only the missing logical key
|
||||
|
||||
### Requirement: Operators can review and amend bindings
|
||||
The management console SHALL derive profile choices and logical binding inputs from plugin declarations and SHALL provide a server-detail workflow to review or amend the selected profile and binding completeness.
|
||||
|
||||
#### Scenario: Create form submits selected contract
|
||||
- **WHEN** an operator selects a plugin and profile and completes declared logical fields
|
||||
- **THEN** the web client submits the actual profile key and binding map in the create workflow request
|
||||
|
||||
#### Scenario: Detail workflow updates bindings safely
|
||||
- **WHEN** an authorized operator changes a stopped or draft server's profile or logical bindings
|
||||
- **THEN** the console saves through the runtime-binding API and refreshes the redacted readiness projection
|
||||
|
||||
#### Scenario: UI does not render sensitive runtime data
|
||||
- **WHEN** a binding response is rendered in create or detail workflows
|
||||
- **THEN** the UI contains no secret value, raw path, socket, DSN, or internal storage reference
|
||||
@@ -0,0 +1,32 @@
|
||||
## 1. Runtime Profile Contract
|
||||
|
||||
- [x] 1.1 Add typed runtime profile declarations to platform domain, DTO, model, copy, and response projections.
|
||||
- [x] 1.2 Validate profile keys, references, capabilities, safe strings, and cross-profile references during manifest registration.
|
||||
- [x] 1.3 Persist registered runtime profiles through file/MySQL snapshots and prove reload behavior with tests.
|
||||
|
||||
## 2. Runtime Binding Persistence and API
|
||||
|
||||
- [x] 2.1 Add runtime binding snapshot persistence and repository reload coverage.
|
||||
- [x] 2.2 Implement required logical-key derivation and binding validation against the selected plugin profile.
|
||||
- [x] 2.3 Implement authorized list/update binding services and redacted DTO projections.
|
||||
- [x] 2.4 Add documented server runtime-binding routes and API authorization/non-disclosure tests.
|
||||
|
||||
## 3. Lifecycle and Action Gating
|
||||
|
||||
- [x] 3.1 Extend server creation DTO/domain flow with a required profile key and initial logical bindings.
|
||||
- [x] 3.2 Persist the binding before install dispatch and reject incomplete or undeclared create inputs.
|
||||
- [x] 3.3 Gate start/stop and runtime-dependent actions on a present, current, complete binding with safe reasons.
|
||||
- [x] 3.4 Add service/API regressions for missing/invalid bindings, successful dispatch, and reload survival.
|
||||
|
||||
## 4. Management Console
|
||||
|
||||
- [x] 4.1 Add frontend API types/client methods and form contracts for runtime profiles and redacted bindings.
|
||||
- [x] 4.2 Connect plugin profile selection and declared logical binding inputs to the create-server workflow.
|
||||
- [x] 4.3 Add a server-detail review/update workflow with safe missing reasons and no runtime value disclosure.
|
||||
- [x] 4.4 Add frontend regressions proving real request submission, review/update behavior, and secret/path/socket non-disclosure.
|
||||
|
||||
## 5. Verification and Documentation
|
||||
|
||||
- [x] 5.1 Update platform, plugin, and web API/domain documentation for persisted profile and binding behavior without claiming later roadmap readiness.
|
||||
- [x] 5.2 Run plugin manifest/SDK tests, platform Go tests, platform_web tests/typecheck/build, and risk-relevant run tests if run changes are required.
|
||||
- [x] 5.3 Run `openspec validate persist-runtime-profiles-and-server-bindings --strict` and `scripts/check-structure.sh`, then record only evidence-backed completion.
|
||||
Reference in New Issue
Block a user