From fe3bd81cae8448587c6bf6b968cf986632f5afc1 Mon Sep 17 00:00:00 2001 From: "Tran G. (Revernomad) Khoa" Date: Fri, 17 Apr 2026 20:35:39 +0700 Subject: [PATCH] docs: update API.md, FRONTEND.md, MODULES.md, CLAUDE.md for Phase 1 and 2 completion - API.md: add GET /config/schema endpoint docs; add GET|PUT /missions/rotation endpoints; fix mission response shape (name/filename/size_bytes/terrain); mark Phase 1+2 as done - FRONTEND.md: add TagListEditor, useServerConfigSchema, useServerMissionRotation, useUpdateMissionRotation; update Mission/Mod type notes; remove planned hooks now live - MODULES.md: update config_generator and missions_router descriptions - CLAUDE.md: mark Phase 1 and 2 as Done --- API.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++----- CLAUDE.md | 8 ++-- FRONTEND.md | 25 ++++++------ MODULES.md | 4 +- 4 files changed, 118 insertions(+), 27 deletions(-) diff --git a/API.md b/API.md index 826b07d..07397e7 100644 --- a/API.md +++ b/API.md @@ -790,6 +790,39 @@ Get all config sections combined. Sensitive fields (passwords) are masked with ` --- +### GET /servers/{server_id}/config/schema + +Returns per-field widget hints for the frontend config editor. Used by `ConfigEditor` to render the correct UI widget (text box, toggle, select, tag list, etc.) for each field. + +**Auth:** Required (any role) + +**Response 200:** + +```json +{ + "success": true, + "data": { + "server": { + "hostname": { "widget": "text", "label": "Server Hostname" }, + "max_players": { "widget": "number", "label": "Max Players", "min": 1, "max": 1000 }, + "password": { "widget": "password", "label": "Player Password" }, + "forced_difficulty": { "widget": "select", "label": "Difficulty Preset", "options": ["Recruit", "Regular", "Veteran", "Custom"] }, + "battleye": { "widget": "toggle", "label": "BattleEye Anti-Cheat" }, + "motd_lines": { "widget": "textarea", "label": "Message of the Day (one line per row)" }, + "admin_uids": { "widget": "tag-list", "label": "Admin Steam UIDs", "placeholder": "76561198000000000" } + }, + "rcon": { + "rcon_password": { "widget": "password", "label": "RCon Password" } + } + }, + "error": null +} +``` + +Returns `{}` if the adapter does not implement `get_ui_schema()`. + +--- + ### GET /servers/{server_id}/config/preview Rendered config for preview. Admin only because it may contain plaintext credentials. @@ -1182,10 +1215,10 @@ List all available mission/scenario files on disk. "total": 2, "missions": [ { + "name": "MyMission.Altis", "filename": "MyMission.Altis.pbo", - "mission_name": "MyMission.Altis", - "terrain": "Altis", - "file_size": 102400 + "size_bytes": 102400, + "terrain": "Altis" } ] }, @@ -1226,6 +1259,63 @@ Upload a mission file. **Multipart form-data**. Maximum file size: **500 MB**. F --- +### GET /servers/{server_id}/missions/rotation + +Get the current mission rotation from the server config. + +**Auth:** Required (any role) + +**Response 200:** + +```json +{ + "success": true, + "data": { + "missions": [ + { "name": "MyMission.Altis", "difficulty": "Regular" }, + { "name": "TvT.Stratis", "difficulty": "Veteran" } + ] + }, + "error": null +} +``` + +--- + +### PUT /servers/{server_id}/missions/rotation + +Replace the mission rotation. Uses **optimistic locking** — must include `config_version` from the last server config read. + +**Auth:** Admin required + +**Request:** + +```json +{ + "missions": [ + { "name": "MyMission.Altis", "difficulty": "Regular" }, + { "name": "TvT.Stratis", "difficulty": "" } + ], + "config_version": 3 +} +``` + +`difficulty` can be `""` for default, or one of `"Recruit"`, `"Regular"`, `"Veteran"`, `"Custom"`. + +**Response 200:** + +```json +{ + "success": true, + "data": { "missions": [ ... ] }, + "error": null +} +``` + +**Error 409:** Config version conflict — re-fetch and retry. + +--- + ### DELETE /servers/{server_id}/missions/{filename} Delete a mission file by filename. Removes the file from disk. @@ -1491,20 +1581,20 @@ Implemented via `slowapi` middleware. ## Upcoming Endpoints (UX Enhancement Plan) -These endpoints are planned and will be added during the Arma 3 UX Enhancement implementation. They do not exist yet. +Endpoints planned during the Arma 3 UX Enhancement. ✅ = implemented. -### Phase 1 — Config UI Schema +### Phase 1 — Config UI Schema ✅ | Method | Path | Auth | Description | |--------|------|------|-------------| -| GET | `/servers/{server_id}/config/ui-schema` | Bearer | Returns widget hints per field (`widget`, `label`, `placeholder`) for the frontend config editor | +| GET ✅ | `/servers/{server_id}/config/schema` | Bearer | Returns widget hints per field for the frontend config editor | -### Phase 2 — Mission Rotation +### Phase 2 — Mission Rotation ✅ | Method | Path | Auth | Description | |--------|------|------|-------------| -| GET | `/servers/{server_id}/missions/rotation` | Bearer | Get current mission rotation list | -| PUT | `/servers/{server_id}/missions/rotation` | Admin | Replace mission rotation (requires `config_version` for optimistic locking) | +| GET ✅ | `/servers/{server_id}/missions/rotation` | Bearer | Get current mission rotation list | +| PUT ✅ | `/servers/{server_id}/missions/rotation` | Admin | Replace mission rotation (requires `config_version` for optimistic locking) | ### Phase 4 — Player Kick / Ban diff --git a/CLAUDE.md b/CLAUDE.md index 0d2d31e..0fef8e1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,15 +58,15 @@ Types below reflect the **current** API shape. Fields marked `(planned)` will be | Phase | Feature | Status | |-------|---------|--------| -| 1 | Config field UI widgets (textarea/toggle/select/tag-list per field) | Pending | -| 2 | Mission rotation table + multi-file upload | Pending | +| 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 | Pending | | 4 | Player Kick/Ban from Players tab via RCon | Pending | | 5 | Historical log file browser + live log level filter | Pending | **New endpoints added by the plan:** -- `GET /api/servers/{id}/config/schema` — per-field widget hints -- `GET|PUT /api/servers/{id}/missions/rotation` — mission rotation +- `GET /api/servers/{id}/config/schema` — per-field widget hints (**implemented**) +- `GET|PUT /api/servers/{id}/missions/rotation` — mission rotation (**implemented**) - `POST /api/servers/{id}/players/{slot_id}/kick` - `POST /api/servers/{id}/players/{slot_id}/ban` - `GET /api/servers/{id}/logfiles` diff --git a/FRONTEND.md b/FRONTEND.md index 6d75bd1..68d3047 100644 --- a/FRONTEND.md +++ b/FRONTEND.md @@ -65,17 +65,18 @@ frontend/src/ │ ├── servers/ │ │ ├── ServerCard.tsx # Server card with actions │ │ ├── ServerHeader.tsx # Server name, status, stats grid, lifecycle buttons -│ │ ├── ConfigEditor.tsx # Tabbed config section editor with optimistic locking +│ │ ├── ConfigEditor.tsx # Tabbed config section editor; per-field widgets via useServerConfigSchema │ │ ├── PlayerTable.tsx # Current players + history with search │ │ ├── BanTable.tsx # Ban list + create/revoke form -│ │ ├── MissionList.tsx # Mission list + upload/delete .pbo +│ │ ├── MissionList.tsx # Available missions + Mission Rotation sections; multi-file upload │ │ ├── ModList.tsx # Mod list with enable/disable checkboxes │ │ └── LogViewer.tsx # Log display with level filter (receives logs as props) │ ├── settings/ │ │ ├── PasswordChange.tsx # Password change form │ │ └── UserManager.tsx # User CRUD table (admin only) │ └── ui/ -│ └── StatusLed.tsx # Colored status indicator dot +│ ├── StatusLed.tsx # Colored status indicator dot +│ └── TagListEditor.tsx # Dynamic string-list editor (add/remove items) │ └── __tests__/ ├── api.test.ts # Axios interceptor tests @@ -129,10 +130,10 @@ App │ │ │ ├── ServerHeader (status, stats, lifecycle buttons) │ │ │ ├── Tab bar (Overview, Config, Players, Bans, Missions, Mods, Logs) │ │ │ ├── OverviewTab (stats grid, executable path) -│ │ │ ├── ConfigEditor (section tabs, edit form, optimistic locking) +│ │ │ ├── ConfigEditor (section tabs, per-field widgets from schema, optimistic locking) │ │ │ ├── PlayerTable (current + history with search) │ │ │ ├── BanTable (ban list + create/revoke) -│ │ │ ├── MissionList (upload .pbo, delete) +│ │ │ ├── MissionList (Available + Rotation sections, multi-file upload) │ │ │ ├── ModList (enable/disable checkboxes) │ │ │ └── LogViewer (level filter, real-time via WebSocket onEvent) │ │ ├── /servers/new → CreateServerPage @@ -169,16 +170,19 @@ All server data flows through TanStack Query hooks: |---|---|---|---| | `useServerConfig(id)` | Query | `GET /api/servers/:id/config` | `["servers", id, "config"]` | | `useServerConfigSection(id, section)` | Query | `GET /api/servers/:id/config/:section` | `["servers", id, "config", section]` | +| `useServerConfigSchema(id)` | Query | `GET /api/servers/:id/config/schema` | `["servers", id, "config", "schema"]` | | `useServerConfigPreview(id)` | Query | `GET /api/servers/:id/config/preview` | `["servers", id, "config", "preview"]` | | `useServerPlayers(id)` | Query | `GET /api/servers/:id/players` | `["players", id]` | | `useServerPlayerHistory(id, opts?)` | Query | `GET /api/servers/:id/players/history` | `["players", id, "history", opts]` | | `useServerBans(id)` | Query | `GET /api/servers/:id/bans` | `["bans", id]` | | `useServerMissions(id)` | Query | `GET /api/servers/:id/missions` | `["missions", id]` | +| `useServerMissionRotation(id)` | Query | `GET /api/servers/:id/missions/rotation` | `["missions", id, "rotation"]` | | `useServerMods(id)` | Query | `GET /api/servers/:id/mods` | `["mods", id]` | | `useUpdateConfigSection(id, section)` | Mutation | `PUT /api/servers/:id/config/:section` | Invalidates config keys | | `useCreateBan(id)` | Mutation | `POST /api/servers/:id/bans` | Invalidates `["bans", id]` | | `useRevokeBan(id)` | Mutation | `DELETE /api/servers/:id/bans/:banId` | Invalidates `["bans", id]` | -| `useUploadMission(id)` | Mutation | `POST /api/servers/:id/missions` (multipart) | Invalidates `["missions", id]` | +| `useUploadMission(id)` | Mutation | `POST /api/servers/:id/missions` (multipart, `File[]`) | Invalidates `["missions", id]` | +| `useUpdateMissionRotation(id)` | Mutation | `PUT /api/servers/:id/missions/rotation` | Invalidates rotation + server config | | `useDeleteMission(id)` | Mutation | `DELETE /api/servers/:id/missions/:filename` | Invalidates `["missions", id]` | | `useSetEnabledMods(id)` | Mutation | `PUT /api/servers/:id/mods/enabled` | Invalidates `["mods", id]` | | `useSendCommand(id)` | Mutation | `POST /api/servers/:id/rcon/command` | No invalidation | @@ -205,18 +209,15 @@ All server data flows through TanStack Query hooks: **Key type notes**: - `Server` type in `useServers.ts` uses `game_port`, `current_players`, `max_players` (matches enriched API response) -- `Mission` type: `{ name, filename, size_bytes }` — `terrain` field planned (Phase 2 UX enhancement) -- `Mod` type: `{ name, path, size_bytes, enabled }` — `display_name`, `workshop_id` fields planned (Phase 3 UX enhancement) +- `Mission` type: `{ name, filename, size_bytes, terrain }` — terrain parsed from filename +- `Mod` type: `{ name, path, size_bytes, enabled, display_name, workshop_id }` — `display_name`/`workshop_id` from mod.cpp/meta.cpp (planned Phase 3) - `Ban` type: `{ id, server_id, guid, name, reason, banned_by, banned_at, expires_at, is_active, game_data }` (matches API) - There is no REST endpoint for logs — logs are only pushed via WebSocket events -**Planned hooks (UX Enhancement Plan):** +**Planned hooks (UX Enhancement Plan — remaining):** | Hook | Phase | Endpoint | |---|---|---| -| `useConfigUISchema(serverId)` | Phase 1 | `GET /api/servers/:id/config/ui-schema` | -| `useMissionRotation(id)` | Phase 2 | `GET /api/servers/:id/missions/rotation` | -| `useUpdateMissionRotation(id)` | Phase 2 | `PUT /api/servers/:id/missions/rotation` | | `useKickPlayer(id)` | Phase 4 | `POST /api/servers/:id/players/:slot_id/kick` | | `useBanPlayer(id)` | Phase 4 | `POST /api/servers/:id/players/:slot_id/ban` | | `useLogFiles(id)` | Phase 5 | `GET /api/servers/:id/logfiles` | diff --git a/MODULES.md b/MODULES.md index 379b2fb..b30e6ef 100644 --- a/MODULES.md +++ b/MODULES.md @@ -49,7 +49,7 @@ All 7 capabilities implemented: | Module | Class | Purpose | |---|---|---| | `adapter.py` | `Arma3Adapter` | Composite adapter declaring all capabilities | -| `config_generator.py` | `Arma3ConfigGenerator` | 5 Pydantic config models, writes server.cfg/basic.cfg/Arma3Profile/beserver.cfg, builds launch args | +| `config_generator.py` | `Arma3ConfigGenerator` | 5 Pydantic config models, writes server.cfg/basic.cfg/Arma3Profile/beserver.cfg, builds launch args, `get_ui_schema()` for per-field widget hints | | `process_config.py` | `Arma3ProcessConfig` | Allowed executables, port conventions (game+1/+2/+3), directory layout | | `log_parser.py` | `RPTParser` | Regex-based .rpt log parser, log file resolver | | `rcon_client.py` | `BERConClient` | BattlEye RCon v2 UDP protocol implementation | @@ -74,7 +74,7 @@ All 7 capabilities implemented: | `router.py` | Server CRUD, lifecycle (start/stop/restart/kill), config read/write/preview, RCon command | | `players_router.py` | Player list, player history | | `bans_router.py` | Ban CRUD with bans.txt file sync | -| `missions_router.py` | Mission list, .pbo upload (500MB), delete | +| `missions_router.py` | Mission list, .pbo upload (500MB), delete, GET/PUT rotation | | `mods_router.py` | List mods, set enabled mods | | `service.py` | `ServerService` — orchestrates all lifecycle operations, config writes, thread management | | `schemas.py` | Pydantic models: CreateServerRequest, UpdateServerRequest, StopServerRequest |