1445 lines
54 KiB
Markdown
1445 lines
54 KiB
Markdown
# Corrosion — Platform Architecture & Specification
|
||
|
||
**Product:** Corrosion — Rust Server Management Platform
|
||
**Domain:** corrosionmgmt.com
|
||
**Author:** Vantz Stockwell — Vigil Cyber LLC
|
||
**Version:** 1.0
|
||
**Date:** February 14, 2026
|
||
|
||
---
|
||
|
||
## Executive Summary
|
||
|
||
Corrosion is a hosted SaaS platform that gives Rust server administrators a complete management interface — from wipe automation to plugin management to community storefronts — without requiring any technical infrastructure on their end. Customers install a single uMod plugin, register online, and manage everything from the web.
|
||
|
||
The platform eliminates the complexity that keeps casual server owners from running professional communities. One plugin. One dashboard. Everything works.
|
||
|
||
---
|
||
|
||
## Product Vision
|
||
|
||
**One sentence:** A Rust server admin installs one plugin, registers online, and never has to SSH into their box, edit a config file, or babysit a wipe again.
|
||
|
||
**The problem:** Running a Rust server well requires juggling multiple tools, editing JSON configs over SFTP, manually timing wipes, hand-installing plugins, and being online when things break. The barrier to entry is high, and even experienced admins waste hours on operational tasks instead of building their community.
|
||
|
||
**The solution:** Corrosion moves all server administration to a hosted web platform. The game server runs a lightweight plugin that communicates with Corrosion's cloud via NATS. Everything else — configuration, plugin management, wipe automation, player moderation, community websites, item stores — happens in the browser.
|
||
|
||
---
|
||
|
||
## Business Model
|
||
|
||
### Licensing
|
||
|
||
| Tier | Price | What They Get |
|
||
|------|-------|---------------|
|
||
| Base License | $50 one-time (CodeFling) | Core platform access: server management, auto-wiper, plugin installer, public site, analytics, RBAC, all Phase 1-3 features |
|
||
| Module Store | $9.99–$24.99 per module | Add-on modules (loot manager, event plugins, etc.) tied to their license key |
|
||
| Webstore Add-on | $10/month | Integrated item store with PayPal processing |
|
||
| Cloud Backup | $X/month | Off-server backup storage on Corrosion infrastructure |
|
||
| Site License (B2B) | $XXX/month | Hosting company integration — bulk licensing for all their Rust customers |
|
||
|
||
### License Rules
|
||
|
||
- One license = one server = one subdomain
|
||
- Multi-admin with unlimited team members per license (RBAC)
|
||
- License key validated on plugin startup and periodic check-in
|
||
- Module purchases are tied to the license key and unlocked instantly
|
||
- License is transferable (server owner sells their server, license goes with it)
|
||
|
||
---
|
||
|
||
## Platform Architecture
|
||
|
||
### High-Level Overview
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ CORROSION CLOUD │
|
||
│ │
|
||
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────┐ │
|
||
│ │ Web App │ │ REST API │ │ NATS Cluster │ │
|
||
│ │ (Vue 3) │ │ (Rust/Axum)│ │ (JetStream) │ │
|
||
│ │ │ │ │ │ │ │
|
||
│ │ Dashboard │ │ Business │ │ Real-time comms │ │
|
||
│ │ Public sites│ │ Logic │ │ Command delivery │ │
|
||
│ │ Module store│ │ License │ │ Stats streaming │ │
|
||
│ │ Status page │ │ Billing │ │ Health monitoring │ │
|
||
│ └──────┬──────┘ └──────┬──────┘ └─────────┬──────────┘ │
|
||
│ │ │ │ │
|
||
│ ┌──────┴────────────────┴────────────────────┴──────────┐ │
|
||
│ │ PostgreSQL │ │
|
||
│ └───────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌───────────────┐ ┌──────────────┐ ┌────────────────┐ │
|
||
│ │ Cloudflare │ │ Nginx │ │ File Storage │ │
|
||
│ │ DNS API │ │ Reverse │ │ (Maps, Backups│ │
|
||
│ │ (Subdomains) │ │ Proxy │ │ Modules) │ │
|
||
│ └───────────────┘ └──────────────┘ └────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
NATS (outbound from customer)
|
||
│
|
||
┌───────────────────┼───────────────────┐
|
||
│ │ │
|
||
┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐
|
||
│ Customer A │ │ Customer B │ │ Customer C │
|
||
│ │ │ │ │ │
|
||
│ Rust Server│ │ Rust Server│ │ Rust Server│
|
||
│ + Plugin │ │ + Plugin │ │ + Plugin │
|
||
│ + Companion│ │ (AMP) │ │ (Ptero) │
|
||
│ (Bare Metal│ │ │ │ │
|
||
└─────────────┘ └─────────────┘ └─────────────┘
|
||
```
|
||
|
||
### Connection Model
|
||
|
||
All connections are **outbound from the customer's server** to the Corrosion cloud. No inbound ports need to be opened on the customer's firewall.
|
||
|
||
**Panel users (AMP / Pterodactyl):**
|
||
- uMod plugin connects outbound to Corrosion NATS cluster
|
||
- Customer provides panel API credentials in the dashboard
|
||
- Corrosion API calls the panel API directly for server control and file operations
|
||
|
||
**Bare metal users:**
|
||
- uMod plugin connects outbound to Corrosion NATS cluster
|
||
- Companion agent (pre-configured binary downloaded from dashboard) connects outbound to Corrosion NATS cluster
|
||
- Companion handles server process control and filesystem operations locally
|
||
|
||
**In both cases:** The customer's dashboard experience is identical. The connection method is an implementation detail they configure once during setup and never think about again.
|
||
|
||
---
|
||
|
||
## Technology Stack
|
||
|
||
### Corrosion Cloud — Backend (Rust)
|
||
|
||
| Component | Crate | Purpose |
|
||
|-----------|-------|---------|
|
||
| Web Framework | `axum` | HTTP API, built on Tokio async runtime |
|
||
| Database | `sqlx` | Compile-time verified PostgreSQL queries |
|
||
| Messaging | `async-nats` | NATS client with JetStream support |
|
||
| Middleware | `tower-http` | CORS, authentication, rate limiting, logging |
|
||
| Password Hashing | `argon2` | Secure credential storage |
|
||
| JWT Auth | `jsonwebtoken` | Session and API token management |
|
||
| 2FA | `totp-rs` | TOTP-based two-factor authentication |
|
||
| Email | `lettre` | Transactional email (verification, alerts, backup codes) |
|
||
| Serialization | `serde` / `serde_json` | JSON serialization/deserialization |
|
||
| Scheduling | `tokio-cron-scheduler` | Cron-based scheduled tasks (wipes, restarts, etc.) |
|
||
| HTTP Client | `reqwest` | Panel API calls, Cloudflare API, Steam API, PayPal webhooks |
|
||
| Encryption | `aes-gcm` | Encrypt sensitive stored data (API keys, webhook URLs) |
|
||
| URL Signing | `hmac` / `sha2` | Signed URLs for file downloads |
|
||
|
||
### Corrosion Cloud — Frontend (Vue 3 + TypeScript)
|
||
|
||
| Component | Library | Purpose |
|
||
|-----------|---------|---------|
|
||
| Build Tool | Vite | Fast dev server and production builds |
|
||
| Routing | Vue Router | SPA client-side routing |
|
||
| State | Pinia | Reactive state management |
|
||
| Styling | Tailwind CSS | Utility-first CSS |
|
||
| Charts | Apache ECharts | Analytics and monitoring visualizations |
|
||
| Real-time | NATS WebSocket | Live server data in dashboard |
|
||
| Icons | Lucide | Clean icon set |
|
||
|
||
### Game Server — uMod Plugin (C#)
|
||
|
||
| Component | Library | Purpose |
|
||
|-----------|---------|---------|
|
||
| Framework | Oxide/uMod | Rust game server plugin API |
|
||
| Messaging | NATS.Client | Outbound NATS connection to Corrosion cloud |
|
||
| JSON | Newtonsoft.Json | Payload serialization |
|
||
| HTTP | RestSharp | REST API calls (license validation, file downloads) |
|
||
|
||
### Game Server — Companion Agent (Go)
|
||
|
||
| Component | Purpose |
|
||
|-----------|---------|
|
||
| NATS Client | Outbound connection to Corrosion cloud |
|
||
| Process Manager | Start/stop/restart Rust server process |
|
||
| File System | Read/write/delete server files, map swaps, config edits |
|
||
| Steam Update | Trigger SteamCMD updates |
|
||
| Self-Update | Pull new versions from Corrosion API |
|
||
|
||
### Infrastructure
|
||
|
||
| Service | Purpose |
|
||
|---------|---------|
|
||
| PostgreSQL 16 | Primary data store (multi-tenant) |
|
||
| NATS Cluster (JetStream) | Real-time messaging, command delivery, stats streaming |
|
||
| Nginx | Reverse proxy, subdomain routing, static file serving |
|
||
| Cloudflare | DNS management (subdomain provisioning via API), SSL, CDN, DDoS protection |
|
||
| Object Storage (S3-compatible) | Map library, cloud backups, module distribution |
|
||
|
||
---
|
||
|
||
## Multi-Tenant Data Architecture
|
||
|
||
Every customer record is scoped by `license_id`. All queries filter by license. No customer can ever see another customer's data.
|
||
|
||
### Database Schema
|
||
|
||
#### `licenses`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_key | VARCHAR(64) | Unique, generated on CodeFling purchase |
|
||
| status | VARCHAR(20) | 'active', 'suspended', 'expired', 'revoked' |
|
||
| owner_user_id | UUID | FK → users (the purchaser) |
|
||
| server_name | VARCHAR(100) | Display name for this server |
|
||
| subdomain | VARCHAR(63) | Unique subdomain on corrosionmgmt.com |
|
||
| custom_domain | VARCHAR(255) | Optional CNAME domain |
|
||
| modules_enabled | TEXT[] | List of module slugs activated on this license |
|
||
| webstore_active | BOOLEAN | Default false |
|
||
| webstore_subscription_id | VARCHAR(100) | PayPal subscription ID if active |
|
||
| created_at | TIMESTAMPTZ | |
|
||
| expires_at | TIMESTAMPTZ | Nullable — lifetime licenses have no expiry |
|
||
|
||
#### `users`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| email | VARCHAR(255) | Unique, verified |
|
||
| username | VARCHAR(50) | Unique display name |
|
||
| password_hash | TEXT | Argon2 hashed |
|
||
| totp_secret | TEXT | Encrypted, nullable |
|
||
| totp_enabled | BOOLEAN | Default false |
|
||
| backup_codes | TEXT[] | Encrypted |
|
||
| email_verified | BOOLEAN | Default false |
|
||
| created_at | TIMESTAMPTZ | |
|
||
| last_login_at | TIMESTAMPTZ | |
|
||
|
||
#### `team_members`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| user_id | UUID | FK → users |
|
||
| role_id | UUID | FK → roles |
|
||
| invited_by | UUID | FK → users |
|
||
| accepted_at | TIMESTAMPTZ | Nullable until accepted |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `roles`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses (null for system defaults) |
|
||
| role_name | VARCHAR(50) | e.g., "Owner", "Head Admin", "Moderator" |
|
||
| is_system_default | BOOLEAN | True for built-in roles |
|
||
| is_cloned_from | UUID | FK → roles, nullable |
|
||
| permissions | JSONB | Permission flags (see below) |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
**Default system roles:**
|
||
|
||
```json
|
||
{
|
||
"owner": {
|
||
"server.*": true,
|
||
"wipe.*": true,
|
||
"plugins.*": true,
|
||
"players.*": true,
|
||
"team.*": true,
|
||
"billing.*": true,
|
||
"store.*": true,
|
||
"settings.*": true,
|
||
"public_site.*": true
|
||
},
|
||
"head_admin": {
|
||
"server.*": true,
|
||
"wipe.*": true,
|
||
"plugins.*": true,
|
||
"players.*": true,
|
||
"team.view": true,
|
||
"team.invite": true,
|
||
"store.*": true,
|
||
"settings.server": true,
|
||
"public_site.*": true
|
||
},
|
||
"moderator": {
|
||
"server.view": true,
|
||
"server.console": true,
|
||
"players.kick": true,
|
||
"players.ban": true,
|
||
"players.chat_log": true,
|
||
"wipe.view": true,
|
||
"store.view": true
|
||
},
|
||
"viewer": {
|
||
"server.view": true,
|
||
"players.view": true,
|
||
"wipe.view": true,
|
||
"store.view": true
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `server_connections`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| connection_type | VARCHAR(20) | 'amp', 'pterodactyl', 'bare_metal' |
|
||
| panel_api_endpoint | TEXT | Nullable (not used for bare metal) |
|
||
| panel_api_key_encrypted | TEXT | Nullable |
|
||
| panel_server_identifier | VARCHAR(255) | Panel-specific server ID, nullable |
|
||
| companion_agent_token | VARCHAR(128) | Auth token for companion agent, nullable |
|
||
| companion_last_seen | TIMESTAMPTZ | Last heartbeat from companion |
|
||
| plugin_last_seen | TIMESTAMPTZ | Last heartbeat from uMod plugin |
|
||
| server_ip | VARCHAR(45) | |
|
||
| server_port | INTEGER | |
|
||
| game_port | INTEGER | |
|
||
| connection_status | VARCHAR(20) | 'connected', 'degraded', 'offline' |
|
||
| created_at | TIMESTAMPTZ | |
|
||
| updated_at | TIMESTAMPTZ | |
|
||
|
||
#### `server_config`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| server_name | VARCHAR(255) | In-game server name |
|
||
| max_players | INTEGER | |
|
||
| world_size | INTEGER | |
|
||
| current_seed | INTEGER | |
|
||
| current_map_id | UUID | FK → map_library, nullable |
|
||
| server_description | TEXT | |
|
||
| server_url | TEXT | |
|
||
| server_header_image | TEXT | |
|
||
| tags | TEXT[] | Server tags |
|
||
| auto_restart_enabled | BOOLEAN | Default false |
|
||
| auto_restart_cron | VARCHAR(100) | Cron expression for scheduled restarts |
|
||
| auto_restart_timezone | VARCHAR(50) | |
|
||
| crash_recovery_enabled | BOOLEAN | Default true |
|
||
| crash_recovery_max_attempts | INTEGER | Default 3 |
|
||
| crash_recovery_cooldown_minutes | INTEGER | Default 10 |
|
||
| force_wipe_eligible | BOOLEAN | Default true |
|
||
| auto_update_on_force_wipe | BOOLEAN | Default true |
|
||
| config_overrides | JSONB | Additional server.cfg key-value pairs |
|
||
| created_at | TIMESTAMPTZ | |
|
||
| updated_at | TIMESTAMPTZ | |
|
||
|
||
#### `game_admins`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| steam_id | VARCHAR(20) | Steam64 ID |
|
||
| display_name | VARCHAR(100) | |
|
||
| admin_level | VARCHAR(20) | 'owner', 'admin', 'moderator' |
|
||
| permissions | JSONB | Oxide permission flags |
|
||
| added_by | UUID | FK → users |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `wipe_profiles`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| profile_name | VARCHAR(100) | |
|
||
| description | TEXT | |
|
||
| pre_wipe_config | JSONB | Pre-wipe sequence settings |
|
||
| post_wipe_config | JSONB | Post-wipe verification settings |
|
||
| created_at | TIMESTAMPTZ | |
|
||
| updated_at | TIMESTAMPTZ | |
|
||
|
||
**`pre_wipe_config` JSONB structure:**
|
||
|
||
```json
|
||
{
|
||
"enabled": true,
|
||
"backup_before_wipe": true,
|
||
"countdown_warnings": [30, 15, 5, 1],
|
||
"countdown_unit": "minutes",
|
||
"countdown_messages": {
|
||
"30": "Server wipe in 30 minutes! Prepare yourselves!",
|
||
"15": "Server wipe in 15 minutes!",
|
||
"5": "Server wipe in 5 minutes! Wrapping up...",
|
||
"1": "Server wipe in 1 minute! See you on the other side!"
|
||
},
|
||
"kick_players_before_wipe": true,
|
||
"kick_message": "Server is wiping. Be back shortly!",
|
||
"run_final_save": true,
|
||
"discord_pre_announce": true,
|
||
"pushbullet_notify": true,
|
||
"custom_commands_before": []
|
||
}
|
||
```
|
||
|
||
**`post_wipe_config` JSONB structure:**
|
||
|
||
```json
|
||
{
|
||
"enabled": true,
|
||
"verify_server_started": true,
|
||
"verify_correct_map": true,
|
||
"verify_plugins_loaded": true,
|
||
"verify_player_slots_open": true,
|
||
"max_restart_attempts": 3,
|
||
"health_check_timeout_seconds": 120,
|
||
"discord_post_announce": true,
|
||
"pushbullet_notify": true,
|
||
"rollback_on_failure": true,
|
||
"post_wipe_commands": []
|
||
}
|
||
```
|
||
|
||
#### `wipe_schedules`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| wipe_profile_id | UUID | FK → wipe_profiles |
|
||
| schedule_name | VARCHAR(100) | |
|
||
| wipe_type | VARCHAR(20) | 'map', 'blueprint', 'full' |
|
||
| cron_expression | VARCHAR(100) | |
|
||
| timezone | VARCHAR(50) | |
|
||
| wipe_blueprints | BOOLEAN | Default false |
|
||
| is_active | BOOLEAN | Default true |
|
||
| next_scheduled_run | TIMESTAMPTZ | |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `map_library`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| filename | VARCHAR(255) | |
|
||
| display_name | VARCHAR(255) | |
|
||
| storage_path | TEXT | Path in object storage |
|
||
| file_size_bytes | BIGINT | |
|
||
| map_type | VARCHAR(20) | 'custom' or 'procedural' |
|
||
| seed | INTEGER | Nullable |
|
||
| world_size | INTEGER | Nullable |
|
||
| thumbnail_path | TEXT | Nullable |
|
||
| checksum | VARCHAR(64) | SHA-256 |
|
||
| uploaded_at | TIMESTAMPTZ | |
|
||
|
||
#### `map_rotations`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| map_id | UUID | FK → map_library |
|
||
| rotation_order | INTEGER | |
|
||
| is_active | BOOLEAN | Default true |
|
||
|
||
#### `plugin_registry`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| plugin_name | VARCHAR(255) | |
|
||
| plugin_version | VARCHAR(50) | |
|
||
| source | VARCHAR(20) | 'umod', 'corrosion_module', 'manual' |
|
||
| umod_slug | VARCHAR(255) | Nullable, for uMod-sourced plugins |
|
||
| is_installed | BOOLEAN | |
|
||
| is_loaded | BOOLEAN | Current runtime state from plugin report |
|
||
| config_json | JSONB | Plugin config (editable from dashboard) |
|
||
| data_path | TEXT | Relative path to plugin data |
|
||
| wipe_on_map | BOOLEAN | Default false |
|
||
| wipe_on_bp | BOOLEAN | Default false |
|
||
| wipe_on_full | BOOLEAN | Default false |
|
||
| never_wipe | BOOLEAN | Default false |
|
||
| installed_at | TIMESTAMPTZ | |
|
||
| updated_at | TIMESTAMPTZ | |
|
||
|
||
#### `wipe_history`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| wipe_schedule_id | UUID | FK → wipe_schedules, nullable |
|
||
| wipe_profile_id | UUID | FK → wipe_profiles |
|
||
| wipe_type | VARCHAR(20) | |
|
||
| trigger_type | VARCHAR(20) | 'scheduled', 'manual', 'force_wipe' |
|
||
| status | VARCHAR(20) | 'pending', 'pre_wipe', 'wiping', 'post_wipe', 'success', 'failed', 'rolled_back' |
|
||
| started_at | TIMESTAMPTZ | |
|
||
| completed_at | TIMESTAMPTZ | |
|
||
| map_used | VARCHAR(255) | |
|
||
| plugins_wiped | TEXT[] | |
|
||
| plugins_preserved | TEXT[] | |
|
||
| backup_reference | TEXT | Storage path to pre-wipe backup |
|
||
| error_message | TEXT | |
|
||
| execution_log | JSONB | Step-by-step log |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `scheduled_tasks`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| task_type | VARCHAR(30) | 'restart', 'announcement', 'command', 'plugin_reload' |
|
||
| task_name | VARCHAR(100) | |
|
||
| cron_expression | VARCHAR(100) | |
|
||
| timezone | VARCHAR(50) | |
|
||
| task_config | JSONB | Task-specific configuration |
|
||
| is_active | BOOLEAN | Default true |
|
||
| next_run | TIMESTAMPTZ | |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `notifications_config`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| discord_webhook_url | TEXT | Encrypted |
|
||
| discord_enabled | BOOLEAN | Default false |
|
||
| pushbullet_api_key | TEXT | Encrypted |
|
||
| pushbullet_enabled | BOOLEAN | Default false |
|
||
| email_alerts_enabled | BOOLEAN | Default true |
|
||
| notify_wipe_start | BOOLEAN | Default true |
|
||
| notify_wipe_complete | BOOLEAN | Default true |
|
||
| notify_wipe_failed | BOOLEAN | Default true |
|
||
| notify_server_crash | BOOLEAN | Default true |
|
||
| notify_server_offline | BOOLEAN | Default true |
|
||
| notify_store_purchase | BOOLEAN | Default true |
|
||
| notify_player_report | BOOLEAN | Default false |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `chat_logs`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| steam_id | VARCHAR(20) | Player Steam64 ID |
|
||
| player_name | VARCHAR(100) | |
|
||
| channel | VARCHAR(20) | 'global', 'team', 'server' |
|
||
| message | TEXT | |
|
||
| flagged | BOOLEAN | Default false |
|
||
| flagged_by | UUID | FK → users, nullable |
|
||
| flag_reason | TEXT | Nullable |
|
||
| created_at | TIMESTAMPTZ | Indexed |
|
||
|
||
#### `player_actions`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| steam_id | VARCHAR(20) | |
|
||
| player_name | VARCHAR(100) | |
|
||
| action_type | VARCHAR(20) | 'kick', 'ban', 'unban', 'warn', 'note' |
|
||
| reason | TEXT | |
|
||
| duration_minutes | INTEGER | Nullable (for timed bans) |
|
||
| performed_by | UUID | FK → users |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `server_stats`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| player_count | INTEGER | |
|
||
| max_players | INTEGER | |
|
||
| fps | FLOAT | |
|
||
| entity_count | INTEGER | |
|
||
| uptime_seconds | INTEGER | |
|
||
| memory_usage_mb | INTEGER | |
|
||
| recorded_at | TIMESTAMPTZ | Indexed, partitioned by time |
|
||
|
||
#### `server_stats_hourly`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| hour | TIMESTAMPTZ | Truncated to hour |
|
||
| avg_players | FLOAT | |
|
||
| max_players | INTEGER | |
|
||
| avg_fps | FLOAT | |
|
||
| min_fps | FLOAT | |
|
||
| avg_entities | INTEGER | |
|
||
| uptime_percentage | FLOAT | |
|
||
|
||
#### `public_site_config`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| site_enabled | BOOLEAN | Default true |
|
||
| show_on_status_page | BOOLEAN | Default false |
|
||
| steam_connect_url | VARCHAR(255) | |
|
||
| motd | TEXT | |
|
||
| public_mods | TEXT[] | Curated list of plugins to show |
|
||
| header_image_url | TEXT | |
|
||
| theme_color | VARCHAR(7) | Hex color |
|
||
| custom_css | TEXT | Nullable |
|
||
| discord_invite_url | TEXT | |
|
||
| show_player_count | BOOLEAN | Default true |
|
||
| show_wipe_schedule | BOOLEAN | Default true |
|
||
| show_wipe_countdown | BOOLEAN | Default true |
|
||
| show_mod_list | BOOLEAN | Default true |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `webstore_config`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| is_active | BOOLEAN | Default false |
|
||
| paypal_client_id | TEXT | Encrypted |
|
||
| paypal_secret | TEXT | Encrypted |
|
||
| paypal_mode | VARCHAR(10) | 'sandbox' or 'live' |
|
||
| store_name | VARCHAR(100) | |
|
||
| store_description | TEXT | |
|
||
| currency | VARCHAR(3) | Default 'USD' |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `webstore_categories`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| category_name | VARCHAR(100) | |
|
||
| display_order | INTEGER | |
|
||
| is_active | BOOLEAN | Default true |
|
||
|
||
#### `webstore_items`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| category_id | UUID | FK → webstore_categories |
|
||
| item_name | VARCHAR(100) | |
|
||
| description | TEXT | |
|
||
| price | DECIMAL(10,2) | |
|
||
| image_url | TEXT | |
|
||
| item_type | VARCHAR(20) | 'kit', 'rank', 'currency', 'custom_command' |
|
||
| delivery_config | JSONB | Commands to execute on delivery |
|
||
| is_active | BOOLEAN | Default true |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `webstore_transactions`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| item_id | UUID | FK → webstore_items |
|
||
| buyer_steam_id | VARCHAR(20) | |
|
||
| buyer_name | VARCHAR(100) | |
|
||
| amount | DECIMAL(10,2) | |
|
||
| currency | VARCHAR(3) | |
|
||
| paypal_transaction_id | VARCHAR(100) | |
|
||
| status | VARCHAR(20) | 'pending', 'paid', 'delivered', 'failed', 'refunded' |
|
||
| delivered_at | TIMESTAMPTZ | Nullable |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `migration_exports`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| license_id | UUID | FK → licenses |
|
||
| export_type | VARCHAR(20) | 'full', 'config_only', 'store_only' |
|
||
| storage_path | TEXT | Path to export archive |
|
||
| file_size_bytes | BIGINT | |
|
||
| created_by | UUID | FK → users |
|
||
| expires_at | TIMESTAMPTZ | Auto-delete after 7 days |
|
||
| created_at | TIMESTAMPTZ | |
|
||
|
||
#### `platform_changelog`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| version | VARCHAR(20) | |
|
||
| title | VARCHAR(200) | |
|
||
| body | TEXT | Markdown |
|
||
| category | VARCHAR(20) | 'feature', 'bugfix', 'module', 'security' |
|
||
| published_at | TIMESTAMPTZ | |
|
||
|
||
#### `module_store`
|
||
|
||
| Column | Type | Notes |
|
||
|--------|------|-------|
|
||
| id | UUID | PK |
|
||
| module_slug | VARCHAR(50) | Unique identifier |
|
||
| module_name | VARCHAR(100) | Display name |
|
||
| description | TEXT | |
|
||
| long_description | TEXT | Markdown |
|
||
| price | DECIMAL(10,2) | One-time price |
|
||
| price_type | VARCHAR(20) | 'one_time' or 'monthly' |
|
||
| monthly_price | DECIMAL(10,2) | Nullable |
|
||
| version | VARCHAR(20) | |
|
||
| download_path | TEXT | |
|
||
| thumbnail_url | TEXT | |
|
||
| screenshots | TEXT[] | |
|
||
| category | VARCHAR(50) | |
|
||
| is_active | BOOLEAN | Default true |
|
||
| created_at | TIMESTAMPTZ | |
|
||
| updated_at | TIMESTAMPTZ | |
|
||
|
||
---
|
||
|
||
## NATS Subject Architecture
|
||
|
||
All subjects are namespaced by license ID for multi-tenant isolation.
|
||
|
||
### Core Subjects
|
||
|
||
| Subject | Direction | Payload | Purpose |
|
||
|---------|-----------|---------|---------|
|
||
| `corrosion.{license_id}.heartbeat` | Plugin → Cloud | `{ timestamp, status, player_count, fps }` | Plugin health check (every 30s) |
|
||
| `corrosion.{license_id}.companion.heartbeat` | Companion → Cloud | `{ timestamp, status, disk_free, cpu }` | Companion health check (every 30s) |
|
||
| `corrosion.{license_id}.stats` | Plugin → Cloud | `{ players, fps, entities, uptime, memory }` | Server metrics (every 60s) |
|
||
| `corrosion.{license_id}.players.event` | Plugin → Cloud | `{ event, steam_id, name, ip }` | Player join/leave/death events |
|
||
| `corrosion.{license_id}.chat` | Plugin → Cloud | `{ steam_id, name, channel, message }` | Chat messages for logging |
|
||
| `corrosion.{license_id}.console` | Plugin → Cloud | `{ line, level, timestamp }` | Server console output stream |
|
||
|
||
### Command Subjects (Cloud → Game Server)
|
||
|
||
| Subject | Direction | Payload | Purpose |
|
||
|---------|-----------|---------|---------|
|
||
| `corrosion.{license_id}.cmd.server` | Cloud → Companion | `{ action: start/stop/restart }` | Server process control |
|
||
| `corrosion.{license_id}.cmd.console` | Cloud → Plugin | `{ command }` | Execute server command |
|
||
| `corrosion.{license_id}.cmd.console.response` | Plugin → Cloud | `{ command, output }` | Command result |
|
||
| `corrosion.{license_id}.cmd.announce` | Cloud → Plugin | `{ message }` | In-game broadcast |
|
||
| `corrosion.{license_id}.cmd.kick` | Cloud → Plugin | `{ steam_id, reason }` | Kick player |
|
||
| `corrosion.{license_id}.cmd.ban` | Cloud → Plugin | `{ steam_id, reason, duration }` | Ban player |
|
||
| `corrosion.{license_id}.cmd.plugin` | Cloud → Plugin | `{ action: load/unload/reload, name }` | Plugin management |
|
||
| `corrosion.{license_id}.cmd.deliver` | Cloud → Plugin | `{ steam_id, commands[] }` | Webstore item delivery |
|
||
|
||
### Wipe Subjects
|
||
|
||
| Subject | Direction | Payload | Purpose |
|
||
|---------|-----------|---------|---------|
|
||
| `corrosion.{license_id}.wipe.prepare` | Cloud → Plugin | `{ wipe_id, countdown_config }` | Start pre-wipe countdown |
|
||
| `corrosion.{license_id}.wipe.status` | Plugin → Cloud | `{ wipe_id, step, progress, message }` | Wipe progress updates |
|
||
| `corrosion.{license_id}.wipe.health` | Plugin → Cloud | `{ map, seed, plugins[], fps, slots }` | Post-wipe health report |
|
||
|
||
### File Operation Subjects (Cloud → Companion)
|
||
|
||
| Subject | Direction | Payload | Purpose |
|
||
|---------|-----------|---------|---------|
|
||
| `corrosion.{license_id}.files.get` | Cloud → Companion | `{ path }` | Read file from server |
|
||
| `corrosion.{license_id}.files.put` | Cloud → Companion | `{ path, download_url }` | Write file to server |
|
||
| `corrosion.{license_id}.files.delete` | Cloud → Companion | `{ path }` | Delete file from server |
|
||
| `corrosion.{license_id}.files.list` | Cloud → Companion | `{ path }` | List directory contents |
|
||
| `corrosion.{license_id}.files.response` | Companion → Cloud | `{ request_id, data/status }` | File operation result |
|
||
| `corrosion.{license_id}.update.steam` | Cloud → Companion | `{ validate: bool }` | Trigger SteamCMD update |
|
||
|
||
### JetStream Streams
|
||
|
||
| Stream | Subjects | Retention | Purpose |
|
||
|--------|----------|-----------|---------|
|
||
| HEARTBEATS | `corrosion.*.heartbeat`, `corrosion.*.companion.heartbeat` | Limits (1 hour) | Connection monitoring |
|
||
| STATS | `corrosion.*.stats` | Limits (24 hours) | Raw metrics for aggregation |
|
||
| EVENTS | `corrosion.*.players.event` | Limits (7 days) | Player events for analytics |
|
||
| CHAT | `corrosion.*.chat` | Limits (30 days) | Chat log retention |
|
||
| COMMANDS | `corrosion.*.cmd.*` | WorkQueue | Reliable command delivery |
|
||
| WIPE_EVENTS | `corrosion.*.wipe.*` | Limits (30 days) | Wipe audit trail |
|
||
|
||
---
|
||
|
||
## Wipe Execution Sequence
|
||
|
||
**CRITICAL DESIGN PRINCIPLE:** All file system operations are performed by the **Corrosion Cloud API** — either via the Panel API (AMP/Pterodactyl) or via the Companion Agent (bare metal) — while the server is **stopped**. The C# plugin handles only in-game operations and post-restart verification.
|
||
|
||
```
|
||
WIPE SEQUENCE
|
||
│
|
||
├── 1. PRE-WIPE [Plugin — server is RUNNING]
|
||
│ ├── Cloud sends wipe.prepare with countdown config
|
||
│ ├── Plugin broadcasts in-game countdown warnings
|
||
│ ├── Cloud sends Discord/Pushbullet pre-wipe notification
|
||
│ ├── Plugin executes custom pre-wipe commands
|
||
│ ├── Plugin kicks all players with configured message
|
||
│ ├── Plugin confirms all players disconnected
|
||
│ ├── Cloud triggers final server save (via console command)
|
||
│ └── Cloud stops server (via Panel API or Companion)
|
||
│
|
||
├── 2. WIPE EXECUTION [Cloud — server is STOPPED]
|
||
│ ├── Create backup (via Panel API or Companion file ops)
|
||
│ ├── Delete selected plugin data files per wipe settings
|
||
│ ├── Preserve protected plugin data (never_wipe = true)
|
||
│ ├── Handle blueprint wipe if configured
|
||
│ ├── Rotate to next map in rotation
|
||
│ │ ├── Custom map: transfer from Corrosion storage to server
|
||
│ │ └── Procedural: update seed/size values
|
||
│ ├── Update server.cfg with new map settings
|
||
│ └── Log every action to wipe_history
|
||
│
|
||
├── 3. SERVER RESTART [Cloud]
|
||
│ ├── If force wipe: trigger SteamCMD update first
|
||
│ ├── Start server (via Panel API or Companion)
|
||
│ └── Wait for plugin heartbeat on NATS (confirms server is up)
|
||
│
|
||
├── 4. POST-WIPE VERIFICATION [Plugin — server is RUNNING]
|
||
│ ├── Plugin publishes health report via NATS
|
||
│ ├── Cloud evaluates health against expected state
|
||
│ ├── Retry up to max_restart_attempts on failure
|
||
│ └── If all retries fail + rollback enabled:
|
||
│ └── Cloud executes rollback (stop → restore backup → start)
|
||
│
|
||
├── 5. POST-WIPE NOTIFICATION [Cloud]
|
||
│ ├── Update wipe_history record
|
||
│ ├── Discord/Pushbullet: wipe complete or failed
|
||
│ ├── Send in-game announcement via plugin
|
||
│ └── Log final status
|
||
│
|
||
└── DONE
|
||
```
|
||
|
||
---
|
||
|
||
## Steam Update Watcher
|
||
|
||
Background service in the Corrosion Cloud API that monitors for Rust Dedicated Server updates.
|
||
|
||
```
|
||
STEAM UPDATE WATCHER
|
||
│
|
||
├── Poll Steam Web API every 60 seconds
|
||
│ └── Check buildid for app 258550 (Rust Dedicated Server)
|
||
│
|
||
├── On buildid change detected:
|
||
│ ├── For each license with auto_update_on_force_wipe = true:
|
||
│ │ ├── If force_wipe_eligible: trigger full wipe sequence
|
||
│ │ └── If not: trigger update + restart only
|
||
│ └── Send notifications to all affected license holders
|
||
│
|
||
└── Store detected force wipe dates for calendar display
|
||
```
|
||
|
||
---
|
||
|
||
## Customer Onboarding Flow (Setup Wizard)
|
||
|
||
```
|
||
REGISTRATION & SETUP
|
||
│
|
||
├── 1. REGISTER
|
||
│ ├── Customer visits panel.corrosionmgmt.com/register
|
||
│ ├── Enters: email, username, password, license key
|
||
│ ├── Email verification sent
|
||
│ ├── License key validated against CodeFling purchase
|
||
│ └── Account created, redirected to setup wizard
|
||
│
|
||
├── 2. SETUP WIZARD — Step 1: Name Your Server
|
||
│ ├── Server display name
|
||
│ └── Choose subdomain: _______.corrosionmgmt.com
|
||
│ └── Cloudflare API creates DNS record immediately
|
||
│
|
||
├── 3. SETUP WIZARD — Step 2: How Is Your Server Hosted?
|
||
│ ├── Option A: Game Hosting Panel (AMP)
|
||
│ │ └── Enter AMP API endpoint + credentials → test connection
|
||
│ ├── Option B: Game Hosting Panel (Pterodactyl)
|
||
│ │ └── Enter Pterodactyl API endpoint + credentials → test connection
|
||
│ └── Option C: Bare Metal / Other
|
||
│ └── Download pre-configured companion agent
|
||
│
|
||
├── 4. SETUP WIZARD — Step 3: Install the Plugin
|
||
│ ├── Download WipeManager.cs (pre-configured with license token)
|
||
│ ├── Instructions: "Copy to oxide/plugins/ and restart your server"
|
||
│ └── Dashboard shows "Waiting for plugin connection..."
|
||
│ └── Plugin connects → green checkmark → "Server Online!"
|
||
│
|
||
├── 5. SETUP WIZARD — Step 4: Server Template (Optional)
|
||
│ ├── What kind of server are you running?
|
||
│ │ ├── Vanilla
|
||
│ │ ├── 2x Modded
|
||
│ │ ├── 5x Modded
|
||
│ │ ├── 10x Modded
|
||
│ │ ├── PvE
|
||
│ │ ├── Creative/Build
|
||
│ │ └── Custom (skip templates)
|
||
│ ├── Selected template auto-installs recommended plugins from uMod
|
||
│ └── Plugins installed with sensible default configs
|
||
│
|
||
├── 6. SETUP WIZARD — Step 5: Set Up Your First Wipe Schedule
|
||
│ ├── How often do you wipe? (weekly/bi-weekly/monthly)
|
||
│ ├── What day and time?
|
||
│ ├── Wipe blueprints? (yes/no)
|
||
│ └── Creates default wipe profile and schedule
|
||
│
|
||
└── 7. DONE → Dashboard
|
||
└── "Your server is live at servername.corrosionmgmt.com!"
|
||
```
|
||
|
||
---
|
||
|
||
## Subdomain & Routing Architecture
|
||
|
||
### URL Structure
|
||
|
||
| URL | Purpose |
|
||
|-----|---------|
|
||
| `panel.corrosionmgmt.com` | Main platform login and dashboard |
|
||
| `{servername}.corrosionmgmt.com` | Customer's public server site |
|
||
| `{servername}.corrosionmgmt.com/store` | Customer's webstore (if enabled) |
|
||
| `status.corrosionmgmt.com` | Public status page (opted-in servers) |
|
||
| `api.corrosionmgmt.com` | REST API endpoint |
|
||
| `nats.corrosionmgmt.com` | NATS cluster endpoint (plugin/companion connections) |
|
||
|
||
### Subdomain Provisioning
|
||
|
||
On license registration:
|
||
1. Customer chooses subdomain during setup wizard
|
||
2. Corrosion API calls Cloudflare API to create CNAME/A record
|
||
3. Nginx config dynamically routes based on subdomain → license_id lookup
|
||
4. SSL handled automatically by Cloudflare
|
||
|
||
For custom domains:
|
||
1. Customer adds CNAME record pointing their domain to `{servername}.corrosionmgmt.com`
|
||
2. Customer enters custom domain in dashboard settings
|
||
3. Corrosion API updates Cloudflare and Nginx routing
|
||
4. SSL provisioned via Cloudflare
|
||
|
||
---
|
||
|
||
## Security Model
|
||
|
||
### Authentication & Authorization
|
||
|
||
- User registration with email verification
|
||
- Argon2 password hashing
|
||
- JWT access tokens (15 min expiry) + refresh tokens (7 days)
|
||
- TOTP 2FA with encrypted backup codes
|
||
- RBAC enforced on every API endpoint
|
||
- License ownership verified on all license-scoped operations
|
||
|
||
### Data Isolation
|
||
|
||
- Every database query filters by `license_id`
|
||
- NATS subjects namespaced by `license_id` — subscriptions scoped per tenant
|
||
- File storage paths prefixed by `license_id`
|
||
- API middleware validates license ownership before any operation
|
||
|
||
### Secrets Management
|
||
|
||
- Panel API keys encrypted at rest (AES-256-GCM)
|
||
- Discord webhook URLs encrypted at rest
|
||
- Pushbullet API keys encrypted at rest
|
||
- PayPal credentials encrypted at rest
|
||
- Companion agent tokens are unique per license, rotatable from dashboard
|
||
|
||
### Plugin & Companion Authentication
|
||
|
||
- Plugin authenticates to NATS with license-specific token
|
||
- Companion authenticates to NATS with separate companion-specific token
|
||
- Both tokens are revocable from the dashboard
|
||
- License validation on plugin startup and periodic check-in (every 6 hours)
|
||
- Invalid/expired license → plugin enters read-only mode (stats only, no commands)
|
||
|
||
---
|
||
|
||
## Crash Recovery System
|
||
|
||
```
|
||
CRASH DETECTION
|
||
│
|
||
├── Plugin heartbeat stops (no message for 90 seconds)
|
||
│ └── Cloud marks server as "unresponsive"
|
||
│
|
||
├── Companion heartbeat confirms server process is dead
|
||
│ └── OR Panel API confirms server is stopped
|
||
│
|
||
├── If crash_recovery_enabled = true:
|
||
│ ├── Attempt 1: Restart server
|
||
│ │ └── Wait for plugin heartbeat (timeout: 120s)
|
||
│ ├── Attempt 2: Restart server
|
||
│ │ └── Wait for plugin heartbeat (timeout: 120s)
|
||
│ ├── Attempt 3: Restart server
|
||
│ │ └── Wait for plugin heartbeat (timeout: 120s)
|
||
│ └── All attempts failed:
|
||
│ ├── Mark server as "crashed — manual intervention required"
|
||
│ └── Send critical alert (Discord + Pushbullet + Email)
|
||
│
|
||
├── Cooldown: No more auto-recovery for crash_recovery_cooldown_minutes
|
||
│ └── Prevents restart loops from corrupted data
|
||
│
|
||
└── All crash events logged with timestamps and attempt details
|
||
```
|
||
|
||
---
|
||
|
||
## Server Migration System
|
||
|
||
### Export
|
||
|
||
Customer triggers export from dashboard. System packages:
|
||
|
||
- All server configuration (server_config, config_overrides)
|
||
- All wipe profiles and schedules
|
||
- Plugin registry with configurations
|
||
- Map rotation settings (not map files — too large)
|
||
- Webstore categories and items (not transaction history)
|
||
- Public site configuration
|
||
- Game admin list
|
||
- Notification settings
|
||
- RBAC roles (custom only)
|
||
|
||
Exported as encrypted JSON archive. Download link valid for 7 days.
|
||
|
||
### Import
|
||
|
||
Customer registers new license, runs setup wizard, then imports:
|
||
|
||
- Upload export archive
|
||
- System validates and maps data to new license_id
|
||
- Customer reviews what will be imported
|
||
- One-click apply
|
||
- Map files must be re-uploaded separately
|
||
|
||
---
|
||
|
||
# PHASE 1 — Foundation & Core Platform
|
||
|
||
**Goal:** Customer buys the plugin, registers, connects their server, and sees it live on the dashboard with basic management capabilities. Prove the platform works end-to-end.
|
||
|
||
**Success metric:** A customer with zero technical knowledge beyond "install this plugin" can register, connect their server, and manage it from the web within 15 minutes.
|
||
|
||
### Phase 1 Deliverables
|
||
|
||
**Platform Infrastructure**
|
||
|
||
- [ ] Corrosion Cloud deployment (Docker Compose: PostgreSQL, NATS, Rust API, Nginx)
|
||
- [ ] `panel.corrosionmgmt.com` — main web application
|
||
- [ ] Cloudflare DNS API integration for subdomain provisioning
|
||
- [ ] Nginx dynamic subdomain routing
|
||
- [ ] SSL via Cloudflare (wildcard cert for *.corrosionmgmt.com)
|
||
|
||
**Registration & Licensing**
|
||
|
||
- [ ] User registration with email verification
|
||
- [ ] License key validation and activation
|
||
- [ ] Login with JWT auth
|
||
- [ ] TOTP 2FA setup and verification
|
||
- [ ] License check-in endpoint for plugin validation
|
||
|
||
**Setup Wizard**
|
||
|
||
- [ ] Step 1: Name server + choose subdomain
|
||
- [ ] Step 2: Select connection type (AMP / Pterodactyl / Bare Metal)
|
||
- [ ] Step 3: Panel API configuration with connection test OR companion agent download
|
||
- [ ] Step 4: Plugin download (pre-configured with license token) + connection verification
|
||
- [ ] Step 5: Server template selection with auto plugin install from uMod
|
||
- [ ] Step 6: First wipe schedule creation
|
||
- [ ] Wizard completion → redirect to dashboard
|
||
|
||
**uMod Plugin (C#)**
|
||
|
||
- [ ] NATS outbound connection with auto-reconnect
|
||
- [ ] License token authentication
|
||
- [ ] Periodic license validation (every 6 hours)
|
||
- [ ] Heartbeat publishing (every 30 seconds)
|
||
- [ ] Server stats publishing (players, FPS, entities, uptime, memory)
|
||
- [ ] Player join/leave event publishing
|
||
- [ ] Chat message publishing
|
||
- [ ] Console output streaming
|
||
- [ ] Command subscription and execution
|
||
- [ ] Player kick/ban execution
|
||
- [ ] In-game announcement broadcasting
|
||
- [ ] Plugin list reporting (name, version, loaded state)
|
||
- [ ] Wipe countdown message broadcasting
|
||
- [ ] Post-wipe health report publishing
|
||
- [ ] Configurable via license token only (no manual config editing)
|
||
|
||
**Companion Agent (Go)**
|
||
|
||
- [ ] NATS outbound connection with auto-reconnect
|
||
- [ ] Pre-configured download from dashboard (license token + NATS endpoint baked in)
|
||
- [ ] Server process management (start, stop, restart)
|
||
- [ ] Server process monitoring (detect crashes)
|
||
- [ ] File system operations (read, write, delete, list)
|
||
- [ ] SteamCMD update execution
|
||
- [ ] Self-update capability
|
||
- [ ] Runs as system service (systemd / Windows service)
|
||
|
||
**Panel Adapters**
|
||
|
||
- [ ] PanelAdapter trait definition
|
||
- [ ] AMP adapter: connect, test, discover server, start, stop, restart, file ops, send command
|
||
- [ ] Pterodactyl adapter: same interface
|
||
- [ ] Panel connection health monitoring
|
||
|
||
**Dashboard — Server Management**
|
||
|
||
- [ ] Server status overview (online/offline, player count, FPS, uptime)
|
||
- [ ] Start / Stop / Restart server
|
||
- [ ] Live server console (real-time via NATS WebSocket)
|
||
- [ ] Console command input with history
|
||
- [ ] Server configuration editor (server.cfg key-value editing from web)
|
||
- [ ] Scheduled restarts (cron-based with timezone)
|
||
- [ ] Crash recovery (auto-restart with configurable attempts and cooldown)
|
||
|
||
**Dashboard — Player Management**
|
||
|
||
- [ ] Live player list (name, SteamID, playtime, ping)
|
||
- [ ] Kick player with reason
|
||
- [ ] Ban player with reason and duration
|
||
- [ ] Unban player
|
||
- [ ] Ban list management
|
||
- [ ] In-game admin registration (enter SteamID, select level, apply)
|
||
|
||
**Dashboard — Plugin Management**
|
||
|
||
- [ ] View installed plugins with version info
|
||
- [ ] Load / Unload / Reload plugins
|
||
- [ ] uMod plugin browser (search and install from uMod)
|
||
- [ ] Plugin configuration editing from web UI (JSON editor with save)
|
||
- [ ] Plugin data wipe settings (per-plugin, per-wipe-type toggles)
|
||
|
||
**Dashboard — Auto-Wiper**
|
||
|
||
- [ ] Wipe profile creation and management
|
||
- [ ] Pre-wipe sequence configuration (toggleable steps)
|
||
- [ ] Post-wipe verification configuration (toggleable checks)
|
||
- [ ] Wipe schedule creation (cron with timezone, wipe type)
|
||
- [ ] Wipe calendar view (all scheduled wipes + force wipe dates)
|
||
- [ ] Facepunch force wipe conflict detection
|
||
- [ ] SteamUpdateWatcher (buildid polling, auto-trigger)
|
||
- [ ] Manual wipe trigger with confirmation
|
||
- [ ] Dry-run / preview mode
|
||
- [ ] Wipe history with detailed execution logs
|
||
- [ ] Pre-wipe backup (via panel/companion)
|
||
- [ ] One-click rollback from dashboard
|
||
|
||
**Dashboard — Map Management**
|
||
|
||
- [ ] Map library (upload, metadata, thumbnails)
|
||
- [ ] Map rotation configuration (ordered list per server)
|
||
- [ ] Procedural seed management
|
||
- [ ] Signed download URLs for plugin map retrieval (15 min expiry)
|
||
- [ ] Checksum verification
|
||
|
||
**Dashboard — Notifications**
|
||
|
||
- [ ] Discord webhook configuration and test
|
||
- [ ] Pushbullet configuration and test
|
||
- [ ] Email alerts (server crash, wipe failed)
|
||
- [ ] Per-event notification toggles
|
||
|
||
**Dashboard — Team Management (RBAC)**
|
||
|
||
- [ ] Invite team members by email
|
||
- [ ] Assign roles to team members
|
||
- [ ] Default system roles (Owner, Head Admin, Moderator, Viewer)
|
||
- [ ] Clone and customize roles
|
||
- [ ] Permission enforcement on all UI elements and API endpoints
|
||
|
||
**Dashboard — Chat Log & Moderation**
|
||
|
||
- [ ] Real-time chat feed from server
|
||
- [ ] Chat history with search
|
||
- [ ] Flag messages with reason
|
||
- [ ] Quick-action: kick/ban from chat log entry
|
||
|
||
**Public Server Site (`servername.corrosionmgmt.com`)**
|
||
|
||
- [ ] Server info display (name, description, header image)
|
||
- [ ] Steam connect link (clickable)
|
||
- [ ] MOTD display
|
||
- [ ] Mod/plugin list (curated by admin)
|
||
- [ ] Wipe schedule display
|
||
- [ ] Next wipe countdown timer (live via NATS WebSocket)
|
||
- [ ] Live player count
|
||
- [ ] Discord invite link
|
||
- [ ] Configurable from dashboard (toggle sections on/off, colors, images)
|
||
|
||
**Platform Features**
|
||
|
||
- [ ] Changelog / update feed in dashboard
|
||
- [ ] Server migration export
|
||
- [ ] Server migration import
|
||
|
||
---
|
||
|
||
# PHASE 2 — Analytics & Intelligence
|
||
|
||
**Goal:** Data-driven insights that make admins smarter and look incredible in screenshots. This is the CodeFling differentiator.
|
||
|
||
**Depends on:** Phase 1 complete. NATS stats stream already collecting data.
|
||
|
||
### Phase 2 Deliverables
|
||
|
||
**Player Analytics**
|
||
|
||
- [ ] Player count tracking over time (hourly, daily, weekly graphs)
|
||
- [ ] Peak player tracking per day/week/month
|
||
- [ ] Player retention after wipe (what percentage return within 24h, 48h, 72h)
|
||
- [ ] Player count correlation with wipe timing
|
||
- [ ] Unique player counts (SteamID-based)
|
||
- [ ] Average session duration trends
|
||
- [ ] New vs returning player ratio
|
||
- [ ] Player join/leave heatmap (time of day patterns)
|
||
|
||
**Wipe Analytics**
|
||
|
||
- [ ] Wipe success/failure rate over time
|
||
- [ ] Average wipe execution duration
|
||
- [ ] Wipe-to-peak-population time (how fast server fills post-wipe)
|
||
- [ ] Population curve by wipe cycle (day 1 vs day 2 vs day 3 pattern)
|
||
- [ ] Optimal wipe timing recommendations based on historical data
|
||
- [ ] "Your best wipe day is X at Y" summary card
|
||
|
||
**Server Performance Analytics**
|
||
|
||
- [ ] FPS tracking over time (trend graphs)
|
||
- [ ] Entity count growth over wipe cycle
|
||
- [ ] FPS vs player count correlation
|
||
- [ ] Memory usage trends
|
||
- [ ] Performance degradation alerts (FPS below configurable threshold)
|
||
|
||
**Map Analytics**
|
||
|
||
- [ ] Player count per map (which maps drive the most players)
|
||
- [ ] Average population per map across wipe cycles
|
||
- [ ] Map rotation effectiveness scoring
|
||
|
||
**Dashboard Visualizations (Apache ECharts)**
|
||
|
||
- [ ] Interactive charts with date range selectors
|
||
- [ ] Server comparison views (if customer has multiple licenses)
|
||
- [ ] Summary insight cards
|
||
- [ ] Real-time updating charts
|
||
- [ ] Exportable chart images (PNG download for CodeFling screenshots / social media)
|
||
|
||
**Alerting**
|
||
|
||
- [ ] Discord/Pushbullet alerts for anomalies (population drop > X%, FPS below threshold)
|
||
- [ ] Configurable alert thresholds
|
||
- [ ] Alert history log
|
||
|
||
**Data Infrastructure**
|
||
|
||
- [ ] Aggregation service: raw stats → hourly → daily rollups
|
||
- [ ] Data retention policies (raw: 7 days, hourly: 90 days, daily: 1 year)
|
||
- [ ] Historical data CSV export
|
||
|
||
---
|
||
|
||
# PHASE 3 — Status Page
|
||
|
||
**Goal:** Public status page showcasing all opted-in servers. Free marketing for the platform.
|
||
|
||
**Depends on:** Phase 1 complete. Heartbeat and stats data already flowing.
|
||
|
||
### Phase 3 Deliverables
|
||
|
||
**Status Page (`status.corrosionmgmt.com`)**
|
||
|
||
- [ ] Public page listing all servers with `show_on_status_page = true`
|
||
- [ ] Per-server: name, status (online/offline/degraded), player count, uptime percentage
|
||
- [ ] Per-server: basic config display (map size, max players, wipe schedule)
|
||
- [ ] Overall platform health summary
|
||
- [ ] Uptime history graph per server (24h, 7d, 30d)
|
||
- [ ] Incident history (downtime events with duration)
|
||
- [ ] Real-time updates via NATS WebSocket
|
||
- [ ] Mobile-responsive design
|
||
- [ ] "Powered by Corrosion" branding with link to platform
|
||
|
||
---
|
||
|
||
# PHASE 4 — Module Store & First Modules
|
||
|
||
**Goal:** Launch the module marketplace and ship the first paid add-on modules. Prove the module ecosystem works.
|
||
|
||
**Depends on:** Phase 1 complete. Plugin infrastructure supports module loading.
|
||
|
||
### Phase 4 Deliverables
|
||
|
||
**Module Store Infrastructure**
|
||
|
||
- [ ] Module store page in dashboard (browse, preview, purchase)
|
||
- [ ] Module purchase flow (payment processing — details TBD)
|
||
- [ ] License key module activation (purchased modules tied to license)
|
||
- [ ] Module auto-installation (download module plugin, deploy to server via companion/panel)
|
||
- [ ] Module update system (new versions auto-detected, one-click update)
|
||
- [ ] Module configuration in dashboard (per-module settings UI)
|
||
|
||
**Loot Manager Module ($9.99)**
|
||
|
||
- [ ] Visual loot table editor (drag-and-drop items, set spawn rates, quantities)
|
||
- [ ] Container browser (every crate type, barrel, NPC drop, Bradley, Heli)
|
||
- [ ] Loot profiles ("2x Vanilla", "10x Modded", "Event Weekend")
|
||
- [ ] One-click profile switching (no restart required)
|
||
- [ ] Import/export loot profiles
|
||
- [ ] Skin selection from visual gallery
|
||
- [ ] Probability distribution preview
|
||
- [ ] Wipe-aware loot rotation (swap loot profiles automatically on wipe day)
|
||
- [ ] Scheduled loot changes (generous day 1, tighter day 5)
|
||
|
||
**Future Module Pipeline (not built in Phase 4, but planned)**
|
||
|
||
- Event plugins (convoy-style PvE events)
|
||
- Economics/currency system
|
||
- Kits manager
|
||
- Teleportation system
|
||
- Home/base management
|
||
- Clan/team management
|
||
- Voting rewards
|
||
- Custom crafting recipes
|
||
|
||
---
|
||
|
||
# PHASE 5 — Integrated Webstore
|
||
|
||
**Goal:** Tebex alternative where server owners monetize their community. $10/month recurring revenue per customer.
|
||
|
||
**Depends on:** Phase 1 complete (public site), Phase 4 complete (module delivery infrastructure).
|
||
|
||
### Phase 5 Deliverables
|
||
|
||
**Webstore Setup**
|
||
|
||
- [ ] Webstore add-on activation ($10/month subscription via PayPal)
|
||
- [ ] PayPal Business account connection (client ID + secret)
|
||
- [ ] Sandbox mode for testing before going live
|
||
- [ ] Store configuration (name, description, currency)
|
||
|
||
**Store Management (Dashboard)**
|
||
|
||
- [ ] Category management (create, reorder, toggle)
|
||
- [ ] Item management (create, edit, pricing, images)
|
||
- [ ] Item types: kits, ranks, in-game currency, custom commands
|
||
- [ ] Delivery configuration (server commands to execute on purchase)
|
||
- [ ] Item preview (see what the customer sees)
|
||
|
||
**Customer-Facing Store (`servername.corrosionmgmt.com/store`)**
|
||
|
||
- [ ] Store page integrated into public server site
|
||
- [ ] Category browsing
|
||
- [ ] Item detail pages with images and descriptions
|
||
- [ ] Cart and checkout flow
|
||
- [ ] PayPal payment processing (money goes directly to server owner)
|
||
- [ ] SteamID verification (buyer enters their Steam ID)
|
||
- [ ] Order confirmation page
|
||
|
||
**Delivery System**
|
||
|
||
- [ ] PayPal IPN/webhook listener
|
||
- [ ] Payment verification
|
||
- [ ] Automatic in-game delivery via NATS → Plugin command execution
|
||
- [ ] Delivery for online players: immediate
|
||
- [ ] Delivery for offline players: queued, delivered on next join
|
||
- [ ] Delivery confirmation logging
|
||
|
||
**Revenue Dashboard**
|
||
|
||
- [ ] Transaction history with filters
|
||
- [ ] Revenue summary (daily, weekly, monthly)
|
||
- [ ] Top-selling items
|
||
- [ ] Purchase activity graph
|
||
- [ ] Transaction status tracking (pending, paid, delivered, failed)
|
||
|
||
**Store Notifications**
|
||
|
||
- [ ] Discord notification on purchase
|
||
- [ ] Pushbullet notification on purchase
|
||
- [ ] Email receipt to buyer (optional)
|
||
- [ ] In-game announcement on purchase (optional, "Player X just bought VIP!")
|
||
|
||
---
|
||
|
||
# PHASE 6 — B2B Site Licensing
|
||
|
||
**Goal:** Hosting companies integrate Corrosion into their platform as a value-add for their Rust customers. High-value recurring B2B revenue.
|
||
|
||
**Depends on:** All previous phases stable and proven in production.
|
||
|
||
### Phase 6 Deliverables
|
||
|
||
**B2B Infrastructure**
|
||
|
||
- [ ] Organization/tenant model (hosting company as parent org)
|
||
- [ ] Bulk license provisioning (hosting company generates licenses for their customers)
|
||
- [ ] White-label options (custom branding, custom domain for the panel)
|
||
- [ ] Usage-based billing (per-active-server-month)
|
||
- [ ] B2B admin dashboard (hosting company sees all their customer servers)
|
||
- [ ] Custom panel adapter development support (hosting company's proprietary panel)
|
||
|
||
**Integration**
|
||
|
||
- [ ] API for hosting company to provision/deprovision servers
|
||
- [ ] SSO integration (customer logs into hosting company panel → auto-authenticated in Corrosion)
|
||
- [ ] Embedded dashboard option (iframe or SDK for embedding in hosting company panel)
|
||
- [ ] Custom module distribution (hosting company can offer their own modules)
|
||
|
||
---
|
||
|
||
## Infrastructure Scaling Notes
|
||
|
||
### Phase 1 (Single-server deployment)
|
||
|
||
```yaml
|
||
# Docker Compose — suitable for initial launch
|
||
services:
|
||
postgres:
|
||
image: postgres:16-alpine
|
||
volumes: [pg_data:/var/lib/postgresql/data]
|
||
|
||
nats:
|
||
image: nats:latest
|
||
command: [--jetstream, --store_dir, /data, --config, /etc/nats/nats.conf]
|
||
volumes: [nats_data:/data]
|
||
ports: [4222:4222, 9222:9222] # Client + WebSocket
|
||
|
||
api:
|
||
build: ./backend
|
||
environment:
|
||
DATABASE_URL: postgres://...
|
||
NATS_URL: nats://nats:4222
|
||
CLOUDFLARE_API_TOKEN: ${CF_TOKEN}
|
||
CLOUDFLARE_ZONE_ID: ${CF_ZONE}
|
||
ENCRYPTION_KEY: ${ENC_KEY}
|
||
|
||
nginx:
|
||
image: nginx:alpine
|
||
ports: [80:80, 443:443]
|
||
volumes:
|
||
- ./frontend/dist:/usr/share/nginx/html
|
||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||
```
|
||
|
||
### Scaling Milestones
|
||
|
||
| Customers | Infrastructure Change |
|
||
|-----------|----------------------|
|
||
| 1–50 | Single Docker Compose on one VPS |
|
||
| 50–200 | Separate database server, NATS on dedicated node |
|
||
| 200–500 | NATS cluster (3 nodes), read replicas for PostgreSQL |
|
||
| 500+ | Kubernetes, horizontal API scaling, managed PostgreSQL |
|
||
|
||
The architecture supports all of these transitions without application code changes. NATS clustering is transparent to clients. Database connection pooling handles read replicas. API is stateless (JWT + NATS) so it scales horizontally.
|
||
|
||
---
|
||
|
||
## Revenue Projections (Conservative)
|
||
|
||
| Milestone | Customers | Monthly Revenue |
|
||
|-----------|-----------|-----------------|
|
||
| Launch + 6 months | 50 licenses ($50 each) | $2,500 one-time + module sales |
|
||
| Year 1 | 200 licenses | ~$10,000 one-time + $500/mo webstore subscriptions |
|
||
| Year 2 | 500 licenses, 2 hosting companies | ~$25,000 one-time + $2,000/mo recurring |
|
||
| Year 3 | 1,000+ licenses, 5 hosting companies | Recurring revenue exceeds one-time |
|
||
|
||
These are conservative. The Convoy plugin sold 29,000 copies at $35. The Rust server market is large and underserved for management tooling.
|
||
|
||
---
|
||
|
||
*End of specification. To begin implementation, say: "Build Phase X"*
|