Tran G. (Revernomad) Khoa d45345a094 feat: fix mods tab, add client/server split, and scaffold server dirs
Mods tab bug fixes:
- mod_manager: fix wrong kwargs in set_enabled_mods, fix scan dir to use
  mods/ subdir instead of server root, migrate old string-list format to
  dict format on read
- service: replace dead server_mods SQL JOIN with get_enabled_mods()
  call through the mod_manager capability; pass is_server_mod to
  build_mod_args
- mods_router: accept list[EnabledModEntry] objects (name + is_server_mod)
  instead of bare strings

Client/server mod split:
- Mods now stored as list[{"name": str, "is_server_mod": bool}]; old
  string-list format auto-migrated on read
- is_server_mod=true routes to -serverMod= arg; false to -mod= arg
- ModList UI: amber Client/Server badge in selected pane; toggle button
  in split-pane selector

Directory scaffold:
- process_config: adds "mods" to dir layout; provides get_dir_readme()
  with per-directory README.txt content
- file_utils: ensure_server_dirs() gains readme_provider kwarg; writes
  README.txt idempotently if absent
- service.create_server: passes readme_provider via hasattr probe
- main.py startup: backfills all existing servers with correct subdirs
  and README files (idempotent)

Docs: API.md and FRONTEND.md updated for new mod schema and types
Test __init__.py files added for pytest discovery
2026-04-20 10:54:56 +07:00

Languard Server Manager

A multi-game server management platform with a Python/FastAPI backend and React/TypeScript frontend. Currently supports Arma 3 with an extensible adapter system for adding more games.

Tech Stack

Backend

  • Python 3.12+ / FastAPI — async REST API
  • SQLite with WAL mode — zero-config database
  • SQLAlchemy — raw SQL via text() queries (no ORM)
  • BattlEye RCon — UDP protocol v2 for remote admin
  • APScheduler — background cleanup jobs
  • psutil — process monitoring and resource metrics
  • JWT (python-jose) + bcrypt — authentication
  • Fernet (cryptography) — sensitive config field encryption

Frontend

  • React 19 / TypeScript 6 / Vite 8
  • TanStack Query v5 — server state management
  • Zustand 5 — client state (auth, UI)
  • Tailwind CSS — dark neumorphic design system
  • Playwright — E2E testing
  • Vitest + React Testing Library — unit tests (173 tests)

Quick Start

1 — Backend setup

cd backend

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate        # macOS / Linux
# venv\Scripts\activate         # Windows (cmd)
# venv\Scripts\Activate.ps1     # Windows (PowerShell)

pip install -r requirements.txt

Generate required secrets (one-time):

# Secret key (JWT signing)
openssl rand -hex 32

# Fernet encryption key (sensitive config fields at rest)
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

Copy .env.example to .env and fill in the two keys:

cp .env.example .env   # then open .env in your editor
# .env — minimum required values
LANGUARD_SECRET_KEY=<output of openssl command>
LANGUARD_ENCRYPTION_KEY=<output of Fernet command>
LANGUARD_ARMA3_DEFAULT_EXE=C:/path/to/arma3server_x64.exe

Start the backend (development — auto-reload on file changes):

uvicorn main:app --host 0.0.0.0 --port 8000 --reload

First run prints a randomly-generated admin password to the console. Log in and change it immediately via Settings → Change Password (or PUT /api/auth/password).

  • API root: http://localhost:8000
  • Interactive docs: http://localhost:8000/docs

Debug in VS Code: add this launch.json configuration:

{
  "name": "Backend — uvicorn",
  "type": "debugpy",
  "request": "launch",
  "module": "uvicorn",
  "args": ["main:app", "--host", "0.0.0.0", "--port", "8000"],
  "cwd": "${workspaceFolder}/backend",
  "env": { "PYTHONDONTWRITEBYTECODE": "1" },
  "jinja": true,
  "justMyCode": false
}

2 — Frontend setup

cd frontend
npm install
npm run dev

