docs: mark phases 3-5 complete, update API/FRONTEND/MODULES/CLAUDE.md

This commit is contained in:
Tran G. (Revernomad) Khoa
2026-04-17 20:50:19 +07:00
parent 5a62d21def
commit 8bac29fb68
5 changed files with 44 additions and 53 deletions

View File

@@ -14,9 +14,9 @@
|-------|--------|------------------| |-------|--------|------------------|
| 1 — Config UI Schema | `[x] done` | TagListEditor, useServerConfigSchema, ConfigEditor widget routing, backend get_ui_schema + endpoint | | 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 | | 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` | | | 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 | `[ ] not started` | | | 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 | `[ ] not started` | | | 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. **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
View File

@@ -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 | | 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) | | 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 | | 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}/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}/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 | | 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` | 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/{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 |

View File

@@ -42,42 +42,35 @@ All routers, services, repositories, game adapter system, WebSocket, background
### Frontend Type Mapping (API → Frontend) ### 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 | | API Resource | Frontend Type | Key Fields |
|---|---|---| |---|---|---|
| Server (enriched) | `Server` in useServers.ts | `game_port`, `current_players`, `max_players`, `cpu_percent`, `ram_mb` | | 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)* | | Mission | `Mission` in useServerDetail.ts | `name`, `filename`, `size_bytes`, `terrain` |
| Mod | `Mod` in useServerDetail.ts | `name`, `path`, `size_bytes`, `enabled`, `display_name` *(planned)*, `workshop_id` *(planned)* | | 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` | | 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` | | 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 | | Phase | Feature | Status |
|-------|---------|--------| |-------|---------|--------|
| 1 | Config field UI widgets (textarea/toggle/select/tag-list per field) | Done | | 1 | Config field UI widgets (textarea/toggle/select/tag-list per field) | **Done** |
| 2 | Mission rotation table + multi-file upload | Done | | 2 | Mission rotation table + multi-file upload | **Done** |
| 3 | Mod display names (mod.cpp) + split-pane selector | Pending | | 3 | Mod display names (mod.cpp) + split-pane selector | **Done** |
| 4 | Player Kick/Ban from Players tab via RCon | Pending | | 4 | Player Kick/Ban from Players tab via RCon | **Done** |
| 5 | Historical log file browser + live log level filter | Pending | | 5 | Historical log file browser + live log level filter | **Done** |
**New endpoints added by the plan:** **Endpoints added:**
- `GET /api/servers/{id}/config/schema` — per-field widget hints (**implemented**) - `GET /api/servers/{id}/config/schema` — per-field widget hints
- `GET|PUT /api/servers/{id}/missions/rotation` — mission rotation (**implemented**) - `GET|PUT /api/servers/{id}/missions/rotation` — mission rotation with optimistic locking
- `POST /api/servers/{id}/players/{slot_id}/kick` - `POST /api/servers/{id}/players/{slot_id}/kick` — kick via RCon
- `POST /api/servers/{id}/players/{slot_id}/ban` - `POST /api/servers/{id}/players/{slot_id}/ban` — ban via RCon + DB record
- `GET /api/servers/{id}/logfiles` - `GET /api/servers/{id}/logfiles` — list `.rpt` log files
- `GET /api/servers/{id}/logfiles/{filename}/download` - `GET /api/servers/{id}/logfiles/{filename}/download` — download log file
- `DELETE /api/servers/{id}/logfiles/{filename}` - `DELETE /api/servers/{id}/logfiles/{filename}` — delete log file
**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
## Test Commands ## Test Commands

View File

