Architecture
Technical architecture and system design of PipeWorks MUD Server.
Overview
PipeWorks MUD Server uses a modern three-tier architecture:
FastAPI backend - RESTful API server
Gradio frontend - Web-based client interface
SQLite database - Persistent data storage
All components are written in Python 3.12+ using modern best practices.
Three-Tier Design
┌─────────────────────────────────────────────────────────────┐
│ Gradio Web Interface │
│ (Client Layer) │
│ http://localhost:7860 │
└────────────────────────┬────────────────────────────────────┘
│ HTTP/HTTPS
▼
┌─────────────────────────────────────────────────────────────┐
│ FastAPI REST API │
│ (Server Layer) │
│ http://localhost:8000 │
└────────────────────────┬────────────────────────────────────┘
│
┌────────────────┴────────────────┐
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Game Engine │ │ SQLite Database │
│ (Core Layer) │◄──────────┤ (Persistence) │
│ │ │ │
│ - World/Rooms │ │ - Players │
│ - Items │ │ - Sessions │
│ - Actions │ │ - Chat Messages │
└──────────────────┘ └──────────────────┘
Modular Client Architecture
The Gradio client uses a fully modular design:
src/mud_server/client/
├── app.py # Main entry point (~180 lines)
├── api/ # API client layer
│ ├── base.py # BaseAPIClient - common HTTP patterns
│ ├── auth.py # Authentication operations
│ ├── game.py # Game operations
│ ├── settings.py # Settings and server control
│ ├── admin.py # Admin operations
│ └── ollama.py # Ollama AI integration
├── ui/ # UI utilities
│ ├── validators.py # Input validation (100% coverage)
│ └── state.py # Gradio state builders
├── tabs/ # Tab modules
│ ├── login_tab.py # Login interface
│ ├── register_tab.py # Registration interface
│ ├── game_tab.py # Main gameplay interface
│ ├── settings_tab.py # Settings and server control
│ ├── database_tab.py # Admin database viewer
│ ├── ollama_tab.py # AI model management
│ └── help_tab.py # Help documentation
├── utils.py # Shared utilities
└── static/styles.css # Centralized CSS
Benefits:
Clear separation between API logic, validation, and UI
100% test coverage on API and UI utility modules (191 tests)
API clients work outside Gradio (CLI tools, tests, scripts)
Easy to extend with new features or tabs
System Components
Backend (FastAPI)
Located in src/mud_server/api/:
server.py- App initialization, CORS, routingroutes.py- All API endpointsmodels.py- Pydantic request/response modelsauth.py- Session managementpassword.py- Bcrypt password hashingpermissions.py- Role-based access control
Game Engine
Located in src/mud_server/core/:
engine.py- GameEngine class with all game logicworld.py- World, Room, Item dataclassesbus.py- Event bus for game event handlingevents.py- Event type constants
Event Bus Architecture
The event bus provides publish-subscribe infrastructure for game events. It follows these key principles:
Synchronous Emit: Events are committed to the log before handlers are notified. This ensures deterministic ordering via sequence numbers.
Immutable Events: Once emitted, events cannot be changed. They represent facts about what happened (Ledger truth).
Plugin-Ready: The bus is designed to support future plugin systems where plugins react to events but cannot intervene or block them.
┌─────────────────────────────────────────────────────────────────┐
│ Event Bus │
│ │
│ Engine.move() │
│ │ │
│ ▼ │
│ bus.emit("player:moved", {...}) │
│ │ │
│ ├── 1. Increment sequence (deterministic ordering) │
│ │ │
│ ├── 2. Create immutable MudEvent │
│ │ │
│ ├── 3. Append to event log (COMMITTED) │
│ │ │
│ └── 4. Notify handlers (async execution allowed) │
│ │
└─────────────────────────────────────────────────────────────────┘
Event types follow “domain:action” format in past tense (e.g., player:moved,
item:picked_up) to emphasize they record facts, not requests.
Database Layer
Located in src/mud_server/db/:
database.py- SQLite operations, schema, CRUD
Data Flow
Request Flow:
Client - User interacts with Gradio interface
API Call - Client sends HTTP request to FastAPI
Session Validation - Server validates session and permissions
Command Parsing - Server parses command and arguments
Game Logic - Engine executes command
Database - Engine reads/writes to SQLite
Response - Server returns result to client
Display - Client updates interface
Technology Stack
Component |
Technology |
Purpose |
|---|---|---|
Backend |
FastAPI 0.125+ |
REST API framework |
Frontend |
Gradio 6.2+ |
Web interface |
Server |
Uvicorn 0.38+ |
ASGI server |
Database |
SQLite 3 |
Data persistence |
Auth |
Passlib + Bcrypt |
Password hashing |
Testing |
pytest 8.3+ |
Test framework |
Linting |
Ruff 0.8+ |
Code quality |
Formatting |
Black 24.10+ |
Code style |
Type Checking |
Mypy 1.13+ |
Static analysis |
Key Design Patterns
Session Management
UUID-based sessions stored in memory and database
Session tuples:
(user_id: int, role: str, character_id: int | None)Activity tracking updated on each API call
Validation decorator:
@validate_session()
Role-Based Access Control
Four roles with hierarchical permissions:
Player - Basic gameplay
WorldBuilder - Player + content creation
Admin - WorldBuilder + user management
Superuser - Admin + role management, full access
Command Pattern
Command parsing splits into
cmdandargsRouter delegates to appropriate engine method
Response model:
CommandResponsewith success/messageError handling via HTTP exceptions
Repository Pattern
Database layer isolated in
database.pyCRUD operations as separate functions
JSON serialization for complex types
Connection management via context managers
Database Schema
Users Table
id(INTEGER, PRIMARY KEY)username(TEXT, UNIQUE)password_hash(TEXT)email_hash(TEXT, UNIQUE, NULLABLE) - placeholder for hashed emailsrole(TEXT) - Player, WorldBuilder, Admin, Superuseris_active(INTEGER)is_guest(INTEGER)guest_expires_at(TIMESTAMP, NULLABLE)account_origin(TEXT) - e.g. legacy, visitor, admincreated_at(TIMESTAMP)last_login(TIMESTAMP)tombstoned_at(TIMESTAMP, NULLABLE) - set for deactivated users; guest accounts are deleted on expiry
Characters Table
id(INTEGER, PRIMARY KEY)user_id(INTEGER, NULLABLE)name(TEXT, UNIQUE)inventory(TEXT) - JSON array of item IDsis_guest_created(INTEGER)created_at(TIMESTAMP)updated_at(TIMESTAMP)
Character Locations Table
character_id(INTEGER, PRIMARY KEY)room_id(TEXT)updated_at(TIMESTAMP)
Sessions Table
session_id(TEXT, UNIQUE) - UUIDuser_id(INTEGER)character_id(INTEGER, NULLABLE)created_at(TIMESTAMP)last_activity(TIMESTAMP)expires_at(TIMESTAMP, NULLABLE)client_type(TEXT)
Chat Messages Table
id(INTEGER, PRIMARY KEY)character_id(INTEGER, NULLABLE)user_id(INTEGER, NULLABLE)message(TEXT)room(TEXT)recipient_character_id(INTEGER, NULLABLE)timestamp(TIMESTAMP)
Security Considerations
Authentication
Password hashing: Bcrypt via passlib (intentionally slow, ~100ms per hash)
Password policy: NIST SP 800-63B aligned with comprehensive validation
Session IDs: UUID v4 (cryptographically random, hard to guess)
Session validation: Every API call validates session and extracts role
Role-based access: Four-tier permission system (Player < WorldBuilder < Admin < Superuser)
Password Policy
The STANDARD password policy enforces:
Minimum 12 characters (NIST recommended)
Common password rejection (150+ known weak passwords blocked)
Leet-speak detection (p@ssw0rd detected as “password” variant)
Sequential character detection (abc, 123, xyz patterns blocked)
Repeated character detection (aaa, 1111 patterns blocked)
Three policy levels available: BASIC (8 chars), STANDARD (12 chars), STRICT (16 chars + complexity).
See Security for complete details.
Known Limitations
SQLite concurrency limits for high-traffic deployments
No email verification (email hashes are placeholders for future use)
No two-factor authentication
Performance
Current Capacity
~50-100 concurrent players (SQLite limitation)
No caching (every request hits DB)
Synchronous DB operations
In-memory sessions (fast but not persistent)
Scaling Considerations
For larger deployments:
Migrate to PostgreSQL for concurrency
Add Redis for session storage
Implement caching layer
Use async database operations
Add load balancing