Implement SCUM direct data plane

This commit is contained in:
npc0-hue
2026-08-13 16:33:11 +08:00
parent b07a792784
commit 8b236d7c15
56 changed files with 1466 additions and 90 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-13
@@ -0,0 +1,57 @@
## Context
SCUM database schema, log grammar, and configuration files change with the game. The present Platform implementation identifies SCUM row types from query-key substrings and shapes data into fixed projection structs. That puts version-specific knowledge in the wrong component and forces a Platform update for routine game changes.
The supplied SCUM v57 sample confirms the required real sources: SQLite tables (`user_profile`, `prisoner`, `squad`, `squad_member`, `vehicle_spawner`, `base`, timed gifts/tasks), UTF-16LE server logs, and INI/JSON configuration. Platform needs durable, queryable `scum_*` records; Run remains an independent generic executor and is not changed in this repository.
## Goals / Non-Goals
**Goals:**
- Package SCUM v57 SQL, log grammar, and configuration mappings with the SCUM plugin.
- Make manifest validation accept safe package-relative SQL references and declarative row destinations while rejecting browser-provided or inline SQL.
- Make Platform ingest typed result rows through declaration metadata and upsert relational `scum_*` tables without SCUM query-name dispatch.
- Provide users, squads, activity, gifts, and map data to the management console from those persisted tables.
**Non-Goals:**
- Adding a `run/` tree, implementing Run-side executors, or adding SCUM game details to Run.
- Parsing a SCUM database from the browser or exposing host paths/raw SQL to browser users.
- Supporting every historical SCUM database version in the initial pack, changing lifecycle management, or adding unrelated product areas.
## Decisions
### Plugin package owns version-specific declarations
Each SCUM query template declares a package-relative `sqlRef`, `targetTable`, `upsertKeys`, and optional column mapping. SQL source is a `.sql` package asset named for SCUM database version. Logs/configuration use package assets with explicit encoding/format metadata.
This gives a SCUM version update one editable location: the plugin package. Inline SQL remains invalid so the browser continues to request only named templates and typed parameters. Storing SQL in Platform would reproduce the current coupling; accepting arbitrary browser SQL would make the contract unauditable.
### Platform performs generic declaration-driven ingestion
The execution path resolves a registered plugin declaration, validates the reported columns/keys, and applies its rows to the named `scum_*` relation. The generic layer never infers destination type by matching `player`, `squad`, or other SCUM words in a query key.
Tables are deliberately shaped for the first console features: sync runs, users, squads, squad members, vehicles, flags, map points, activity events, gift catalogs/grants, and configuration files. A generic JSON payload retains plugin-version fields not promoted to columns, avoiding a Platform release for every added SCUM field.
### APIs and console read persisted projections only
Platform dataset endpoints list scoped persisted rows. The console renders the five requested real datasets and uses empty states until a sync exists; it does not invent demo state or query SQLite directly.
## Risks / Trade-offs
- [SCUM schema drift invalidates a SQL asset] -> Version the asset directory, identify its schema version in the plugin manifest, and return a typed sync error rather than corrupting a table.
- [A mapping declares an unexpected relation] -> Manifest validation limits targets to `scum_*`, validates relative asset paths, key names, and declared columns before plugin registration.
- [Initial normalized tables omit a future game field] -> Preserve unmapped source values in row payload JSON and add columns only when they become a first-class console field.
- [Existing fixed projections have callers] -> Retain compatibility responses while migrating callers, then remove string-key dispatch in the same change after tests cover declaration-driven ingestion.
## Migration Plan
1. Register the new manifest schema and v57 package assets alongside existing declarations.
2. Add relational `scum_*` repository models/migrations and generic ingest APIs.
3. Switch SCUM sync result handling and console APIs to the declarations.
4. Verify against fixture rows derived from the supplied SCUM v57 database/log/config corpus.
5. Roll back by deploying the previous Platform and plugin version; existing `scum_*` rows are additive and can be ignored by the old runtime.
## Open Questions
- The first pack uses `pragma user_version = 57`; future versions will be added as plugin package assets when their actual schema is supplied.
@@ -0,0 +1,29 @@
## Why
The current SCUM integration keeps game-version SQL and data-shaping knowledge in Platform projections, which makes a SCUM update require coordinated changes across components. The management console needs to operate on actual SCUM v57 users, squads, activity, gifts, and map data with game-specific knowledge packaged alongside the SCUM plugin.
## What Changes
- Add a plugin-packaged SCUM data plane: versioned SQL files, log parser definitions, and configuration mappings referenced from the plugin manifest.
- Let Platform validate and distribute those declarations, accept typed result rows, and persist them in relational `scum_*` tables without dispatching on SCUM query-name substrings.
- Expose persisted SCUM user, squad, activity, gift, and map datasets through Platform APIs and the first-party game operations console.
- Replace the old hard-coded SCUM projection pathway with declaration-driven target-table and upsert metadata.
- **BREAKING** Plugin query-template declarations gain package-relative SQL references and row-target metadata; inline SQL remains invalid.
## Capabilities
### New Capabilities
- `scum-direct-data-plane`: Plugin-owned versioned SCUM data declarations, generic Platform ingestion, and `scum_*` persistence.
- `scum-operations-console`: First-party views and APIs for persisted SCUM users, squads, activity, gifts, and map points.
### Modified Capabilities
<!-- None. -->
## Impact
- `plugins/`: SCUM manifest/schema/validator/tests and versioned SQL, log, and config packages.
- `platform/`: plugin contracts, generic ingest service, relational repository models/migrations, and SCUM dataset APIs.
- `platform_web/`: server management SCUM data views using existing themed console conventions.
- No `run/` source is added; Run continues to perform only generic plugin-declared SQL and file jobs supplied by Platform.
@@ -0,0 +1,31 @@
## ADDED Requirements
### Requirement: Plugin-declared SCUM data packs
The system SHALL allow a SCUM plugin manifest to reference package-relative versioned SQL, log parser, and configuration mapping assets. Every query declaration that produces persisted SCUM rows MUST declare a `scum_*` target table and non-empty upsert keys; inline SQL and browser-supplied SQL MUST be rejected.
#### Scenario: v57 query declaration resolves a packaged statement
- **WHEN** the SCUM v57 plugin package declares a query with a relative `.sql` reference and row-target metadata
- **THEN** manifest validation accepts the declaration and distribution includes the referenced asset
#### Scenario: inline statement is rejected
- **WHEN** a manifest contains SQL text instead of a package-relative SQL reference
- **THEN** manifest validation rejects the manifest with a declaration error
### Requirement: Generic SCUM row ingestion
The system SHALL ingest rows returned for a registered SCUM data template according to that template's declared target table, upsert keys, and column mappings, without routing by a query-key substring.
#### Scenario: user rows are ingested
- **WHEN** a registered user template returns rows containing its declared key and columns
- **THEN** Platform upserts those rows into `scum_users` and records their plugin payload
#### Scenario: unsupported row target is rejected
- **WHEN** a registered data template names a target outside the allowed `scum_*` tables
- **THEN** Platform rejects the result before any dataset row is written
### Requirement: SCUM v57 source coverage
The initial SCUM pack SHALL include data declarations for users, squads and members, activity, gifts, and map points, plus parser/mapping declarations for supplied SCUM logs and configuration formats.
#### Scenario: operators inspect supplied source families
- **WHEN** the SCUM plugin package is assembled for database version 57
- **THEN** it contains SQL assets and declarations for all five console datasets and log/config parser assets
@@ -0,0 +1,19 @@
## ADDED Requirements
### Requirement: Persisted SCUM operations datasets
The system SHALL expose persisted SCUM users, squads, activity events, gifts, and map points through Platform APIs scoped to a server instance.
#### Scenario: a completed sync is queried
- **WHEN** an operator requests a SCUM dataset for an instance with persisted records
- **THEN** Platform returns only the corresponding persisted `scum_*` rows for that instance
### Requirement: SCUM operations console views
The first-party management console SHALL provide themed views for 用户, 队伍, 活动, 礼包, and 地图 using Platform's persisted SCUM dataset APIs, with an explicit empty state when no sync has completed.
#### Scenario: data is available
- **WHEN** an operator opens a SCUM-enabled server after a data sync
- **THEN** the console displays the returned persisted dataset without browser-side SQLite or log access
#### Scenario: no data is available
- **WHEN** an operator opens a SCUM-enabled server with no completed data sync
- **THEN** each dataset view displays an empty state rather than synthetic records
@@ -0,0 +1,20 @@
## 1. Plugin Data Pack
- [x] 1.1 Extend plugin manifest schema and validator with package-relative SQL references and declared SCUM row targets, keys, and mappings.
- [x] 1.2 Add tested SCUM v57 SQL assets for users, squads/members, activity, gifts, and map data.
- [x] 1.3 Add plugin-declared UTF-16LE log parser and INI/JSON configuration mapping assets for the supplied SCUM formats.
## 2. Platform Data Plane
- [x] 2.1 Replace SCUM query-key projection dispatch with declaration-driven row ingestion contracts and tests.
- [x] 2.2 Add scoped relational `scum_*` repository models/migrations and generic upsert/list operations for the first five datasets.
- [x] 2.3 Expose server-instance APIs for persisted users, squads, activity, gifts, and map points.
## 3. Operations Console
- [x] 3.1 Add themed server-management views and API clients for the five persisted SCUM datasets with real empty states.
## 4. Verification and Delivery
- [x] 4.1 Run manifest, Platform, frontend, OpenSpec strict, and structure checks; record evidence.
- [ ] 4.2 Stage only this change, commit on `main`, and push the configured remote.