From 2ba5880a1b038d081caf323a0b9598fa71045fa9 Mon Sep 17 00:00:00 2001 From: datadunia Date: Fri, 22 May 2026 09:38:20 +0700 Subject: [PATCH] feat: add Makefile with reset-db target, update submodule refs --- .sisyphus/plans/nxg-deployment-tools.md | 73 +++++++++ .../nxg-fix-peers-500-and-delete-device.md | 154 ++++++++++++++++++ Makefile | 29 ++++ apps/dashboard-ui | 2 +- apps/server-core | 2 +- 5 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 .sisyphus/plans/nxg-deployment-tools.md create mode 100644 .sisyphus/plans/nxg-fix-peers-500-and-delete-device.md create mode 100644 Makefile diff --git a/.sisyphus/plans/nxg-deployment-tools.md b/.sisyphus/plans/nxg-deployment-tools.md new file mode 100644 index 0000000..4f6ebcb --- /dev/null +++ b/.sisyphus/plans/nxg-deployment-tools.md @@ -0,0 +1,73 @@ +# Deployment Tools: Makefile + HWID Migration + +## TODOs + +- [ ] 1. Create Makefile with reset-db command + + **What to do**: + - Create `D:\www-project\NexusGuard\Makefile` with this content: + ```makefile + .PHONY: up down reset-db logs dev migrate + + up: + docker compose up -d + + down: + docker compose down + + logs: + docker compose logs -f + + reset-db: + docker compose down -v + docker compose up -d postgres redis + @echo "Waiting for postgres to be ready..." + @for i in $$(seq 1 30); do \ + docker compose exec -T postgres pg_isready -U nexusguard >/dev/null 2>&1 && break; \ + echo " waiting... $$i"; \ + sleep 2; \ + done + cd apps/server-core && go run -tags dev . -migrate-prod + @echo "" + @echo "Database reset complete. Run 'make up' to start all services." + + dev: + docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d + + migrate: + cd apps/server-core && go run -tags dev . -migrate-prod + ``` + + - Then run `cd D:\www-project\NexusGuard && git add Makefile` + + **Recommended Agent Profile**: `build` (file creation + git) + +- [ ] 2. SSH: Migrate empty HWIDs to NULL + restart container + + **What to do**: + - SSH into 172.20.8.191: + ```bash + ssh root@172.20.8.191 "docker exec nexus-guard-suite-postgres-1 psql -U nexusguard -d nexusguard -c \"UPDATE devices SET hwid = NULL WHERE hwid = '';\"" + ``` + - Then restart server-core: + ```bash + ssh root@172.20.8.191 "docker restart nexus-guard-suite-server-core-1" + ``` + + **QA Scenarios**: + ``` + Scenario: Verify no empty HWIDs remain + Tool: Bash + Steps: + 1. ssh root@172.20.8.191 "docker exec nexus-guard-suite-postgres-1 psql -U nexusguard -d nexusguard -c \"SELECT count(*) FROM devices WHERE hwid = '';\"" + Expected Result: count = 0 + ``` + +- [ ] 3. Commit and push all changes (server-core HWID fix, frontend delete button, Makefile) + +- [ ] 4. Verify POST /api/v1/peers returns 201 + + ```bash + ssh root@172.20.8.191 'curl -s -X POST http://localhost:3000/api/v1/auth/login -H "Content-Type: application/json" -d "{\"username\":\"admin\",\"password\":\"...\"}"' + # Then use token to create a peer + ``` diff --git a/.sisyphus/plans/nxg-fix-peers-500-and-delete-device.md b/.sisyphus/plans/nxg-fix-peers-500-and-delete-device.md new file mode 100644 index 0000000..e9060b7 --- /dev/null +++ b/.sisyphus/plans/nxg-fix-peers-500-and-delete-device.md @@ -0,0 +1,154 @@ +# Fix Peers API 500 + Add Delete Device to Devices List + +## TL;DR +> **Quick Summary**: Fix `HWID` unique constraint violation causing 500 on POST `/api/v1/peers` by making `HWID` nullable; add delete button to Devices.vue list view +> +> **Deliverables**: +> - 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.HWID` is `string` with `uniqueIndex`. `CreatePeer` sets `HWID: ""` 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/:id` exists at `main.go:176`, `devicesHandler.Delete` in `devices.go:235` +- API: `deleteDevice(id)` exists in `devices.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 `*string` in Device model + + **What to do**: + - Edit `apps/server-core/internal/models/models.go` line 60: + - Change `HWID string \`gorm:"column:hwid;uniqueIndex;size:64"\`` + - To `HWID *string \`gorm:"column:hwid;uniqueIndex;size:64"\`` + + **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 + ``` + +- [ ] 2. Backend: Fix CreatePeer to not set empty HWID + + **What to do**: + - Edit `apps/server-core/api/peers.go` — remove `HWID: ""` line (line 96) + - Since `HWID` is 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 + ``` + +- [ ] 3. Backend: Fix CreateDevice to not set empty HWID + + **What to do**: + - Edit `apps/server-core/api/devices.go` — verify `Create` function (line 84-89) doesn't set HWID + - It currently doesn't set HWID at all, so with `*string` it will default to nil — correct + - Verify `Delete` function (line 235-255) already works — it does, no changes needed + +- [ ] 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: + ```bash + 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: + ```bash + docker restart nexus-guard-suite-server-core-1 + ``` + + **QA 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: + ```html + + ``` + - Import `deleteDevice` from `../api/devices` + - Add `handleDelete` function: + ```typescript + 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 + ``` + +- [ ] 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 ./...` passes +- [ ] `vue-tsc --noEmit` passes +- [ ] POST `/api/v1/peers` returns 201, not 500 +- [ ] Devices.vue has a delete button per row that works +- [ ] Existing empty HWIDs migrated to NULL diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..75e0a21 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +.PHONY: up down reset-db logs dev migrate + +up: + docker compose up -d + +down: + docker compose down + +logs: + docker compose logs -f + +reset-db: + docker compose down -v + docker compose up -d postgres redis + @echo "Waiting for postgres to be ready..." + @for i in $$(seq 1 30); do \ + docker compose exec -T postgres pg_isready -U nexusguard >/dev/null 2>&1 && break; \ + echo " waiting... $$i"; \ + sleep 2; \ + done + cd apps/server-core && go run -tags dev . -migrate-prod + @echo "" + @echo "Database reset complete. Run 'make up' to start all services." + +dev: + docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d + +migrate: + cd apps/server-core && go run -tags dev . -migrate-prod diff --git a/apps/dashboard-ui b/apps/dashboard-ui index e6c71e6..24ae011 160000 --- a/apps/dashboard-ui +++ b/apps/dashboard-ui @@ -1 +1 @@ -Subproject commit e6c71e6c50660ad5ac32a4e0bd865f96c33be327 +Subproject commit 24ae0119fd3f94aae5074aacbb99feeba1b03343 diff --git a/apps/server-core b/apps/server-core index 9980cd3..4ebf097 160000 --- a/apps/server-core +++ b/apps/server-core @@ -1 +1 @@ -Subproject commit 9980cd3ec65840f46bf031611288d09a48765c4b +Subproject commit 4ebf097fe22c1069b884321ed190f7bc746eeb75