Documentation

Backend Plugin Spec

API contracts, data schemas, and operational requirements for the ServerStats plugin.

# ServerStats Backend Plugin Integration This document outlines the backend capabilities the ServerStats plugin needs so it can push telemetry into the platform and retrieve insights for in-game surfaces. It covers API contracts, data schemas, security requirements, and operations considerations. ## 1. Goals & Assumptions - **Targets Minecraft Java network operators.** Plugin runs on Paper/Fabric servers living behind a proxy (Velocity/Bungee). Multiple shards per network. - **Data volume:** thousands of concurrent players; telemetry sent every 10–15 seconds. - **Two-directional:** plugin needs to *push* real-time events (players, chat, vault, shard health) and *pull* insights (alerts, retention plays, tasks). - **Zero-knowledge of infra:** plugin only knows shard name + API credentials; backend hydrates dashboards and automations. ## 2. Authentication & Provisioning | Flow | Description | API | | --- | --- | --- | | Provision API key | Admin presses “Create key” in Console. Key is scoped to a network + shard and now seeds a stable shard UUID the plugin must persist. | `POST /api/plugin-keys { shardId, label } → { apiKey, shardToken, shardUuid, shardSecret }` | | Plugin bootstrap | Plugin configured with `apiKey`, `shardToken`, `shardUuid`, `shardSecret`, `baseUrl`. On start it exchanges key for short-lived JWT. | `POST /api/plugin-auth { apiKey, shardToken, shardUuid, signature } → { accessToken, expiresIn }` | | Token refresh | Plugin refreshes before expiry. | `POST /api/plugin-auth/refresh` | Console operators can mint a key + shard UUID via the API or a curl invocation: ```bash curl -X POST https://console.serverstats.gg/api/plugin-keys \ -H "Authorization: Bearer <console-session-token>" \ -H "Content-Type: application/json" \ -d '{ "shardId": 2, "label": "Velocity Proxy" }' # → { "apiKey": "sk_a12...", "shardToken": "st_b77...", "shardUuid": "3f23f20c-7b5c-4f10-98a4-7a502c8f3275", "shardSecret": "1c2da..." } Before calling `/api/plugin-auth`, the plugin signs the payload using the `shardSecret`: ```bash payload='{ "apiKey": "sk_a12...", "shardToken": "st_b77...", "shardUuid": "3f23..." }' signature=$(echo -n "$payload" | openssl dgst -sha256 -hmac "1c2da..." | awk '{print $2}') curl -X POST https://ingest.serverstats.gg/api/plugin-auth \ -H "Content-Type: application/json" \ -d "{ \"apiKey\": \"sk_a12...\", \"shardToken\": \"st_b77...\", \"shardUuid\": \"3f23...\", \"signature\": \"$signature\" }" # → { "accessToken": "1db4...", "expiresIn": 900 } ``` Refresh uses the short payload: ```bash curl -X POST https://ingest.serverstats.gg/api/plugin-auth/refresh \ -H "Content-Type: application/json" \ -d '{ "accessToken": "1db4..." }' ``` ``` All plugin requests include: - `Authorization: Bearer <accessToken>` - `X-Signature: HMAC_SHA256(body, shardSecret)` - `X-Shard-ID` - `X-Shard-UUID` - `X-Plugin-Version` The plugin must also include the UUID and signature in any ping/backoff calls. Example health check (used by `/api/plugin/health`): ```bash curl https://ingest.serverstats.gg/api/plugin/health \ -H "Authorization: Bearer <accessToken>" \ -H "X-Shard-ID: 2" \ -H "X-Shard-UUID: 3f23f20c-7b5c-4f10-98a4-7a502c8f3275" \ -H "X-Signature: $(printf '' | openssl dgst -sha256 -hmac 1c2da... | awk '{print $2}')" ``` Every plugin request follows this envelope: 1. Compute `signature = HMAC_SHA256(body, shardSecret)` (sign an empty string for GETs). 2. Send `Authorization: Bearer <accessToken>` plus shard headers (`X-Shard-ID`, `X-Shard-UUID`). 3. Include `X-Plugin-Version` for rollout coordination. ## 3. Telemetry Ingest APIs ### 3.1 Players Snapshot ``` POST /api/ingest/players { "shardId": 2, "collectedAt": "2024-07-23T19:02:11.213Z", "online": 612, "queue": 23, "uniqueJoins": 84, "tps": 19.78, "latencyMs": 63, "topPlayers": [ { "playerId": 39102, "name": "QuartzLion", "sessionMinutes": 64, "vaultBalance": 684120, "netWorth": 1000200, "retentionRate": 82 } ] } ``` Backend persists payloads in `plugin_ingest_events` (type `players-snapshot`) and updates player summaries. ### 3.2 Player Stream Events | Event | Endpoint | Payload highlights | | --- | --- | --- | | Login/logout | `POST /api/ingest/player-events` | `{ eventType: "LOGIN"|"LOGOUT", playerId, uuid, ip, timestamp }` | | Chat | `POST /api/ingest/chat` | `{ channel: "PUBLIC"|"PRIVATE", fromPlayerId, toPlayerId?, message, sentimentScore }` | | Vault transaction | `POST /api/ingest/vault` | `{ txnId, playerId, amount, direction, counterpart }` | | Punishment | `POST /api/ingest/punishment` | `{ eventType: "BAN"|"MUTE"|..., moderator, expiresAt }` | ### 3.3 Economy & Performance ``` POST /api/ingest/performance { "shardId": 2, "collectedAt": "...", "ticksPerSecond": 19.6, "cpuPercent": 68, "memoryPercent": 72, "chunksLoaded": 4823, "hopperCount": 602 } ``` ``` POST /api/ingest/economy { "shardId": 2, "collectedAt": "...", "auctionVolume": 182000, "shopVolume": 92000, "emeraldInflux": 128000, "flaggedVolume": 12000 } ``` ## 4. Pull APIs (Plugin → Console) | Use case | Endpoint | Notes | | --- | --- | --- | | Fetch retention actions | `GET /api/plugin/shards/:id/retention-sprints` | Plugin shows tasks to staff (e.g., “Grant VIP crate to player X”). | | Live alerts | `GET /api/plugin/shards/:id/alerts?since=<timestamp>` | Returns flagged fraud, TPS drops, etc. | | Automation queue | `GET /api/plugin/shards/:id/automations` | For autop-run commands (kick bots, throttle farms). | | Player intelligence lookup | `GET /api/plugin/players/:playerId` | Serve `/inspect player` command in-game. | | Shop purchase hook | `POST /api/ingest/shop-purchase` | ShopGUI+, Tebex, or custom web store posts purchases here (player, sku, price, currency, paymentMethod, processor, orderId). Plugin can capture ShopGUI+ console logs and forward them. | Responses should be lightweight (small lists with `nextCursor` to support pagination). Implemented pull routes: - `GET /api/plugin/shards/:id/retention-sprints` - `GET /api/plugin/shards/:id/alerts?since=<timestamp>` - `GET /api/plugin/shards/:id/automations` - `GET /api/plugin/shards/:id/config` - `GET /api/plugin/players/:playerId` ## 5. Data Model Requirements - **Players:** full schema includes `id`, `uuid`, `name`, `shard_id`, `first_seen_at`, `last_login_at`, `playtime_minutes`, `session_count`, `retention_rate`, `risk_level`, `vault_balance`, `net_worth`, `discord_id?`, `country?`, `client_version`, `edition`, `linked_accounts(jsonb)`, `ranks(jsonb)`, `shop_purchases(jsonb)`, `flags(jsonb)` for automation tags. - **Player Sessions:** `id`, `player_id`, `shard_id`, `started_at`, `ended_at`, `duration_minutes`, `avg_tps`, `avg_latency`, `actions(jsonb)` for commands or triggers. - **Chat Stream:** `id`, `player_id`, `shard_id`, `channel`, `message`, `sentiment`, `toxicity_score`, `created_at`, `target_player_id?`. - **Vault Transactions:** `id`, `shard_id`, `player_id`, `amount`, `direction`, `currency`, `counterparty_type`, `counterparty_id`, `risk_flag`, `created_at`. - **Player Purchases:** `id`, `player_id`, `shard_id`, `sku`, `price`, `currency`, `source` (web/shop), `payment_method`, `processor` (Stripe, Tebex, BTC wallet), `order_id`, `receipt_metadata`, `created_at`. ShopGUI+ must emit events/logs so plugin forwards them to the backend within a few seconds of purchase. - **Ranks/Permissions:** `id`, `player_id`, `rank`, `tier`, `price`, `assigned_at`, `expires_at`. - **Linked Accounts:** `id`, `player_id`, `type` (ip, hardware, discord), `value`, `first_seen_at`, `last_seen_at`. - **Shard metrics:** time-series table with `players`, `uniqueJoins`, `tps`, `latency`, `sessions`, `cpu`, `memory`, `chunks`, `queue`. - **Shard identifiers:** `shard_identifiers` table to map numeric shard IDs to the immutable `shard_uuid` that plugins send back. Ensures every event + ingest payload can be deduplicated per shard even if IDs change. - **Plugin keys:** `plugin_keys` storing hashed `apiKey`, `shardToken`, `shardSecret`, binding user + shard. - **Plugin sessions:** `plugin_sessions` keeping active access tokens + expirations for `/api/plugin-auth`. - **Ingest log:** `plugin_ingest_events` capturing every POST body for observability + replay. - **Economy flows:** aggregated volumes + transaction ledger (`vault_transactions`). - **Chat stream:** persisted for 24h (for sentiment + risk). Should support ingestion backlog w/ `eventId` dedupe. ### 5.1 Database bootstrap command Run this against the `serverstats` MySQL schema (safe to run repeatedly thanks to `IF NOT EXISTS`): ```bash mysql -u serverstats_user -p serverstats <<'SQL' CREATE TABLE IF NOT EXISTS plugin_keys ( id INT NOT NULL AUTO_INCREMENT, shard_id INT NOT NULL, label VARCHAR(255) NULL, api_key_hash CHAR(64) NOT NULL, shard_token_hash CHAR(64) NOT NULL, shard_uuid CHAR(36) NOT NULL, shard_secret CHAR(64) NOT NULL, created_by INT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_used_at TIMESTAMP NULL, PRIMARY KEY (id), CONSTRAINT fk_plugin_keys_shard FOREIGN KEY (shard_id) REFERENCES shards(id) ON DELETE CASCADE, CONSTRAINT fk_plugin_keys_user FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS plugin_sessions ( id INT NOT NULL AUTO_INCREMENT, plugin_key_id INT NOT NULL, access_token CHAR(64) NOT NULL, expires_at DATETIME NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY idx_plugin_sessions_token (access_token), CONSTRAINT fk_plugin_sessions_key FOREIGN KEY (plugin_key_id) REFERENCES plugin_keys(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS plugin_ingest_events ( id BIGINT NOT NULL AUTO_INCREMENT, plugin_key_id INT NOT NULL, shard_id INT NOT NULL, shard_uuid CHAR(36) NOT NULL, event_type VARCHAR(64) NOT NULL, payload LONGTEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_plugin_ingest_shard (shard_id), CONSTRAINT fk_plugin_ingest_key FOREIGN KEY (plugin_key_id) REFERENCES plugin_keys(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; SQL ``` ## 6. Frontend View Data Contracts This section maps each page/component of the site to the datasets and API endpoints it needs. When implementing backend services, ensure these contracts stay stable so the React pages render without additional JOIN-heavy logic. ### 6.1 Marketing Landing Page (`/`) | Section | Data needs | Notes | | --- | --- | --- | | Hero | Static copy only. | No API needed. | | Feature grid | Hard-coded features. | None. | | Dashboard preview | Consumes `GET /api/marketing/dashboard-preview` returning demo scenarios with timelines, flows, retention, version mix, edition mix, etc. The payload should mirror real shards so marketing and console can share components. | | Pricing cards | Currently static tiers. For future dynamic pricing, expose `GET /api/marketing/pricing` with tier metadata. | | Payments highlight + Crypto card | No server data, but if we expose payment configs later, `GET /api/payments/providers`. | ### 6.2 Console Home (`/console`) | Module | Data requirements | Existing API | | --- | --- | --- | | Navbar + session | `GET /api/session` (user, avatar, plan). | Already available via Next auth utilities. | | Dashboard summary | `GET /api/dashboard/snapshot` returns: shards list, player timelines, unique timelines, TPS timelines, economy timelines, player leaderboard, vault summary, stats (avg session, peak players, new players). | | Console dashboard cards | Needs the same `snapshot` object. `PlayerCountCard`, `NumbersRow`, `EconomyFlowCard`, `TpsCard`, etc. rely on the data structure defined above. | | Alert Composer | `GET /api/alerts/templates`, `POST /api/alerts` to create. | | Retention sprints | `GET /api/retention-sprints`, `POST /api/retention-sprints/:id/complete`. | | Shop telemetry widget | `GET /api/shop/purchases?shardId=...&limit=20` to populate “recent buyers” or revenue charts. | ### 6.3 Shard Layout (`/shards/:id`) | Component | Data | Endpoint | | --- | --- | --- | | Shard header/tabs | Shard metadata (`id`, `name`, `status`, `region`, `latency`). | `GET /api/shards/:id` | | Dashboard tab | `GET /api/shards/:id/detail` containing: `playerTimelines`, `joinTimelines`, `tpsTimelines`, `economyTimelines`, `stats`, `vaultSummary`, `playerLeaderboard`, `playerSeries` used by AI summary. | | Economy tab | `GET /api/shards/:id/economy` (totals, flows, transactions). | | Players tab | `GET /api/shards/:id/players` returning table rows plus insights: engagement series, region stats, retention chart, version/edition distributions. | | Performance tab | `GET /api/shards/:id/performance` (uptime, restarts, series for TPS/latency/CPU/memory/chunks). | ### 6.4 Player Detail (`/players/:id`) Requires a consolidated payload: - `player` object with bio stats, shard info, vault/net worth, retention, last login. - `riskReasons`, `externalSignals`. - `ranks`, `riskLevel`, `recentVault` transactions, `shopPurchases`. - `linkedAccounts`, `ipHistory`. - `playerJourney` data: retention funnel, session timeline, cohort analysis. Expose via `GET /api/players/:id`. ### 6.5 Settings/Plugin Pages | Feature | Data | Endpoint | | --- | --- | --- | | API/Plugin keys | `GET /api/plugin-keys`, `POST /api/plugin-keys`, `DELETE /api/plugin-keys/:id`. Keys include shard binding + last used timestamp. | | Billing | `GET /api/billing/plan`, `POST /api/billing/checkout-session`. | | Audit log | `GET /api/audit?resource=plugin-key` etc. | ### 6.6 Marketing / Blog Add-ons (Future) If we later add testimonials, case studies, etc., prefer `GET /api/content/<slug>` so CMS data is centralized. ## 7. Reliability & Queuing - Plugin batches events (up to 100 records) to reduce HTTP chatter. - If backend returns `429` or network unavailable, plugin enqueues in disk-backed queue (3k messages). - Backend validates schema via JSON Schema; rejects invalid rows with descriptive error. - Provide `/api/plugin/health` so plugin can test connectivity. ## 8. Security - Rotate API keys; store hashed in DB. - Require TLS 1.2+. - Rate limits per shard (e.g., 600 requests/min). Plugin should respect `Retry-After`. - Audit log for key creation, revocation, plugin auth attempts. ## 9. Observability - Metrics: ingest throughput, error rate, latency per endpoint. - Dashboards for active shards, last-event timestamps, backlog depth. - Alerting for missing telemetry (e.g., no player snapshot in 2 minutes). ## 10. Roadmap Items 1. **Offline buffering:** plugin writes queue to disk at shutdown to avoid data loss during restarts. 2. **Command streaming:** allow console to push commands (e.g., `/alert staff`) via SSE/WebSocket. 3. **Schema versioning:** include `schemaVersion` in payloads; backend handles migrations. 4. **Plugin diagnostics endpoint:** `GET /api/plugin/shards/:id/config` to fetch server-specific instructions. ### 10.1 Command Stream Schema When command streaming ships (roadmap item #2), the backend will expose an SSE/WebSocket stream at `/api/plugin/shards/:id/commands`. Every message on that stream follows: ```json { "id": "cmd_e7f8615b", "type": "COMMAND", // COMMAND | MESSAGE | ALERT "command": "/alert staff", "payload": { "priority": "HIGH", "body": "TPS dipped below 18" }, "metadata": { "issuedAt": "2024-08-04T18:01:27.000Z", "expiresAt": "2024-08-04T18:06:27.000Z", "source": "console-user|automation" }, "ackToken": "ack_7b02cd0e" } ``` Plugins must ACK once a command finishes (or fails) via `POST /api/plugin/shards/:id/command-acks`: ```json { "ackToken": "ack_7b02cd0e", "status": "SUCCESS", // SUCCESS | FAILED "details": "Broadcasted to 4 staff members", "completedAt": "2024-08-04T18:01:32.921Z" } ``` Future metadata fields can be added without breaking consumers; unrecognized keys should be ignored. ## 11. Deliverables Checklist - [ ] REST API design approved (OpenAPI spec). - [ ] Authentication service (API keys + JWT exchange). - [ ] Ingest services for players, events, economy, performance. - [ ] Plugin-facing read APIs with pagination + filters. - [ ] Monitoring + rate limiting. - [ ] Developer docs & example plugin snippets (Java/Kotlin). Once these components exist, the plugin can reliably create/push data and pull insights, ensuring the backend is ready to support production networks.