5.2 KiB
Fix Peers API 500 + Add Delete Device to Devices List
TL;DR
Quick Summary: Fix
HWIDunique constraint violation causing 500 on POST/api/v1/peersby makingHWIDnullable; add delete button to Devices.vue list viewDeliverables:
- Backend: HWID model change
string→*string, fix CreatePeer/CreateDevice- Frontend: Delete button in Devices.vue table rows
- Migration: SQL to convert existing empty HWIDs to NULL + container restart
Estimated Effort: Short Parallel Execution: YES
Context
Root Cause
Device.HWIDisstringwithuniqueIndex.CreatePeersetsHWID: ""which collides with other devices having empty HWID → SQLSTATE 23505- Fix: make HWID
*string(nullable), PostgreSQL treats NULLs as distinct in unique constraints
Delete Missing
- Backend:
DELETE /devices/:idexists atmain.go:176,devicesHandler.Deleteindevices.go:235 - API:
deleteDevice(id)exists indevices.ts:50 - DeviceDetail: has delete button with confirm dialog
- Devices.vue: Actions column only has View, Config, Firewall — no Delete
TODOs
-
1. Backend: Change HWID to
*stringin Device modelWhat to do:
- Edit
apps/server-core/internal/models/models.goline 60:- Change
HWID string \gorm:"column:hwid;uniqueIndex;size:64"`` - To
HWID *string \gorm:"column:hwid;uniqueIndex;size:64"``
- Change
Must NOT do:
- Don't change any other fields in the model
Recommended Agent Profile:
unspecified-high(precise Go struct edit)QA Scenarios:
Scenario: Verify build after model change Tool: Bash Steps: 1. cd apps/server-core && go build ./... Expected Result: No compilation errors Evidence: .sisyphus/evidence/task-1-build.txt - Edit
-
2. Backend: Fix CreatePeer to not set empty HWID
What to do:
- Edit
apps/server-core/api/peers.go— removeHWID: ""line (line 96) - Since
HWIDis now*string, the zero value (nil) is correct — it won't violate unique constraint - Keep
RegTokenHash: ""as-is (no unique index on that)
QA Scenarios:
Scenario: Build passes after fix Tool: Bash Steps: 1. cd apps/server-core && go build ./... Expected Result: Clean build Evidence: .sisyphus/evidence/task-2-build.txt - Edit
-
3. Backend: Fix CreateDevice to not set empty HWID
What to do:
- Edit
apps/server-core/api/devices.go— verifyCreatefunction (line 84-89) doesn't set HWID - It currently doesn't set HWID at all, so with
*stringit will default to nil — correct - Verify
Deletefunction (line 235-255) already works — it does, no changes needed
- Edit
-
4. Migration: Convert existing empty HWIDs to NULL on server
What to do:
- SSH into 172.20.8.191 and run SQL against the postgres container:
docker exec nexus-guard-suite-postgres-1 psql -U nexusguard -d nexusguard -c "UPDATE devices SET hwid = NULL WHERE hwid = '';"- Then restart server-core container:
docker restart nexus-guard-suite-server-core-1QA Scenarios:
Scenario: Verify empty HWIDs are now NULL Tool: Bash Steps: 1. docker exec nexus-guard-suite-postgres-1 psql -U nexusguard -d nexusguard -c "SELECT count(*) FROM devices WHERE hwid = '';" Expected Result: count = 0 Evidence: .sisyphus/evidence/task-4-sql.txt Scenario: Verify POST /api/v1/peers succeeds Tool: Bash Steps: 1. Obtain auth token via POST /api/v1/auth/login with admin credentials 2. POST /api/v1/peers with valid body (name, wg_server_id) Expected Result: 201 Created (not 500) Evidence: .sisyphus/evidence/task-4-peers-api.txt -
5. Frontend: Add delete button to Devices.vue list
What to do:
- Edit
apps/dashboard-ui/src/views/Devices.vue - Add delete button in the Actions column (line 34-39), after Firewall button:
<button @click="handleDelete(device.ID, device.Name)" class="text-red-400 hover:text-red-300 font-bold">Delete</button> - Import
deleteDevicefrom../api/devices - Add
handleDeletefunction:const handleDelete = async (id: string, name: string) => { if (!confirm(`Delete device "${name}"? This will destroy its tunnel and all firewall rules.`)) return try { await deleteDevice(id) store.loadDevices() } catch (err: any) { alert(err.response?.data?.error || 'Failed to delete device') } }
Must NOT do:
- Don't remove the existing Config/Firewall buttons
Recommended Agent Profile:
visual-engineering(Vue UI)QA Scenarios:
Scenario: Build passes Tool: Bash Steps: 1. cd apps/dashboard-ui && npx vue-tsc --noEmit Expected Result: No type errors Evidence: .sisyphus/evidence/task-5-tsc.txt - Edit
-
6. Commit and push changes
What to do:
- Commit server-core changes
- Commit dashboard-ui changes
- Push both submodules
- Commit/push root submodule pointer
Success Criteria
go build ./...passesvue-tsc --noEmitpasses- POST
/api/v1/peersreturns 201, not 500 - Devices.vue has a delete button per row that works
- Existing empty HWIDs migrated to NULL