docs: mark phases 3-5 complete, update API/FRONTEND/MODULES/CLAUDE.md
This commit is contained in:
@@ -14,9 +14,9 @@
|
||||
|-------|--------|------------------|
|
||||
| 1 — Config UI Schema | `[x] done` | TagListEditor, useServerConfigSchema, ConfigEditor widget routing, backend get_ui_schema + endpoint |
|
||||
| 2 — Mission Rotation | `[x] done` | terrain in list_missions, rotation GET/PUT endpoints, MissionRotationEntry type, useServerMissionRotation/useUpdateMissionRotation hooks, multi-file upload, MissionList redesigned with Available + Rotation sections |
|
||||
| 3 — Mod Display Names + Split Pane | `[ ] not started` | |
|
||||
| 4 — Player Kick/Ban | `[ ] not started` | |
|
||||
| 5 — Log File Browser | `[ ] not started` | |
|
||||
| 3 — Mod Display Names + Split Pane | `[x] done` | _parse_mod_cpp/_parse_meta_cpp in mod_manager, ModList split-pane redesign |
|
||||
| 4 — Player Kick/Ban | `[x] done` | get_by_slot in PlayerRepository, get_rcon_client in ThreadRegistry, kick/ban endpoints, PlayerTable modals |
|
||||
| 5 — Log File Browser | `[x] done` | list_log_files/get_log_file_path in RPTParser, logfiles_router (GET/download/DELETE), LogViewer file browser section |
|
||||
|
||||
**How to resume:** Read this table first. Find the first phase that is not `[x] done`. Read only that phase section — do not re-read earlier phases. Run `cd frontend && npx tsc --noEmit` to confirm the build is clean before making any changes.
|
||||
|
||||
|
||||
13
API.md
13
API.md
@@ -1596,16 +1596,17 @@ Endpoints planned during the Arma 3 UX Enhancement. ✅ = implemented.
|
||||
| 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
|
||||
### Phase 4 — Player Kick / Ban ✅
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/servers/{server_id}/players/{slot_id}/kick` | Admin | Kick player by slot ID via RCon; requires `reason` in body |
|
||||
| POST | `/servers/{server_id}/players/{slot_id}/ban` | Admin | Ban player by slot ID via RCon + DB; requires `reason` and optional `duration_minutes` (`null` = permanent) |
|
||||
| POST ✅ | `/servers/{server_id}/players/{slot_id}/kick` | Admin | Kick player by slot ID via RCon; requires `reason` in body |
|
||||
| POST ✅ | `/servers/{server_id}/players/{slot_id}/ban` | Admin | Ban player by slot ID via RCon + DB; requires `reason` and optional `duration_minutes` (`null` = permanent) |
|
||||
|
||||
### Phase 5 — Log File Browser
|
||||
### Phase 5 — Log File Browser ✅
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/servers/{server_id}/logfiles` | Bearer | List historical `.rpt` log files with `filename`, `size_bytes`, `modified_at` |
|
||||
| GET | `/servers/{server_id}/logfiles/{filename}` | Bearer | Stream or return contents of a historical log file |
|
||||
| GET ✅ | `/servers/{server_id}/logfiles` | Bearer | List historical `.rpt` log files with `filename`, `size_bytes`, `modified_at` |
|
||||
| GET ✅ | `/servers/{server_id}/logfiles/{filename}/download` | Bearer | Download a historical `.rpt` log file as `text/plain` |
|
||||
| DELETE ✅ | `/servers/{server_id}/logfiles/{filename}` | Admin | Delete a historical `.rpt` log file |
|
||||
43
CLAUDE.md
43
CLAUDE.md
@@ -42,42 +42,35 @@ All routers, services, repositories, game adapter system, WebSocket, background
|
||||
|
||||
### Frontend Type Mapping (API → Frontend)
|
||||
|
||||
Types below reflect the **current** API shape. Fields marked `(planned)` will be added during the UX enhancement plan.
|
||||
|
||||
| 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` *(planned)* |
|
||||
| Mod | `Mod` in useServerDetail.ts | `name`, `path`, `size_bytes`, `enabled`, `display_name` *(planned)*, `workshop_id` *(planned)* |
|
||||
| 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` |
|
||||
|
||||
### Upcoming: UX Enhancement Plan
|
||||
### UX Enhancement Plan — ALL PHASES COMPLETE
|
||||
|
||||
**Plan file:** `.claude/plan/arma3-ux-enhancement.md` — approved, ready to implement.
|
||||
**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 | Pending |
|
||||
| 4 | Player Kick/Ban from Players tab via RCon | Pending |
|
||||
| 5 | Historical log file browser + live log level filter | 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 | **Done** |
|
||||
| 4 | Player Kick/Ban from Players tab via RCon | **Done** |
|
||||
| 5 | Historical log file browser + live log level filter | **Done** |
|
||||
|
||||
**New endpoints added by the plan:**
|
||||
- `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`
|
||||
- `GET /api/servers/{id}/logfiles/{filename}/download`
|
||||
- `DELETE /api/servers/{id}/logfiles/{filename}`
|
||||
|
||||
**New backend additions:**
|
||||
- `Arma3ConfigGenerator.get_ui_schema()` — widget schema per config field
|
||||
- `PlayerRepository.get_by_slot()` — lookup player by slot_id
|
||||
- `ThreadRegistry.get_rcon_client()` — expose live RCon client for kick/ban
|
||||
- `RPTParser.list_log_files()` / `get_log_file_path()` — historical log access
|
||||
**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
|
||||
|
||||
|
||||
24
FRONTEND.md
24
FRONTEND.md
@@ -69,8 +69,8 @@ frontend/src/
|
||||
│ │ ├── PlayerTable.tsx # Current players + history with search
|
||||
│ │ ├── BanTable.tsx # Ban list + create/revoke form
|
||||
│ │ ├── 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)
|
||||
│ │ ├── ModList.tsx # Split-pane mod selector (Available vs Selected); Apply Selection button
|
||||
│ │ └── LogViewer.tsx # Log display with level filter + collapsible Log Files browser (download/delete)
|
||||
│ ├── settings/
|
||||
│ │ ├── PasswordChange.tsx # Password change form
|
||||
│ │ └── UserManager.tsx # User CRUD table (admin only)
|
||||
@@ -134,8 +134,8 @@ App
|
||||
│ │ │ ├── PlayerTable (current + history with search)
|
||||
│ │ │ ├── BanTable (ban list + create/revoke)
|
||||
│ │ │ ├── MissionList (Available + Rotation sections, multi-file upload)
|
||||
│ │ │ ├── ModList (enable/disable checkboxes)
|
||||
│ │ │ └── LogViewer (level filter, real-time via WebSocket onEvent)
|
||||
│ │ │ ├── ModList (split-pane: Available | Selected; Apply Selection)
|
||||
│ │ │ └── LogViewer (level filter, real-time stream + Log Files browser)
|
||||
│ │ ├── /servers/new → CreateServerPage
|
||||
│ │ │ └── 4-step wizard (Game Type → Info → Options → Review)
|
||||
│ │ └── /settings → SettingsPage
|
||||
@@ -186,6 +186,10 @@ All server data flows through TanStack Query hooks:
|
||||
| `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 |
|
||||
| `useKickPlayer(id)` | Mutation | `POST /api/servers/:id/players/:slot_id/kick` | Invalidates `["players", id]` |
|
||||
| `useBanPlayer(id)` | Mutation | `POST /api/servers/:id/players/:slot_id/ban` | Invalidates players + bans |
|
||||
| `useServerLogFiles(id)` | Query | `GET /api/servers/:id/logfiles` | `["servers", id, "logfiles"]` (refetch 30s) |
|
||||
| `useDeleteLogFile(id)` | Mutation | `DELETE /api/servers/:id/logfiles/:filename` | Invalidates logfiles |
|
||||
|
||||
**Auth** (`useAuth.ts`):
|
||||
|
||||
@@ -210,18 +214,10 @@ 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 }` — 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)
|
||||
- `Mod` type: `{ name, path, size_bytes, enabled, display_name, workshop_id }` — `display_name`/`workshop_id` from mod.cpp/meta.cpp
|
||||
- `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 — remaining):**
|
||||
|
||||
| Hook | Phase | Endpoint |
|
||||
|---|---|---|
|
||||
| `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` |
|
||||
|
||||
QueryClient defaults: `staleTime: 10s`, `retry: 2`, `refetchOnWindowFocus: false`.
|
||||
|
||||
### Client State (Zustand)
|
||||
@@ -285,7 +281,7 @@ Dark neumorphic theme defined in `tailwind.config.js`:
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests (120 tests, Vitest + React Testing Library)
|
||||
### Unit Tests (149 tests, Vitest + React Testing Library)
|
||||
|
||||
| Test File | Tests | Coverage |
|
||||
|---|---|---|
|
||||
|
||||
11
MODULES.md
11
MODULES.md
@@ -51,11 +51,11 @@ All 7 capabilities implemented:
|
||||
| `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, `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 |
|
||||
| `log_parser.py` | `RPTParser` | Regex-based .rpt log parser, log file resolver, `list_log_files()`, `get_log_file_path()` |
|
||||
| `rcon_client.py` | `BERConClient` | BattlEye RCon v2 UDP protocol implementation |
|
||||
| `remote_admin.py` | `Arma3RemoteAdmin` + `Arma3RemoteAdminFactory` | Implements RemoteAdmin protocol using BERConClient |
|
||||
| `mission_manager.py` | `Arma3MissionManager` | .pbo upload, delete, list, rotation config generation |
|
||||
| `mod_manager.py` | `Arma3ModManager` | @-prefixed mod scanning, enabled-mod persistence, -mod/-serverMod args |
|
||||
| `mod_manager.py` | `Arma3ModManager` | @-prefixed mod scanning, enabled-mod persistence, -mod/-serverMod args; `_parse_mod_cpp()`/`_parse_meta_cpp()` for display_name/workshop_id |
|
||||
| `ban_manager.py` | `Arma3BanManager` | BattlEye bans.txt file sync + DB sync |
|
||||
|
||||
### `core/auth/` — Authentication
|
||||
@@ -72,7 +72,8 @@ All 7 capabilities implemented:
|
||||
| Module | Purpose |
|
||||
|---|---|
|
||||
| `router.py` | Server CRUD, lifecycle (start/stop/restart/kill), config read/write/preview, RCon command |
|
||||
| `players_router.py` | Player list, player history |
|
||||
| `players_router.py` | Player list, player history, kick/ban by slot_id |
|
||||
| `logfiles_router.py` | List, download, and delete historical `.rpt` log files |
|
||||
| `bans_router.py` | Ban CRUD with bans.txt file sync |
|
||||
| `missions_router.py` | Mission list, .pbo upload (500MB), delete, GET/PUT rotation |
|
||||
| `mods_router.py` | List mods, set enabled mods |
|
||||
@@ -105,7 +106,7 @@ All 7 capabilities implemented:
|
||||
| Module | Purpose |
|
||||
|---|---|
|
||||
| `base_thread.py` | `BaseServerThread` — abstract base with stop event, thread-local DB, exception backoff |
|
||||
| `thread_registry.py` | `ThreadRegistry` — manages per-server thread bundles, start/stop/reattach; `get_rcon_client(server_id)` class method to be added in Phase 4 |
|
||||
| `thread_registry.py` | `ThreadRegistry` — manages per-server thread bundles, start/stop/reattach; `get_rcon_client(server_id)` class method exposes live RCon client |
|
||||
| `log_tail.py` | `LogTailThread` — tails log files, parses lines, persists to DB, broadcasts |
|
||||
| `process_monitor.py` | `ProcessMonitorThread` — detects crashes, triggers auto-restart |
|
||||
| `metrics_collector.py` | `MetricsCollectorThread` — psutil CPU/RAM collection every 10s |
|
||||
@@ -125,7 +126,7 @@ All 7 capabilities implemented:
|
||||
| `base_repository.py` | `BaseRepository` — thin wrapper around SQLAlchemy `text()` queries |
|
||||
| `server_repository.py` | `ServerRepository` — CRUD, status updates, running servers, restart count |
|
||||
| `config_repository.py` | `ConfigRepository` — Per-section upsert with Fernet encryption and optimistic locking |
|
||||
| `player_repository.py` | `PlayerRepository` — Upsert/clear players, player_history queries; `get_by_slot(server_id, slot_id)` to be added in Phase 4 |
|
||||
| `player_repository.py` | `PlayerRepository` — Upsert/clear players, player_history queries, `get_by_slot(server_id, slot_id)` |
|
||||
| `ban_repository.py` | `BanRepository` — Ban CRUD with active/inactive flag |
|
||||
| `event_repository.py` | `EventRepository` — Insert server events, query, cleanup |
|
||||
| `log_repository.py` | `LogRepository` — Insert parsed log entries, query with filters, cleanup |
|
||||
|
||||
Reference in New Issue
Block a user