The Vite dev server starts at http://localhost:5173 and automatically proxies:

  • /api/*http://localhost:8000 (REST)
  • /ws/*ws://localhost:8000 (WebSocket)

Debug in VS Code: install the JavaScript Debugger extension (bundled by default), then add:

{
  "name": "Frontend — Vite (Chrome)",
  "type": "chrome",
  "request": "launch",
  "url": "http://localhost:5173",
  "webRoot": "${workspaceFolder}/frontend/src",
  "sourceMapPathOverrides": {
    "/@fs/*": "${workspaceFolder}/frontend/*"
  }
}

Start the Vite dev server first (npm run dev), then launch this config to attach Chrome DevTools with source-map support.


Running Tests

Backend

cd backend
source venv/bin/activate   # (if not already active)

pytest                             # all tests
pytest tests/adapters/arma3/ -v   # adapter tests only
pytest --tb=short -q               # quiet output

Frontend unit tests

cd frontend
npm test                          # single run (CI-friendly)
npm run test:watch                # watch mode during development
npx vitest run --coverage         # with coverage report

Frontend E2E tests (Playwright)

Start the backend and the Vite dev server first, then:

cd frontend
npm run test:e2e              # all E2E tests (headless)
npm run test:e2e:ui           # Playwright UI mode (interactive, great for debugging)
npx playwright test --headed  # watch tests run in an actual browser

Integration tests (require a live backend) live in tests-e2e/integration/. All other tests use API mocks and run without a backend.

Project Structure

languard-servers-manager/
├── backend/
│   ├── main.py                  # FastAPI app factory, lifespan, middleware
│   ├── config.py               # Pydantic Settings (env vars)
│   ├── database.py              # SQLAlchemy engine, migration runner
│   ├── dependencies.py          # FastAPI deps: auth, admin, server, adapter
│   ├── adapters/                # Game adapter system
│   │   ├── protocols.py         # Protocol definitions (7 capabilities)
│   │   ├── registry.py          # GameAdapterRegistry singleton
│   │   ├── exceptions.py        # Typed adapter exceptions
│   │   └── arma3/               # Arma 3 adapter (7/7 capabilities)
│   ├── core/
│   │   ├── auth/                # JWT auth, user CRUD
│   │   ├── servers/             # Server service, routers, process manager
│   │   ├── games/               # Game type discovery
│   │   ├── system/              # Health and status endpoints
│   │   ├── websocket/           # WS manager, broadcast thread
│   │   ├── threads/             # Background thread registry
│   │   ├── dal/                 # Data access layer (repositories)
│   │   ├── jobs/                # APScheduler cleanup jobs
│   │   ├── utils/               # Crypto, file utils, port checker
│   │   └── migrations/          # SQL migration scripts
│   └── requirements.txt
├── frontend/
│   ├── src/
│   │   ├── App.tsx              # Router + auth guard
│   │   ├── pages/               # LoginPage, DashboardPage, ServerDetailPage, CreateServerPage, SettingsPage
│   │   ├── components/         # Sidebar, ServerCard, ConfigEditor, PlayerTable, BanTable, MissionList, ModList, LogViewer, StatusLed
│   │   ├── hooks/               # useServers, useServerDetail, useAuth, useGames, useWebSocket
│   │   ├── store/               # auth.store, ui.store (Zustand)
│   │   ├── lib/                 # api.ts (Axios client)
│   │   └── __tests__/          # Vitest unit tests (173 tests)
│   ├── tests-e2e/               # Playwright E2E tests
│   └── playwright.config.ts
├── API.md                       # REST + WebSocket API reference
├── ARCHITECTURE.md              # System architecture overview
├── DATABASE.md                  # Database schema reference
├── FRONTEND.md                  # Frontend architecture and components
├── MODULES.md                   # Module-by-module reference
└── THREADING.md                 # Background threading model

Environment Variables

Variable Default Description
LANGUARD_SECRET_KEY (required) JWT signing key
LANGUARD_ENCRYPTION_KEY (required) Fernet key for sensitive config fields
LANGUARD_DB_PATH ./languard.db SQLite database path
LANGUARD_SERVERS_DIR ./servers Base directory for server data
LANGUARD_HOST 0.0.0.0 Listen host
LANGUARD_PORT 8000 Listen port
LANGUARD_CORS_ORIGINS ["http://localhost:5173"] CORS allowed origins
LANGUARD_LOG_RETENTION_DAYS 7 Log cleanup retention
LANGUARD_METRICS_RETENTION_DAYS 30 Metrics cleanup retention
LANGUARD_PLAYER_HISTORY_RETENTION_DAYS 90 Player history retention
LANGUARD_JWT_EXPIRE_HOURS 24 JWT token expiry
LANGUARD_ARMA3_DEFAULT_EXE (required for Arma 3) Default Arma 3 executable path

Documentation

  • ARCHITECTURE.md — System design, component diagram, security model
  • API.md — Complete REST + WebSocket API reference
  • DATABASE.md — Schema, tables, indexes, migration system
  • FRONTEND.md — React component tree, state management, design system
  • MODULES.md — File-by-file module reference
  • THREADING.md — Background thread model and concurrency
Description
No description provided
Readme 1,007 KiB
Languages
TypeScript 52.5%
Python 46.1%
CSS 0.9%
JavaScript 0.4%