58 lines
5.2 KiB
Markdown
58 lines
5.2 KiB
Markdown
## Context
|
|
|
|
Platform already receives sequenced, durable runtime log batches and has a `game.scum` manifest that declares `scum.login` and `scum.logout` schemas. Those entries are queryable as logs but are not durable player-domain records. The new projection must remain local to a server instance, be safe to invoke as part of log ingestion, and not make raw network data browser-visible or persistent.
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
|
|
- Persist independent game-player records keyed by server instance and SCUM player ID, with aliases, bounded sessions, access attempts, and review-only security signals.
|
|
- Project success login/logout semantics atomically and idempotently from accepted log entries, with sequence/event keys for duplicates and timestamp ordering for stale updates.
|
|
- Derive server-isolated correlation identifiers using an HMAC secret and a normalized source value, while retaining only the derived value.
|
|
- Offer permission-scoped, server-authorized management APIs and console records that never return IP values, raw source identifiers, secrets, raw log lines, or automatic enforcement controls.
|
|
- Retain access attempts and signals for a configurable bounded period and preserve player identity/session summaries after evidence expiry.
|
|
|
|
**Non-Goals:**
|
|
|
|
- Platform-user accounts, credentials, game database reads/writes, skill/attribute editing, gifts, map trails, or any automatic ban/kick/punishment.
|
|
- Changes to Run channels, direct host/socket/database access, or browser access to raw semantic log bodies.
|
|
|
|
## Decisions
|
|
|
|
1. **Use server-local game identity.** `game_player` is unique on `(server_instance_id, game_player_id)`; it has no foreign key to `user`. This prevents platform-console authentication from being mistaken for SCUM identity. An alias table records renamed display names with first/last-seen times.
|
|
|
|
Alternative considered: use display name as the identifier. It cannot safely handle player renames or duplicate names.
|
|
|
|
2. **Project only accepted SCUM semantic events in the ingestion transaction.** The log sequence (`log_stream_id`, `seq`) is the projection idempotency key. Login/open-session changes only apply when their event time is not older than the player's latest projected event; a logout closes the latest matching open session no later than its event time. Duplicate batches perform no second projection.
|
|
|
|
Alternative considered: asynchronous parsing of raw log lines. It would duplicate declared parsing rules, complicate order guarantees, and retain unnecessary sensitive content.
|
|
|
|
3. **Store only an HMAC-derived, server-scoped network correlation key.** A server-specific HMAC domain separator plus a process secret produces the correlation key. The source is never saved in models, logs, DTOs, or signal evidence. A digest is useful only within the same server and cannot be compared across servers.
|
|
|
|
Alternative considered: hash the raw IP directly. Unsalted hashes are reversible for common address spaces and correlatable across servers.
|
|
|
|
4. **Treat failures and anomalies as review evidence.** Failed login/connection event payloads create bounded `game_access_attempt` records. A threshold (five failures for the same fingerprint within fifteen minutes) creates or refreshes an `excessive-failed-access` signal; multiple player IDs sharing one server-local fingerprint create a `possible-alt-account` signal. Signals include text status and evidence counts, and have no action API.
|
|
|
|
Alternative considered: automatic moderation. It is excluded because heuristic evidence requires an operator review.
|
|
|
|
5. **Use existing session authorization and console primitives.** New endpoints use existing server read authorization. The frontend fetches named API contracts and renders an ordinary full-width shared table/record list with explicit status labels, never raw logs or a new page-local visual system.
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- [A plugin payload omits a usable player ID] → Ignore the event for projection and retain normal log ingestion; validate only bounded known fields.
|
|
- [Late logout arrives after another login] → Close only a compatible open session whose start is no later than logout; never regress `lastSeenAt`.
|
|
- [Projection failure follows log body append] → Return the ingest error and retry the acknowledged range safely; event identity prevents duplicate records.
|
|
- [HMAC secret rotates] → Derived keys intentionally cease correlating across rotations; raw data is never recoverable. Deployment config keeps the secret stable during its intended retention window.
|
|
- [Evidence tables grow] → Perform retention pruning during projection/query and cap query limits.
|
|
|
|
## Migration Plan
|
|
|
|
1. Add model-first tables and repositories; existing installations begin with no projected players.
|
|
2. Deploy manifest schemas and Platform projection; only newly ingested declared events create records. Historical log backfill remains an explicit later operation.
|
|
3. Deploy APIs and console page after backend authorization is available.
|
|
4. Rollback by disabling the page and projection. Existing records contain no raw network data and can expire through normal retention cleanup.
|
|
|
|
## Open Questions
|
|
|
|
None. Initial thresholds and retention are conservative constants covered by tests and can become declared policy in a later change.
|