@@ -69,8 +69,8 @@ frontend/src/
│ │ ├── PlayerTable.tsx # Current players + history with search │ │ ├── PlayerTable.tsx # Current players + history with search
│ │ ├── BanTable.tsx # Ban list + create/revoke form │ │ ├── BanTable.tsx # Ban list + create/revoke form
│ │ ├── MissionList.tsx # Available missions + Mission Rotation sections; multi-file upload │ │ ├── MissionList.tsx # Available missions + Mission Rotation sections; multi-file upload
│ │ ├── ModList.tsx # Mod list with enable/disable checkboxes │ │ ├── ModList.tsx # Split-pane mod selector (Available vs Selected); Apply Selection button
│ │ └── LogViewer.tsx # Log display with level filter (receives logs as props) │ │ └── LogViewer.tsx # Log display with level filter + collapsible Log Files browser (download/delete)
│ ├── settings/ │ ├── settings/
│ │ ├── PasswordChange.tsx # Password change form │ │ ├── PasswordChange.tsx # Password change form
│ │ └── UserManager.tsx # User CRUD table (admin only) │ │ └── UserManager.tsx # User CRUD table (admin only)
@@ -134,8 +134,8 @@ App
│ │ │ ├── PlayerTable (current + history with search) │ │ │ ├── PlayerTable (current + history with search)
│ │ │ ├── BanTable (ban list + create/revoke) │ │ │ ├── BanTable (ban list + create/revoke)
│ │ │ ├── MissionList (Available + Rotation sections, multi-file upload) │ │ │ ├── MissionList (Available + Rotation sections, multi-file upload)
│ │ │ ├── ModList (enable/disable checkboxes) │ │ │ ├── ModList (split-pane: Available | Selected; Apply Selection)
│ │ │ └── LogViewer (level filter, real-time via WebSocket onEvent) │ │ │ └── LogViewer (level filter, real-time stream + Log Files browser)
│ │ ├── /servers/new → CreateServerPage │ │ ├── /servers/new → CreateServerPage
│ │ │ └── 4-step wizard (Game Type → Info → Options → Review) │ │ │ └── 4-step wizard (Game Type → Info → Options → Review)
│ │ └── /settings → SettingsPage │ │ └── /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]` | | `useDeleteMission(id)` | Mutation | `DELETE /api/servers/:id/missions/:filename` | Invalidates `["missions", id]` |
| `useSetEnabledMods(id)` | Mutation | `PUT /api/servers/:id/mods/enabled` | Invalidates `["mods", id]` | | `useSetEnabledMods(id)` | Mutation | `PUT /api/servers/:id/mods/enabled` | Invalidates `["mods", id]` |
| `useSendCommand(id)` | Mutation | `POST /api/servers/:id/rcon/command` | No invalidation | | `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`): **Auth** (`useAuth.ts`):
@@ -210,18 +214,10 @@ All server data flows through TanStack Query hooks:
**Key type notes**: **Key type notes**:
- `Server` type in `useServers.ts` uses `game_port`, `current_players`, `max_players` (matches enriched API response) - `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 - `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) - `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 - 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`. QueryClient defaults: `staleTime: 10s`, `retry: 2`, `refetchOnWindowFocus: false`.
### Client State (Zustand) ### Client State (Zustand)
@@ -285,7 +281,7 @@ Dark neumorphic theme defined in `tailwind.config.js`:
## Testing ## Testing
### Unit Tests (120 tests, Vitest + React Testing Library) ### Unit Tests (149 tests, Vitest + React Testing Library)
| Test File | Tests | Coverage | | Test File | Tests | Coverage |
|---|---|---| |---|---|---|

View File

@@ -51,11 +51,11 @@ All 7 capabilities implemented:
| `adapter.py` | `Arma3Adapter` | Composite adapter declaring all capabilities | | `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 | | `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 | | `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 | | `rcon_client.py` | `BERConClient` | BattlEye RCon v2 UDP protocol implementation |
| `remote_admin.py` | `Arma3RemoteAdmin` + `Arma3RemoteAdminFactory` | Implements RemoteAdmin protocol using BERConClient | | `remote_admin.py` | `Arma3RemoteAdmin` + `Arma3RemoteAdminFactory` | Implements RemoteAdmin protocol using BERConClient |
| `mission_manager.py` | `Arma3MissionManager` | .pbo upload, delete, list, rotation config generation | | `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 | | `ban_manager.py` | `Arma3BanManager` | BattlEye bans.txt file sync + DB sync |
### `core/auth/` — Authentication ### `core/auth/` — Authentication
@@ -72,7 +72,8 @@ All 7 capabilities implemented:
| Module | Purpose | | Module | Purpose |
|---|---| |---|---|
| `router.py` | Server CRUD, lifecycle (start/stop/restart/kill), config read/write/preview, RCon command | | `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 | | `bans_router.py` | Ban CRUD with bans.txt file sync |
| `missions_router.py` | Mission list, .pbo upload (500MB), delete, GET/PUT rotation | | `missions_router.py` | Mission list, .pbo upload (500MB), delete, GET/PUT rotation |
| `mods_router.py` | List mods, set enabled mods | | `mods_router.py` | List mods, set enabled mods |
@@ -105,7 +106,7 @@ All 7 capabilities implemented:
| Module | Purpose | | Module | Purpose |
|---|---| |---|---|
| `base_thread.py` | `BaseServerThread` — abstract base with stop event, thread-local DB, exception backoff | | `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 | | `log_tail.py` | `LogTailThread` — tails log files, parses lines, persists to DB, broadcasts |
| `process_monitor.py` | `ProcessMonitorThread` — detects crashes, triggers auto-restart | | `process_monitor.py` | `ProcessMonitorThread` — detects crashes, triggers auto-restart |
| `metrics_collector.py` | `MetricsCollectorThread` — psutil CPU/RAM collection every 10s | | `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 | | `base_repository.py` | `BaseRepository` — thin wrapper around SQLAlchemy `text()` queries |
| `server_repository.py` | `ServerRepository` — CRUD, status updates, running servers, restart count | | `server_repository.py` | `ServerRepository` — CRUD, status updates, running servers, restart count |
| `config_repository.py` | `ConfigRepository` — Per-section upsert with Fernet encryption and optimistic locking | | `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 | | `ban_repository.py` | `BanRepository` — Ban CRUD with active/inactive flag |
| `event_repository.py` | `EventRepository` — Insert server events, query, cleanup | | `event_repository.py` | `EventRepository` — Insert server events, query, cleanup |
| `log_repository.py` | `LogRepository` — Insert parsed log entries, query with filters, cleanup | | `log_repository.py` | `LogRepository` — Insert parsed log entries, query with filters, cleanup |