# NexusGuard SD-WAN — WGDashboard Parity Plan (Phase 4.9) **Goal**: Bring the Dashboard UI to feature-parity with WGDashboard — multi-user management, global device view for Admin, WireGuard local interface status, external node health, and proper Endpoint vs ListenAddress config. ## Task 4.9.1: User Management API (Admin CRUD) - [x] Create `api/users.go` with CRUD endpoints (`GET /api/v1/users`, `POST /api/v1/users`, `DELETE /api/v1/users`) - [x] Wire `UsersHandler` in `main.go` protected route group (admin-only JWT check) - [x] Write tests for user CRUD ## Task 4.9.2: Admin Global Device View - [x] Modify `api/devices.go` `List()`: if requester is admin, return ALL devices with Preload("User") - [x] Add `?user_id=` query parameter filter for admin - [x] Write tests verifying admin sees all devices, regular user sees only own ## Task 4.9.3: Dashboard UI - Users Page - [x] Create `src/api/users.ts` with user CRUD API calls - [x] Create `src/views/Users.vue` — table of users with create/delete actions - [x] Add "Users" link to Sidebar in `src/App.vue` and route in `src/router/index.ts` - [x] Add "Owner" column in `src/views/Devices.vue` when admin logged in - [x] Add user filter dropdown in Devices page for admin ## Task 4.9.4: WireGuard Local Interface Manager (Backend) - [x] Create `internal/wgmanager/manager.go` — wgctrl integration for local wg0 (with stub for Windows cross-compile) - [x] Implement: `GetStatus()`, `SetConfig(listenPort, privateKey)`, `Down()` - [x] Add `/api/v1/wg/status` endpoint: UP/DOWN, Rx/Tx bytes, peer count, last handshake - [x] Add `/api/v1/wg/up` and `/api/v1/wg/down` endpoints to start/stop local wg0 - [x] Wire into `main.go` route group ## Task 4.9.5: Dashboard UI - Local WG Status Widget - [x] Create `src/components/WgStatusCard.vue` — ON/OFF toggle, Rx/Tx counters, peer count - [x] Integrate into `src/views/Dashboard.vue` ## Task 4.9.6: External Node Health Check - [x] Add background goroutine in `main.go` pinging registered WgServer endpoints every 30s via UDP - [x] Track health status in a thread-safe in-memory map - [x] Add `GET /api/v1/servers/status` returning health of each node - [x] Update `src/views/Servers.vue` to show Online/Offline dots and last-check timestamp - [x] Update `src/api/servers.ts` with status endpoint ## Task 4.9.7: Endpoint vs ListenAddress Split - [x] Add `ListenAddress` column to WgServer model (default `0.0.0.0:51820`) - [x] Rename `Endpoint` in model/API to `PublicEndpoint` for clarity - [x] Update `migrations/001_init.sql` and GORM model mapper - [x] Update `api/servers.go` CRUD to split the fields - [x] Update Provisioning API to use `PublicEndpoint` (not ListenAddress) - [ ] Update `src/api/servers.ts` type and `src/views/Servers.vue` form to show both fields - [ ] Write tests for provisioning returning correct PublicEndpoint