Backend: - Complete FastAPI backend with 42+ REST endpoints (auth, servers, config, players, bans, missions, mods, games, system) - Game adapter architecture with Arma 3 as first-class adapter - WebSocket real-time events for status, metrics, logs, players - Background thread system (process monitor, metrics, log tail, RCon poller) - Fernet encryption for sensitive config fields at rest - JWT auth with admin/viewer roles, bcrypt password hashing - SQLite with WAL mode, parameterized queries, migration system - APScheduler cleanup jobs for logs, metrics, events Frontend: - Server Detail page with 7 tabs (overview, config, players, bans, missions, mods, logs) - Settings page with password change and admin user management - Create Server wizard (4-step; known bug: silent validation failure) - New hooks: useServerDetail, useAuth, useGames - New components: ServerHeader, ConfigEditor, PlayerTable, BanTable, MissionList, ModList, LogViewer, PasswordChange, UserManager - WebSocket onEvent callback for real-time log accumulation - 120 unit tests passing (Vitest + React Testing Library) Docs: - Added .gitignore, CLAUDE.md, README.md - Updated FRONTEND.md, ARCHITECTURE.md with current implementation state - Added .env.example for backend configuration Known issues: - Create Server form: "Next" buttons don't validate before advancing, causing silent submit failure when fields are invalid - Config sub-tabs need UX redesign for non-technical users
53 lines
1.8 KiB
Python
53 lines
1.8 KiB
Python
"""Typed adapter exceptions. Core catches these specifically."""
|
|
|
|
|
|
class AdapterError(Exception):
|
|
"""Base for all adapter errors."""
|
|
pass
|
|
|
|
|
|
class ConfigWriteError(AdapterError):
|
|
"""Atomic file write failed. Temp files are already cleaned up."""
|
|
def __init__(self, path: str, detail: str):
|
|
self.path = path
|
|
self.detail = detail
|
|
super().__init__(f"Config write failed at {path}: {detail}")
|
|
|
|
|
|
class ConfigValidationError(AdapterError):
|
|
"""Adapter Pydantic model rejected the config values."""
|
|
def __init__(self, section: str, errors: list[dict]):
|
|
self.section = section
|
|
self.errors = errors
|
|
super().__init__(f"Config validation failed for section '{section}': {errors}")
|
|
|
|
|
|
class ConfigMigrationError(AdapterError):
|
|
"""migrate_config() could not transform old schema. Core keeps original."""
|
|
def __init__(self, from_version: str, detail: str):
|
|
self.from_version = from_version
|
|
self.detail = detail
|
|
super().__init__(f"Config migration from {from_version} failed: {detail}")
|
|
|
|
|
|
class LaunchArgsError(AdapterError):
|
|
"""build_launch_args() failed (missing mod path, bad config value)."""
|
|
def __init__(self, detail: str):
|
|
self.detail = detail
|
|
super().__init__(f"Launch args error: {detail}")
|
|
|
|
|
|
class RemoteAdminError(AdapterError):
|
|
"""Remote admin connection or command failed."""
|
|
def __init__(self, detail: str, recoverable: bool = True):
|
|
self.detail = detail
|
|
self.recoverable = recoverable
|
|
super().__init__(f"Remote admin error: {detail}")
|
|
|
|
|
|
class ExeNotAllowedError(AdapterError):
|
|
"""Executable not in adapter allowlist."""
|
|
def __init__(self, exe: str, allowed: list[str]):
|
|
self.exe = exe
|
|
self.allowed = allowed
|
|
super().__init__(f"Executable '{exe}' not allowed. Allowed: {allowed}") |