feat: add Makefile with reset-db target, update submodule refs

This commit is contained in:
datadunia
2026-05-22 09:38:20 +07:00
parent 0d5e3b074a
commit 2ba5880a1b
5 changed files with 258 additions and 2 deletions
+73
View File
@@ -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
```
@@ -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
<button @click="handleDelete(device.ID, device.Name)" class="text-red-400 hover:text-red-300 font-bold">Delete</button>
```
- 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