Files
Tran G. (Revernomad) Khoa fa95587567 docs: expand README quick start with full dev/debug setup
- Step-by-step backend setup: venv, secret key generation (openssl +
  Fernet), .env configuration with annotated minimum values
- VS Code launch.json snippets for backend (debugpy/uvicorn) and
  frontend (Chrome with source maps)
- Vite proxy detail (/api → :8000, /ws → ws://:8000)
- Backend pytest commands alongside existing frontend test section
- Playwright headed/UI mode instructions for E2E debugging
- Updated unit test count to 173; removed stale E2E count
- CLAUDE.md quick start trimmed to point at README for full setup
2026-04-20 10:53:14 +07:00

6.2 KiB

Languard Server Manager

Quick Start

# Backend (from backend/, venv must be active)
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

# Frontend (from frontend/)
npm run dev

Architecture

FastAPI + SQLite backend, React 19 + TypeScript + Vite frontend. See ARCHITECTURE.md for full details.

Key Rules

  • Frontend types must match API response shapes, NOT database schema columns
  • There is no REST endpoint for logs — logs are only pushed via WebSocket events
  • WebSocket onEvent callback is the mechanism for receiving real-time log entries
  • Config updates use optimistic locking (config_version) — 409 on conflict
  • Sensitive config fields are encrypted at rest with Fernet

Current Implementation Status

Backend: Fully implemented (42+ endpoints)

All routers, services, repositories, game adapter system, WebSocket, background threads, and scheduled cleanup are complete.

Frontend: Fully implemented (baseline)

Route Status Notes
/login Complete Zod + react-hook-form validation
/ Complete Dashboard with server grid + Start/Stop/Restart quick actions
/servers/:id Complete 7-tab detail page (overview, config, players, bans, missions, mods, logs)
/servers/new Complete 4-step wizard with per-step validation via trigger()
/settings Complete Password change + admin user management

Frontend Type Mapping (API → Frontend)

API Resource Frontend Type Key Fields
Server (enriched) Server in useServers.ts game_port, current_players, max_players, cpu_percent, ram_mb
Mission Mission in useServerDetail.ts name, filename, size_bytes, terrain
Mod Mod in useServerDetail.ts name, path, size_bytes, enabled, display_name, workshop_id
Ban Ban in useServerDetail.ts id, server_id, guid, name, reason, banned_by, banned_at, expires_at, is_active, game_data
Player Player in useServerDetail.ts id, slot_id, name, guid, ip, ping
LogFile LogFile in useServerDetail.ts filename, size_bytes, modified_at

UX Enhancement Plan — ALL PHASES COMPLETE

Plan file: .claude/plan/arma3-ux-enhancement.md

Phase Feature Status
1 Config field UI widgets (textarea/toggle/select/tag-list per field) Done
2 Mission rotation table + multi-file upload Done
3 Mod display names (mod.cpp) + split-pane selector Done
4 Player Kick/Ban from Players tab via RCon Done
5 Historical log file browser + live log level filter Done

Endpoints added:

  • GET /api/servers/{id}/config/schema — per-field widget hints
  • GET|PUT /api/servers/{id}/missions/rotation — mission rotation with optimistic locking
  • POST /api/servers/{id}/players/{slot_id}/kick — kick via RCon
  • POST /api/servers/{id}/players/{slot_id}/ban — ban via RCon + DB record
  • GET /api/servers/{id}/logfiles — list .rpt log files
  • GET /api/servers/{id}/logfiles/{filename}/download — download log file
  • DELETE /api/servers/{id}/logfiles/{filename} — delete log file

Test Commands

# Frontend unit tests
cd frontend && npx vitest run

# Frontend type check
cd frontend && npx tsc --noEmit

# Backend (no test suite yet)

Key Implementation Notes

  • BanRepository.create() takes expires_at (ISO string), not duration_minutes — convert in service
  • slot_id is stored as a string in the players table — cast with str(slot_id) in queries
  • Config field names in ServerConfig Pydantic model: password_admin (not admin_password), battleye (not battle_eye), disable_von (not von)
  • Arma 3 log files are located at {exe_path_parent}/server/*.rpt (next to the .exe), NOT in languard's servers/{id}/ data directory. Code that finds log files must use Path(server["exe_path"]).parent to resolve the log directory.
  • Config UI schema now covers all ~80 Arma 3 fields across 5 sections (server, basic, profile, launch, rcon) with per-field widget hints (text, toggle, select, number, password, tag-list, hidden, textarea, key-value). The missions field in the server section is marked hidden because mission rotation is managed via the dedicated Missions tab.
  • Arma 3 per-mission params: ServerConfig.missions is now list[MissionRotationItem] (adds optional params: dict). A new default_mission_params field holds server-wide defaults. Config version bumped to "1.1.0". _render_server_cfg() now emits a class Missions { ... } block when the rotation is non-empty; class Params inside each mission uses per-mission params → global defaults → omit (in that priority order). The MissionRotationEntry.params is edited per-row in the Missions tab via MissionParamsEditor; default_mission_params is edited in the Config tab via the key-value widget.
  • Config version migration: migrate_config("1.0.0", ...) backfills params: {} on each existing rotation entry and adds default_mission_params: {}. normalize_section() does the same on reads for stored rows that pre-date the migration run.

Mods Tab — Implementation Notes

  • Mods go in {server_data_dir}/{server_id}/mods/@ModName (e.g. D:/ImContainer/Arma3Server/1/mods/@CBA_A3/)
  • Enabled mods config schema: {"enabled_mods": [{"name": "@CBA_A3", "is_server_mod": false}]}
    • Old string-list format is auto-migrated to the dict format on read
    • is_server_mod: true-serverMod= arg; false-mod= arg
  • list_available_mods() scans {server_dir}/mods/ for @* directories
  • set_enabled_mods() stores the new dict format; validates names against disk
  • Server start reads mods from game_configs via config_repo, NOT from the dead server_mods table
  • Directory scaffold: all 4 Arma3 subdirs (server/, battleye/, mpmissions/, mods/) are created on server create and backfilled on startup; each gets a README.txt if not already present