MAID Admin API Reference¶
The MAID Admin API provides a comprehensive REST/WebSocket interface for server administration, monitoring, and management. All endpoints are prefixed with /admin.
Admin Web UI¶
MAID includes a React-based admin web interface that provides a visual dashboard for server management.
Building the Admin UI¶
The admin frontend is located at packages/maid-engine/admin_frontend/. To build it:
# Navigate to the admin frontend directory
cd packages/maid-engine/admin_frontend
# Install dependencies
npm install
# Build for production
npm run build
# For development with hot reload (connects to API on localhost:8080)
npm run dev
Accessing the Admin UI¶
Once built, the admin UI is automatically served by the MAID server:
- Production:
http://your-server:8080/admin-ui/ - Development:
http://localhost:3000/(with Vite dev server)
The production build is served from packages/maid-engine/admin_frontend/dist/ via FastAPI's StaticFiles mount.
UI Features¶
- Dashboard: Real-time server metrics and performance graphs
- Players: View and manage online players, ban/kick functionality
- Entities: Browse and edit game entities and their components
- World: View room topology and navigate the game world
- Logs: Search and stream server logs in real-time
- Config: View and modify server configuration
Table of Contents¶
- Authentication
- Dashboard
- Entity Management
- Player Management
- World Management
- Logs
- Configuration
- Content Packs
- WebSocket Endpoints
Authentication¶
The Admin API uses JWT (JSON Web Tokens) for authentication. Tokens are issued upon login and must be included in the Authorization header of subsequent requests.
Login¶
POST /admin/auth/login
Authenticate with username and password to receive access and refresh tokens.
Request Body:
Response (200):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 3600,
"user": {
"username": "admin",
"role": "ADMIN",
"permissions": ["view", "edit", "admin"]
}
}
Errors:
- 401 - Invalid credentials
- 403 - Account locked or disabled
Refresh Token¶
POST /admin/auth/refresh
Exchange a refresh token for a new access token.
Request Body:
Response (200):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 3600
}
Logout¶
POST /admin/auth/logout
Revoke the current access token.
Headers:
Response (200):
Get Current User¶
GET /admin/auth/me
Get information about the currently authenticated user.
Response (200):
{
"username": "admin",
"role": "ADMIN",
"permissions": ["view", "edit", "admin"],
"last_login": "2024-01-15T10:30:00Z"
}
Admin Roles¶
| Role | Description | Capabilities |
|---|---|---|
VIEWER |
Read-only access | View entities, logs, metrics |
BUILDER |
World building | Create/modify rooms, entities |
ADMIN |
Administration | Manage players, reload packs |
SUPERADMIN |
Full access | All operations including config |
Dashboard¶
Real-time server metrics and monitoring.
Get All Metrics¶
GET /admin/dashboard/
Get comprehensive dashboard metrics.
Response (200):
{
"server": {
"uptime_seconds": 86400,
"tick_rate": 4.0,
"current_tick": 345600,
"memory_mb": 256.5,
"cpu_percent": 12.3
},
"players": {
"online_count": 42,
"total_accounts": 1234,
"active_sessions": 42,
"peak_today": 67
},
"world": {
"room_count": 500,
"entity_count": 2345,
"loaded_areas": 12,
"active_npcs": 189
},
"performance": {
"avg_tick_ms": 2.5,
"max_tick_ms": 15.3,
"commands_per_second": 8.7
}
}
Get Server Metrics¶
GET /admin/dashboard/server
Get server-specific metrics including CPU, memory, and tick performance.
Get Player Metrics¶
GET /admin/dashboard/players
Get player statistics and session information.
Get World Metrics¶
GET /admin/dashboard/world
Get world state metrics including entity counts and area information.
Entity Management¶
CRUD operations for game entities.
List Entities¶
GET /admin/entities/
List entities with filtering and pagination.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| page | int | Page number (1-indexed) |
| page_size | int | Items per page (1-100) |
| type | string | Filter by entity type |
| room_id | UUID | Filter by room |
| has_tag | string | Filter by tag |
| search | string | Search by name |
Response (200):
{
"entities": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Sword of Destiny",
"type": "item",
"room_id": "660e8400-e29b-41d4-a716-446655440001",
"tags": ["weapon", "magic"],
"component_types": ["ItemComponent", "DamageComponent"]
}
],
"total": 100,
"page": 1,
"page_size": 20,
"has_next": true
}
Get Entity¶
GET /admin/entities/{entity_id}
Get detailed information about a specific entity.
Response (200):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Sword of Destiny",
"type": "item",
"room_id": "660e8400-e29b-41d4-a716-446655440001",
"tags": ["weapon", "magic"],
"components": {
"ItemComponent": {
"weight": 5.0,
"value": 1000
},
"DamageComponent": {
"damage_type": "slashing",
"damage_dice": "2d6+3"
}
},
"metadata": {
"created_at": "2024-01-15T10:30:00Z",
"created_by": "admin"
}
}
Create Entity¶
POST /admin/entities/
Create a new entity.
Required Role: BUILDER
Request Body:
{
"name": "Iron Sword",
"type": "item",
"room_id": "660e8400-e29b-41d4-a716-446655440001",
"tags": ["weapon"],
"components": {
"ItemComponent": {
"weight": 3.0,
"value": 50
}
}
}
Response (201):
{
"id": "770e8400-e29b-41d4-a716-446655440002",
"name": "Iron Sword",
"message": "Entity created successfully"
}
Delete Entity¶
DELETE /admin/entities/{entity_id}
Delete an entity from the world.
Required Role: ADMIN
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| force | bool | Force deletion even if entity has dependents |
Response (200):
Update Component¶
PUT /admin/entities/{entity_id}/components/{component_type}
Update a component on an entity.
Required Role: BUILDER
Request Body:
Add Component¶
POST /admin/entities/{entity_id}/components
Add a new component to an entity.
Required Role: BUILDER
Request Body:
Remove Component¶
DELETE /admin/entities/{entity_id}/components/{component_type}
Remove a component from an entity.
Required Role: BUILDER
Add Tag¶
POST /admin/entities/{entity_id}/tags/{tag}
Add a tag to an entity.
Required Role: BUILDER
Remove Tag¶
DELETE /admin/entities/{entity_id}/tags/{tag}
Remove a tag from an entity.
Required Role: BUILDER
Player Management¶
Manage player accounts and sessions.
List Players¶
GET /admin/players/
List player accounts with filtering.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| page | int | Page number |
| page_size | int | Items per page |
| online_only | bool | Only show online players |
| search | string | Search by username |
| banned | bool | Filter by ban status |
Response (200):
{
"players": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "player1",
"email": "player1@example.com",
"is_online": true,
"is_banned": false,
"access_level": "PLAYER",
"created_at": "2024-01-01T00:00:00Z",
"last_login": "2024-01-15T10:30:00Z"
}
],
"total": 1234,
"page": 1,
"page_size": 20
}
Get Player Details¶
GET /admin/players/{player_id}
Get detailed information about a player.
Response (200):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "player1",
"email": "player1@example.com",
"is_online": true,
"is_banned": false,
"access_level": "PLAYER",
"created_at": "2024-01-01T00:00:00Z",
"last_login": "2024-01-15T10:30:00Z",
"play_time_hours": 156.5,
"character_count": 3,
"current_character_id": "660e8400-e29b-41d4-a716-446655440001",
"ip_address": "192.168.1.100",
"session_start": "2024-01-15T10:00:00Z"
}
Get Player Characters¶
GET /admin/players/{player_id}/characters
List all characters belonging to a player.
Ban Player¶
POST /admin/players/{player_id}/ban
Ban a player account.
Required Role: ADMIN
Request Body:
Unban Player¶
POST /admin/players/{player_id}/unban
Remove a ban from a player account.
Required Role: ADMIN
Kick Player¶
POST /admin/players/{player_id}/kick
Disconnect a player's current session.
Required Role: ADMIN
Request Body:
Set Access Level¶
PUT /admin/players/{player_id}/access-level
Change a player's access level.
Required Role: SUPERADMIN
Request Body:
Send Message¶
POST /admin/players/{player_id}/message
Send a message to a player.
Required Role: ADMIN
Request Body:
World Management¶
Manage rooms, exits, and areas.
List Rooms¶
GET /admin/world/rooms
List rooms with filtering and pagination.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| page | int | Page number (1-indexed) |
| page_size | int | Items per page (1-100) |
| area_id | UUID | Filter by area |
| search | string | Search by room name |
Response (200):
{
"rooms": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Town Square",
"description": "The central square of the town.",
"area_id": "660e8400-e29b-41d4-a716-446655440001",
"area_name": "Town",
"exits": [
{
"direction": "north",
"destination_id": "770e8400-e29b-41d4-a716-446655440002",
"destination_name": "Market Street",
"is_locked": false
}
],
"entity_count": 5,
"player_count": 2
}
],
"total": 500,
"page": 1,
"page_size": 50,
"has_next": true,
"has_previous": false
}
Get Room¶
GET /admin/world/rooms/{room_id}
Get detailed information about a room.
Create Room¶
POST /admin/world/rooms
Create a new room.
Required Role: BUILDER
Request Body:
{
"name": "Secret Chamber",
"description": "A hidden chamber behind the waterfall.",
"area_id": "660e8400-e29b-41d4-a716-446655440001",
"metadata": {
"hidden": true,
"terrain": "cave"
}
}
Response (201):
{
"id": "880e8400-e29b-41d4-a716-446655440003",
"name": "Secret Chamber",
"message": "Room created successfully"
}
Update Room¶
PUT /admin/world/rooms/{room_id}
Update a room's properties.
Required Role: BUILDER
Request Body:
{
"name": "Updated Room Name",
"description": "New description",
"metadata": {
"terrain": "stone"
}
}
Delete Room¶
DELETE /admin/world/rooms/{room_id}
Delete a room and all its exits.
Required Role: ADMIN
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| force | bool | Force deletion even if room contains entities |
Create Exit¶
POST /admin/world/exits
Create an exit between two rooms.
Required Role: BUILDER
Request Body:
{
"from_room_id": "550e8400-e29b-41d4-a716-446655440000",
"to_room_id": "660e8400-e29b-41d4-a716-446655440001",
"direction": "north",
"bidirectional": true,
"reverse_direction": "south",
"is_locked": false
}
Response (201):
{
"from_room_id": "550e8400-e29b-41d4-a716-446655440000",
"to_room_id": "660e8400-e29b-41d4-a716-446655440001",
"direction": "north",
"reverse_created": true,
"message": "Exit created successfully"
}
Delete Exit¶
DELETE /admin/world/exits/{room_id}/{direction}
Delete an exit from a room.
Required Role: BUILDER
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| bidirectional | bool | Also delete the reverse exit |
Get World Graph¶
GET /admin/world/graph
Get the world topology as a graph for visualization.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| area_id | UUID | Filter to a specific area |
Response (200):
{
"nodes": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"label": "Town Square",
"area_id": "660e8400-e29b-41d4-a716-446655440001",
"area_name": "Town",
"player_count": 2
}
],
"edges": [
{
"source": "550e8400-e29b-41d4-a716-446655440000",
"target": "770e8400-e29b-41d4-a716-446655440002",
"label": "north",
"bidirectional": true
}
],
"total_rooms": 500,
"total_exits": 1200,
"total_areas": 12
}
List Areas¶
GET /admin/world/areas
List all areas/zones in the world.
Response (200):
{
"areas": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Town",
"description": "The main town area",
"room_count": 50,
"player_count": 15,
"metadata": {}
}
],
"total": 12
}
Logs¶
View, search, and export server logs.
Search Logs¶
GET /admin/logs/
Search log entries with filters.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| start_time | datetime | Start of time range |
| end_time | datetime | End of time range |
| level | string | Minimum log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
| logger_name | string | Logger name prefix |
| message_pattern | string | Regex pattern for message |
| limit | int | Maximum results (1-1000) |
| offset | int | Pagination offset |
Response (200):
{
"entries": [
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "INFO",
"logger_name": "maid_engine.core.engine",
"message": "Server started successfully",
"module": "engine",
"func_name": "start",
"line_no": 123,
"exc_info": null
}
],
"total": 1500,
"has_more": true
}
Get Recent Logs¶
GET /admin/logs/recent
Get the most recent log entries.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| count | int | Number of entries (1-500) |
List Loggers¶
GET /admin/logs/loggers
Get information about all known loggers.
Response (200):
[
{
"name": "maid_engine.core.engine",
"level": "INFO",
"effective_level": "INFO",
"handlers_count": 2
}
]
Export Logs¶
POST /admin/logs/export
Export logs to JSON or CSV format.
Required Role: ADMIN
Request Body:
{
"format": "json",
"start_time": "2024-01-15T00:00:00Z",
"end_time": "2024-01-15T23:59:59Z",
"level": "WARNING",
"max_entries": 10000
}
Response: Streaming file download
Get Log Statistics¶
GET /admin/logs/stats
Get statistics about logged messages.
Response (200):
{
"total_entries": 10000,
"buffer_capacity": 10000,
"by_level": {
"DEBUG": 5000,
"INFO": 3500,
"WARNING": 1000,
"ERROR": 450,
"CRITICAL": 50
},
"top_loggers": {
"maid_engine.core.engine": 2500,
"maid_engine.network.telnet": 1500
}
}
Configuration¶
View and modify server configuration.
Get All Configuration¶
GET /admin/config/
Get all configuration sections.
Response (200):
[
{
"name": "game",
"description": "Core game engine settings",
"fields": {
"tick_rate": 4.0,
"max_players": 1000
},
"schema_info": {
"tick_rate": {
"type": "float",
"description": "Game ticks per second",
"is_secret": false,
"required": false,
"default": 4.0
}
}
}
]
Get Configuration Section¶
GET /admin/config/{section}
Get a specific configuration section.
Get Configuration Value¶
GET /admin/config/{section}/{key}
Get a specific configuration value.
Response (200):
{
"section": "game",
"key": "tick_rate",
"value": 4.0,
"value_type": "float",
"description": "Game ticks per second",
"is_secret": false,
"is_mutable": true
}
Validate Configuration Change¶
POST /admin/config/validate
Validate a proposed configuration change without applying it.
Required Role: ADMIN
Request Body:
Response (200):
Update Configuration Value¶
PUT /admin/config/{section}/{key}
Update a configuration value at runtime.
Required Role: SUPERADMIN
Request Body:
Reload Configuration¶
POST /admin/config/reload
Reload configuration from files and clear runtime overrides.
Required Role: SUPERADMIN
Get Runtime Overrides¶
GET /admin/config/overrides
Get all runtime configuration overrides.
Required Role: ADMIN
Clear Runtime Override¶
DELETE /admin/config/{section}/{key}/override
Clear a runtime override and revert to the base value.
Required Role: SUPERADMIN
Content Packs¶
Manage content packs (plugins).
List Content Packs¶
GET /admin/packs/
List all available and loaded content packs.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| loaded_only | bool | Only show loaded packs |
Response (200):
{
"packs": [
{
"name": "maid-stdlib",
"display_name": "MAID Standard Library",
"version": "0.1.0",
"description": "Standard components and utilities",
"is_loaded": true,
"is_available": true
}
],
"total_available": 5,
"total_loaded": 3
}
Get Pack Details¶
GET /admin/packs/{pack_name}
Get detailed information about a content pack.
Response (200):
{
"manifest": {
"name": "maid-stdlib",
"version": "0.1.0",
"display_name": "MAID Standard Library",
"description": "Standard components and utilities",
"authors": ["MAID Team"],
"license": "MIT",
"homepage": "https://github.com/example/maid",
"keywords": ["stdlib", "components"]
},
"status": {
"is_loaded": true,
"is_available": true,
"can_unload": false,
"blocking_dependents": ["maid-classic-rpg"],
"load_order": 0
},
"dependencies": [],
"capabilities": {
"provides": ["stdlib"],
"requires": []
},
"resources": {
"systems": 5,
"events": 12,
"commands": 15
}
}
Reload Content Pack¶
POST /admin/packs/{pack_name}/reload
Reload a content pack (unload and load again).
Required Role: ADMIN
Response (200):
{
"success": true,
"message": "Content pack 'maid-stdlib' reloaded successfully",
"pack_name": "maid-stdlib",
"reload_time_ms": 125.5
}
Get Pack Dependencies¶
GET /admin/packs/{pack_name}/dependencies
Get the dependency tree for a content pack.
Query Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| include_transitive | bool | Include indirect dependencies |
Get Pack Dependents¶
GET /admin/packs/{pack_name}/dependents
Get packs that depend on this pack.
Get Load Order¶
GET /admin/packs/load-order
Get the order in which packs were loaded.
WebSocket Endpoints¶
Main Admin WebSocket¶
WS /admin/ws
Main WebSocket connection for subscribing to various channels.
Authentication: Include JWT token as query parameter or in first message.
Subscribe to channels:
Receive updates:
{
"type": "player_connected",
"data": {
"player_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "player1"
}
}
Dashboard WebSocket¶
WS /admin/dashboard/ws
Real-time dashboard metrics streaming.
Receive metrics:
{
"type": "metrics_update",
"data": {
"timestamp": "2024-01-15T10:30:00Z",
"tick_ms": 2.5,
"players_online": 42,
"memory_mb": 256.5
}
}
Log Stream WebSocket¶
WS /admin/logs/stream
Real-time log streaming via WebSocket.
Connection confirmation:
Receive log entries:
{
"type": "log_entry",
"data": {
"timestamp": "2024-01-15T10:30:00Z",
"level": "INFO",
"logger_name": "maid_engine.core.engine",
"message": "Player connected: player1"
}
}
Send ping:
Receive pong:
Error Responses¶
All endpoints return standard HTTP error codes with JSON error bodies:
| Code | Description |
|---|---|
400 |
Bad Request - Invalid input |
401 |
Unauthorized - Invalid or missing token |
403 |
Forbidden - Insufficient permissions |
404 |
Not Found - Resource does not exist |
409 |
Conflict - Resource already exists |
500 |
Internal Server Error |
503 |
Service Unavailable - Engine not ready |
Rate Limiting¶
The Admin API may implement rate limiting. When rate limited, you will receive:
- Status code:
429 Too Many Requests - Headers:
X-RateLimit-Limit: Maximum requests per windowX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Timestamp when limit resets