- Revamp architecture for modular game server support (Arma 3 first, extensible) - Merge ConfigSchema into ConfigGenerator per council decision (8→7 protocols) - Add has_capability() method to GameAdapter protocol for explicit capability probing - Add FRONTEND.md: production-grade dark neumorphism design with amber/orange palette - Update all docs (ARCHITECTURE, MODULES, DATABASE, API, IMPLEMENTATION_PLAN, THREADING) to reflect protocol merge and multi-game adapter patterns
20 KiB
Languard Servers Manager — API Contract
Base URL
http://localhost:8000/api
Authentication
- All endpoints except
POST /auth/loginandGET /system/healthrequire:Authorization: Bearer <JWT> - WebSocket: pass token as query param:
ws://localhost:8000/ws/{server_id}?token=<JWT> - JWT payload:
{ "sub": "user_id", "username": "string", "role": "admin|viewer", "exp": timestamp }
Common Response Envelope
{
"success": true,
"data": { ... },
"error": null
}
Error response:
{
"success": false,
"data": null,
"error": {
"code": "NOT_FOUND",
"message": "Server with id 5 not found"
}
}
HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | No content (DELETE) |
| 400 | Validation error |
| 401 | Unauthenticated |
| 403 | Forbidden (insufficient role) |
| 404 | Not found (or capability not supported by adapter) |
| 409 | Conflict (already running, duplicate) |
| 422 | Unprocessable (Pydantic validation) |
| 500 | Internal server error |
Capability-Based Routing
Some endpoints depend on the server's game adapter supporting a specific capability. If the adapter does not support the capability, the endpoint returns 404 with a clear message:
{
"success": false,
"data": null,
"error": {
"code": "CAPABILITY_NOT_SUPPORTED",
"message": "Missions not supported for game type 'rust'"
}
}
Auth Endpoints
POST /auth/login
Login and receive JWT.
Request:
{
"username": "admin",
"password": "secret"
}
Response 200:
{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"expires_in": 86400,
"user": {
"id": 1,
"username": "admin",
"role": "admin"
}
}
}
POST /auth/logout
Invalidate token (client-side token deletion; server-side blacklist optional).
GET /auth/me
Return current user info.
PUT /auth/password
Change password. Admin only.
{ "current_password": "old", "new_password": "new" }
GET /auth/users
List all users. Admin only.
POST /auth/users
Create user. Admin only.
{ "username": "viewer1", "password": "pass", "role": "viewer" }
DELETE /auth/users/{user_id}
Delete user. Admin only.
Game Type Discovery Endpoints
GET /games
List all registered game types and their capabilities.
Response 200:
{
"success": true,
"data": [
{
"game_type": "arma3",
"display_name": "Arma 3",
"version": "1.0.0",
"capabilities": ["config_generator", "process_config",
"log_parser", "remote_admin", "mission_manager", "mod_manager", "ban_manager"]
}
]
}
GET /games/{game_type}
Get details for a specific game type.
Response 200:
{
"success": true,
"data": {
"game_type": "arma3",
"display_name": "Arma 3",
"version": "1.0.0",
"capabilities": ["config_generator", "process_config",
"log_parser", "remote_admin", "mission_manager", "mod_manager", "ban_manager"],
"config_sections": ["server", "basic", "profile", "launch", "rcon"],
"allowed_executables": ["arma3server_x64.exe", "arma3server.exe"]
}
}
GET /games/{game_type}/config-schema
Returns JSON Schema for each config section defined by the adapter. Used by frontend to build dynamic config forms.
Response 200:
{
"success": true,
"data": {
"server": { /* JSON Schema for server.cfg params */ },
"basic": { /* JSON Schema for basic.cfg params */ },
"profile": { /* JSON Schema for Arma3Profile params */ },
"launch": { /* JSON Schema for launch params */ },
"rcon": { /* JSON Schema for RCon params */ }
}
}
GET /games/{game_type}/defaults
Default config values for new server creation.
Response 200:
{
"success": true,
"data": {
"server": { "hostname": "My Arma 3 Server", "max_players": 40, ... },
"basic": { "min_bandwidth": 800000, ... },
"profile": { "reduced_damage": 0, ... },
"launch": { "world": "empty", "limit_fps": 50, ... },
"rcon": { "max_ping": 200, "enabled": 1 }
}
}
Server Endpoints
GET /servers
List all servers with current status. Supports filtering by game type.
Query params: ?limit=50&offset=0&game_type=arma3
Response 200:
{
"success": true,
"data": [
{
"id": 1,
"name": "Main Server",
"description": "Primary COOP server",
"game_type": "arma3",
"status": "running",
"pid": 12345,
"game_port": 2302,
"rcon_port": 2306,
"player_count": 15,
"max_players": 40,
"cpu_percent": 34.2,
"ram_mb": 1850.5,
"started_at": "2026-04-16T10:00:00Z"
}
]
}
POST /servers
Create a new server. Admin only. game_type determines which adapter handles this server.
Request:
{
"name": "Main Server",
"description": "Primary COOP server",
"game_type": "arma3",
"exe_path": "C:/Arma3Server/arma3server_x64.exe",
"game_port": 2302,
"rcon_port": 2306,
"auto_restart": true,
"max_restarts": 3
}
The adapter provides default config values for all sections. Auto-generated credentials (e.g., password_admin, rcon_password for Arma 3) are returned in the response and not stored in plaintext.
Response 201: Returns full server object including auto-generated credentials.
GET /servers/{server_id}
Get server detail with full status.
Response 200:
{
"success": true,
"data": {
"id": 1,
"name": "Main Server",
"game_type": "arma3",
"status": "running",
"pid": 12345,
"game_port": 2302,
"rcon_port": 2306,
"auto_restart": true,
"restart_count": 0,
"player_count": 15,
"max_players": 40,
"cpu_percent": 34.2,
"ram_mb": 1850.5,
"started_at": "2026-04-16T10:00:00Z",
"uptime_seconds": 3600
}
}
PUT /servers/{server_id}
Update server metadata (name, description, exe_path, ports). Admin only.
DELETE /servers/{server_id}
Delete server (must be stopped first). Admin only. Removes DB rows and servers/{id}/ directory.
POST /servers/{server_id}/start
Start the server. Admin only. Core resolves the adapter and delegates config generation + launch arg building.
Response 200:
{ "success": true, "data": { "status": "starting", "pid": null } }
Response 409: Server already running.
POST /servers/{server_id}/stop
Graceful stop (sends shutdown via adapter's RemoteAdmin, then force-kill after 30s). Admin only.
Request (optional):
{ "force": false, "reason": "Maintenance" }
POST /servers/{server_id}/restart
Stop then start. Admin only.
POST /servers/{server_id}/kill
Force-kill the process immediately. Admin only. Emergency use only.
Server Config Endpoints
Config sections are defined by the server's game adapter. The core game_configs table stores them as JSON. The adapter's Pydantic models validate input.
GET /servers/{server_id}/config
Get all config sections combined. Each section includes its config_version for optimistic locking.
Response 200:
{
"success": true,
"data": {
"server": { /* section JSON */, "_meta": {"config_version": 3, "schema_version": "1.0"} },
"basic": { /* section JSON */, "_meta": {"config_version": 1, "schema_version": "1.0"} },
"profile": { /* section JSON */, "_meta": {"config_version": 2, "schema_version": "1.0"} },
"launch": { /* section JSON */, "_meta": {"config_version": 1, "schema_version": "1.0"} },
"rcon": { "rcon_password": "***", "max_ping": 200, "enabled": 1, "_meta": {"config_version": 1, "schema_version": "1.0"} }
}
}
GET /servers/{server_id}/config/{section}
Get a single config section. Section names are defined by the adapter (e.g., server, basic, profile, launch, rcon for Arma 3).
Response 200:
{
"success": true,
"data": {
"hostname": "My Server",
"max_players": 40,
"_meta": { "config_version": 3, "schema_version": "1.0" }
}
}
PUT /servers/{server_id}/config/{section}
Update a config section. Admin only. Validated against the adapter's Pydantic model for that section. Sensitive fields (passwords) are encrypted before storage. Optimistic locking — client must send config_version from their last read.
Request: Partial object matching the adapter's section schema. Any omitted field keeps current value. Must include config_version for conflict detection.
Arma 3 server section example:
{
"hostname": "Updated Server Name",
"max_players": 64,
"battleye": 1,
"verify_signatures": 2,
"motd_lines": ["Welcome!", "Have fun"],
"motd_interval": 5.0,
"config_version": 3
}
Response 409 (Conflict): Another admin updated this section since you read it.
{
"success": false,
"data": {
"current_config": { /* latest values */ },
"current_version": 5
},
"error": {
"code": "CONFIG_VERSION_CONFLICT",
"message": "Config section 'server' was modified by another user. Re-read and merge your changes."
}
}
Arma 3 basic section example:
{
"max_bandwidth": 50000000,
"max_msg_send": 256
}
Arma 3 profile section example:
{
"third_person_view": 0,
"weapon_crosshair": 0,
"ai_level_preset": 3,
"skill_ai": 0.7,
"precision_ai": 0.6
}
Arma 3 launch section example:
{
"world": "empty",
"limit_fps": 50,
"auto_init": false,
"load_mission_to_memory": true
}
Arma 3 rcon section example:
{
"rcon_password": "newpassword",
"rcon_port": 2306,
"max_ping": 300,
"enabled": true
}
Note: rcon_port is stored in the servers table, not in the config JSON. The service layer updates both tables as needed.
GET /servers/{server_id}/config/preview
Returns rendered config for preview in UI. Admin only — may contain plaintext credentials. Returns a dict of {label: rendered_content} — labels are filenames for file-based configs, variable names for env-var configs, or argument names for CLI configs.
Response 200:
{
"success": true,
"data": {
"server.cfg": "// Generated server.cfg\nhostname = \"My Server\";\n...",
"basic.cfg": "// Generated basic.cfg\n...",
"server.Arma3Profile": "// Generated profile\n..."
}
}
(Non-file games would return e.g. {"SERVER_NAME": "My Server", "MAX_PLAYERS": "40"} for env-var configs.)
GET /servers/{server_id}/config/download/{filename}
Download generated config file. Filename must be in adapter's allowlist (whitelist-validated, no path traversal). Admin only.
Mission Endpoints (Capability: mission_manager)
Returns 404 if adapter does not support mission_manager.
GET /servers/{server_id}/missions
List all mission/scenario files for a server.
Response 200:
{
"success": true,
"data": [
{
"id": 1,
"filename": "MyMission.Altis.pbo",
"mission_name": "MyMission.Altis",
"terrain": "Altis",
"file_size": 102400,
"uploaded_at": "2026-04-16T09:00:00Z"
}
]
}
POST /servers/{server_id}/missions/upload
Upload a mission/scenario file. Admin only. multipart/form-data. File extension validated by adapter's MissionManager.file_extension.
Form fields:
file: the mission file (filename sanitized; only adapter-allowed extensions accepted)
Response 201:
{
"success": true,
"data": {
"id": 2,
"filename": "NewMission.Stratis.pbo",
"mission_name": "NewMission.Stratis",
"terrain": "Stratis",
"file_size": 51200
}
}
DELETE /servers/{server_id}/missions/{mission_id}
Delete a mission file (removes file from disk). Admin only.
GET /servers/{server_id}/missions/rotation
Get current mission/scenario rotation (ordered list).
Response 200:
{
"success": true,
"data": [
{
"id": 1,
"sort_order": 0,
"mission": { "id": 1, "mission_name": "MyMission.Altis" },
"difficulty": "Regular",
"params_json": { "RespawnDelay": 15 }
}
]
}
PUT /servers/{server_id}/missions/rotation
Replace the entire mission rotation. Admin only.
{
"rotation": [
{ "mission_id": 1, "difficulty": "Regular", "params": {} },
{ "mission_id": 2, "difficulty": "Veteran", "params": { "RespawnDelay": 30 } }
]
}
Mod Endpoints (Capability: mod_manager)
Returns 404 if adapter does not support mod_manager.
GET /mods
List all registered mods. Optionally filter by game type.
Query params: ?game_type=arma3
POST /mods
Register a mod folder. Admin only.
{
"game_type": "arma3",
"name": "@CBA_A3",
"folder_path": "C:/Arma3Server/@CBA_A3",
"workshop_id": "450814997",
"description": "Community Base Addons"
}
DELETE /mods/{mod_id}
Delete mod registration. Admin only.
GET /servers/{server_id}/mods
Get mods enabled for a server.
Response 200:
{
"success": true,
"data": [
{
"mod_id": 1,
"name": "@CBA_A3",
"folder_path": "C:/Arma3Server/@CBA_A3",
"is_server_mod": false,
"sort_order": 0
}
]
}
PUT /servers/{server_id}/mods
Replace the mod list for a server. Admin only.
{
"mods": [
{ "mod_id": 1, "is_server_mod": false, "sort_order": 0 },
{ "mod_id": 2, "is_server_mod": true, "sort_order": 1 }
]
}
Player Endpoints
GET /servers/{server_id}/players
Get currently connected players.
Response 200:
{
"success": true,
"data": [
{
"slot_id": "1",
"name": "PlayerOne",
"guid": "abc123...",
"ping": 45,
"game_data": { "verified": true, "steam_uid": "76561198..." },
"joined_at": "2026-04-16T10:15:00Z"
}
]
}
POST /servers/{server_id}/players/{slot_id}/kick
Kick a player. Admin only. Requires adapter remote_admin capability.
{ "reason": "AFK" }
POST /servers/{server_id}/players/{slot_id}/ban
Ban a player. Admin only. Requires adapter remote_admin capability.
{
"reason": "Griefing",
"duration_minutes": 0
}
GET /servers/{server_id}/players/history
Player connection history. Supports pagination.
Query params: ?limit=50&offset=0&search=PlayerName
Ban Endpoints
GET /servers/{server_id}/bans
List all bans for a server.
Query params: ?active_only=true&limit=50&offset=0
POST /servers/{server_id}/bans
Add ban manually. Admin only. If adapter has ban_manager, also syncs to the game's ban file.
{
"guid": "abc123...",
"name": "PlayerName",
"reason": "Cheating",
"duration_minutes": 0
}
DELETE /servers/{server_id}/bans/{ban_id}
Remove a ban. Admin only. If adapter has ban_manager, also removes from the game's ban file.
Remote Admin Endpoints (Capability: remote_admin)
Returns 404 if adapter does not support remote_admin.
POST /servers/{server_id}/remote-admin/command
Send raw remote admin command. Admin only.
{ "command": "#restart" }
Arma 3 available commands:
#restart— Restart mission#reassign— Restart with roles unassigned#missions— Open mission selection#lock/#unlock— Lock/unlock server#mission NAME.TERRAIN [difficulty]— Load specific mission#shutdown— Shut down server#monitor N— Toggle performance monitoringsay -1 MESSAGE— Message all players
POST /servers/{server_id}/remote-admin/say
Broadcast a message to all players. Admin only.
{ "message": "Server restarting in 5 minutes!" }
Log Endpoints
GET /servers/{server_id}/logs
Query stored log lines.
Query params: ?limit=200&offset=0&level=error&since=2026-04-16T10:00:00Z&search=BattlEye
Response 200:
{
"success": true,
"data": {
"total": 1542,
"logs": [
{
"id": 100,
"timestamp": "2026-04-16T10:05:23Z",
"level": "info",
"message": "Player PlayerOne connected"
}
]
}
}
DELETE /servers/{server_id}/logs
Clear all stored log lines for a server. Admin only.
Metrics Endpoints
GET /servers/{server_id}/metrics
Get time-series metrics.
Query params: ?from=2026-04-16T00:00:00Z&to=2026-04-16T23:59:59Z&resolution=5m
Response 200:
{
"success": true,
"data": [
{
"timestamp": "2026-04-16T10:00:00Z",
"cpu_percent": 34.2,
"ram_mb": 1850.5,
"player_count": 15
}
]
}
Event Log Endpoints
GET /servers/{server_id}/events
Get server event history (audit trail).
Query params: ?limit=50&offset=0&event_type=crashed
System Endpoints
GET /system/status
Overall system status. Requires authentication (admin or viewer).
{
"success": true,
"data": {
"version": "1.0.0",
"running_servers": 2,
"total_servers": 3,
"supported_games": ["arma3"],
"uptime_seconds": 86400
}
}
GET /system/health
Health check (for load balancer/Docker). Returns 200 if healthy.
WebSocket API
Connection
ws://localhost:8000/ws/{server_id}?token=<JWT>
Use server_id = "all" to subscribe to events from all servers.
Client → Server Messages
{ "type": "ping" }
{ "type": "subscribe", "channels": ["logs", "players", "metrics", "status"] }
{ "type": "unsubscribe", "channels": ["metrics"] }
Channel subscription: The ConnectionManager tracks per-connection channel subscriptions. Only messages matching subscribed channels are delivered. Default subscriptions on connect: ["status"].
Server → Client Messages
Status Update
{
"type": "status",
"server_id": 1,
"data": {
"status": "running",
"pid": 12345,
"started_at": "2026-04-16T10:00:00Z"
}
}
Log Line
{
"type": "log",
"server_id": 1,
"data": {
"timestamp": "2026-04-16T10:05:23Z",
"level": "info",
"message": "BattlEye Server: Initialized (v1.240)"
}
}
Player List Update
{
"type": "players",
"server_id": 1,
"data": {
"players": [
{ "slot_id": "1", "name": "PlayerOne", "ping": 45 }
],
"count": 1
}
}
Metrics Update
{
"type": "metrics",
"server_id": 1,
"data": {
"cpu_percent": 34.2,
"ram_mb": 1850.5,
"player_count": 1,
"timestamp": "2026-04-16T10:05:25Z"
}
}
Server Event
{
"type": "event",
"server_id": 1,
"data": {
"event_type": "crashed",
"detail": { "exit_code": 1 },
"timestamp": "2026-04-16T10:30:00Z"
}
}
Pong
{ "type": "pong" }
Adapter-Specific Routes
Adapters may register additional routes under /api/servers/{server_id}/game/{game_type}/... for features that have no generic counterpart.
Arma 3 example:
POST /api/servers/{server_id}/game/arma3/battleye/reload
These routes are registered at app startup by iterating over all registered adapters.
Rate Limiting
POST /auth/login: 5 attempts per minute per IP. Exceeded returns429 Too Many Requests.- All other endpoints: 60 requests per minute per token. Exceeded returns
429. - Implemented via FastAPI middleware (e.g.,
slowapi).
Error Codes Reference
| Code | Description |
|---|---|
UNAUTHORIZED |
Missing or invalid token |
FORBIDDEN |
Role insufficient |
NOT_FOUND |
Resource not found |
CAPABILITY_NOT_SUPPORTED |
Adapter lacks required capability for this endpoint |
SERVER_ALREADY_RUNNING |
Start called on running server |
SERVER_NOT_RUNNING |
Stop/command on stopped server |
REMOTE_ADMIN_UNAVAILABLE |
Remote admin connection failed |
INVALID_CONFIG |
Config validation failed (adapter-specific) |
CONFIG_WRITE_ERROR |
Config file write failed (disk, permissions) |
CONFIG_VERSION_CONFLICT |
Optimistic locking conflict on config update |
EXE_NOT_ALLOWED |
Executable not in adapter's allowlist |
PORT_IN_USE |
Game port already occupied |
UPLOAD_FAILED |
File upload error |
VALIDATION_ERROR |
Pydantic validation failure |
GAME_TYPE_NOT_FOUND |
No adapter registered for this game type |
INTERNAL_ERROR |
Unexpected server error |
MOD_IN_USE |
Cannot delete mod — enabled on one or more servers |
MISSION_IN_ROTATION |
Cannot delete mission — in active rotation |
RATE_LIMITED |
Too many requests |