Files
languard-servers-manager/CLAUDE.md
Tran G. (Revernomad) Khoa 3025c2021c feat: per-mission params, default config values, and mods bug docs
- Add per-mission params to rotation (MissionRotationItem.params); falls
  back to default_mission_params, then omits entirely if both empty
- Add key-value widget to ConfigEditor for default_mission_params field
- Add MissionParamsEditor component for editing param key/value/type rows
- Bump config schema to 1.1.0 with migration from 1.0.0
- Add normalize_section() to Protocol and ArmaConfigGenerator for
  read-time backfill of old stored rows
- Set Arma3 BasicConfig and ProfileConfig defaults from basic.cfg /
  Administrator.Arma3Profile
- Document 3 known Mods tab bugs in CLAUDE.md for next-session fix
2026-04-19 19:28:46 +07:00

7.1 KiB
Raw Blame History

Languard Server Manager

Quick Start

# Backend (from backend/)
python -m uvicorn main:app --host 0.0.0.0 --port 8000 --reload

# Frontend (from frontend/)
npx vite --host

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.

Known Bugs — Mods Tab (fix next session)

Three bugs prevent the Mods tab from working correctly:

Bug 1 — Save fails with TypeError (critical)

Arma3ModManager.set_enabled_mods() calls config_repo.upsert_section() with wrong keyword argument names:

  • Passes data= → should be config_data=
  • Passes expected_version= → should be expected_config_version=
  • Missing required game_type= argument
  • Missing required schema_version= argument

File: backend/adapters/arma3/mod_manager.py, set_enabled_mods() method (~line 127)

Bug 2 — Mods not applied on server start (critical)

service.py start_server() reads mods from a server_mods JOIN mods table (SQLAlchemy query, ~line 246) — but those tables are never populated by the Mods tab UI. The correct source is config_repo.get_section(server_id, "mods")["enabled_mods"]. The start flow needs to read from config_repo instead of the dead server_mods table join.

File: backend/core/servers/service.py, start_server() method (~line 242255)

Bug 3 — Wrong mod folder location (UX)

list_available_mods() scans the server root (get_server_dir()) for @* folders. Mods should live in a mods/ subfolder: {server_dir}/mods/@ModName. Needs:

  1. Change scan path: server_dir / "mods" instead of server_dir
  2. Ensure the mods/ subdirectory is created by ensure_server_dirs (add "mods" to the Arma3 get_server_dir_layout())
  3. Update CLAUDE.md + user docs to say mods go in D:/ImContainer/Arma3Server/{id}/mods/@ModName

File: backend/adapters/arma3/mod_manager.py, list_available_mods() and _server_dir() (~line 4788) Also: backend/adapters/arma3/adapter.py, get_server_dir_layout() (add "mods" entry)