Files
datadunia cbacfea7f2
NexusGuard CI / server-core-test (push) Failing after 3m6s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 4s
NexusGuard CI / device-agent-cross-build (amd64, linux) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (amd64, windows) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (arm64, linux) (push) Has been skipped
NexusGuard CI / dashboard-test (push) Failing after 4s
NexusGuard CI / dashboard-dist (push) Has been skipped
chore: update submodule refs, clean up plans/evidence, update .gitignore
2026-06-07 23:53:15 +07:00

12 KiB

NexusGuard — AI Agent Reference: Completed Work History

Purpose: Compact record of all completed implementation work. Use this to understand what's been built, key decisions, and files modified. Avoid re-implementing or regressing completed features. Generated: 2026-05-24 Format: One section per completed phase/plan. Minimal token overhead.


1. Full System Build (nxg-nexusguard-full-build)

Goal: Build complete NexusGuard SD-WAN from scratch across 3 submodules.

Stack: Go 1.25 (Gin/GORM) + Vue 3 (Vite/Pinia/Tailwind) + Device Agent (wireguard-go memory-only)

Key Decisions:

  • Zero-Trust: nftables default DROP. Per-user sets for isolation.
  • Stealth Agent: wireguard-go via device.IpcSet() — no config files on disk.
  • Hardware Binding: SHA256(HWID + Salt) for AES key derivation.
  • Config Encryption: AES-256-GCM server↔agent. Key never transmitted.
  • JWT for Dashboard↔Server. X-Token-Auth for Agent↔Server (one-time reg token).
  • Dev: GORM AutoMigrate. Prod: goose versioned migrations.
  • No STUN/P2P, no WebSocket (polling only), no kernel WireGuard, no agent disk writes.

Guardrails:

  • NEVER nft flush table — element-level ops only
  • NEVER GORM AutoMigrate in production
  • NEVER write WG config to /etc/wireguard/

2. Phase 4.5: Multi-Node & Production Readiness

Goal: Single-node → Multi-Server architecture + DB startup hardening.

Task Files What
Multi-Server DB & API models.go, 001_init.sql, api/servers.go, main.go WgServerID FK on Device. CRUD /api/v1/servers.
Provisioning Multi-Node api/provisioning.go, provisioning_test.go Remove 127.0.0.1:51820 fallback. Return true Endpoint.
Dashboard Nodes Servers.vue, Devices.vue, servers.ts, App.vue Nodes page, device→Node dropdown, sidebar.
Install Detection main.go DB schema check on boot. -migrate-prod flag via goose.

3. Phase 4.9: WGDashboard Parity

Goal: Multi-user, global device view, WG interface status, node health, Endpoint/ListenAddress split.

Task Files What
User CRUD API api/users.go, main.go GET/POST/DELETE /api/v1/users. Admin-only.
Admin Global Devices api/devices.go Admin sees ALL devices. ?user_id= filter.
Users Page UI Users.vue, users.ts, Devices.vue, App.vue, router/ Table, create/delete. Owner column for admin. User filter.
WG Local Manager internal/wgmanager/manager.go GetStatus(), SetConfig(), Down(). Stub for Win.
WG API main.go routes /wg/status, /wg/up, /wg/down.
WG Status Widget WgStatusCard.vue on Dashboard ON/OFF toggle, Rx/Tx, peer count.
Node Health Check main.go goroutine + api/servers.go UDP ping every 30s. GET /servers/status.
Endpoint/ListenAddress models.go, servers.go, 001_init.sql, provisioning PublicEndpointListenAddress. Both editable.

4. Phase 5.0: Peer Management + QR/Conf

Goal: Create peers directly from UI, QR codes, .conf download, share links.

Key Decisions:

  • Route: /api/v1/devices/:id/config (not /peers)
  • PresharedKey via wgtypes.GeneratePrivateKey() for every direct peer
  • RegTokenHash="" for direct peers (never provisionable via token)
  • Share links: Redis with SHARE_LINK_TTL env (default 24h)
  • AllowedIPs: AllowInternet=true0.0.0.0/0, else → <InternalIP>/32
  • MUST NOT push peer config to kernel interface (deferred)
Task Files What
PresharedKey in Provision api/provisioning.go Generate PSK after device key. Include in ConfigPayload.
Direct Peer API api/peers.go, main.go POST /api/v1/peers. Generate keys, alloc IP, create device.
Config Export api/peers.go GET /devices/:id/config. WireGuard [Interface]+[Peer] text.
QR Code api/peers.go (dep: go-qrcode) GET /devices/:id/qr. PNG 256x256.
Share Links api/share.go POST /devices/:id/share + GET /share/:token (public). Redis-backed.
Add Peer Modal AddPeerModal.vue, Devices.vue, api/peers.ts Form: Name, Server, AllowInternet. Success: QR + download + copy.
Config Modal PeerConfigModal.vue, Devices.vue, DeviceDetail.vue QR, config text, download, share link, copy.
Share Page ShareConfig.vue, router/index.ts Public route /share/:token. Shows expired for invalid.
Linked Devices LinkedDevices.vue, DeviceDetail.vue Table: AllowedIPs, Online/Offline, LastHandshake, Disconnect.
Firewall Sync api/peers.go Auto-create nftables rules for SSH (22) on peer create. Graceful on failure.

5. Phase 5.5: WGDashboard Config Parity

Goal: Feature parity for WG config editing + peer settings + firewall sync.

DB Model Updates:

  • WgServer: Added MTU (1420), DNS (1.1.1.1)
  • Device: Added EndpointAllowedIPs, DNS, MTU, PersistentKeepalive (25), Notes, IsSuspended, RxBytes, TxBytes

Backend API:

  • PUT /servers/:id — pointer fields for partial updates, firewall sync on port change
  • PUT /devices/:id — pointer fields for new Device fields
  • POST /devices/:id/suspend, /unsuspend — toggle + firewall rule
  • Config generation: DNS/MTU/Keepalive cascade (device > server > default)
  • Firewall sync on CreatePeer, Update (AllowedIPs change), Delete (cleanup)

Firewall Interface (existing):

  • AddForwardRule, RemoveForwardRule, AddInputRule, RemoveInputRule
  • Linux: via nft CLI. Stub: no-op for non-Linux.

Frontend:

  • Node Edit Modal — PUT /servers/:id with MTU, DNS, ListenPort
  • Advanced Peer Settings in DeviceDetail — accordion: AllowedIPs, DNS, MTU, Keepalive, Notes, Suspend toggle
  • API client: updateServer(), suspendDevice(), unsuspendDevice()

6. WireGuard VPN Functional Fix (wg-vpn-fix)

Goal: Fix 4 blocking gaps — server wg0 IP, peer sync, NAT/masquerade, device-agent TUN IP.

Scope: 10 files across server-core + device-agent.

Fix Files What
Interface types internal/wgmanager/manager.go Expanded interface + PeerConfig, PeerStatus types
Linux impl wgmanager_linux.go ip addr add, SyncPeers() replace-all, NAT masquerade
Stub wgmanager_stub.go Match new interface (no-op)
Handler wiring api/wg.go, api/devices.go, api/peers.go, api/provisioning.go Sync peers on create/delete/suspend/provision
main.go main.go Inject wgMgr to new handlers
Agent TUN IP device-agent/.../wireguard.go, device-agent/main.go Assign InternalIP to TUN device
Tests wgmanager/*_test.go, api/devices_test.go, api/wg_test.go Unit + integration

Unchecked (environment blockers, not implementation):

  • Dashboard build (needs submodule init)
  • Full E2E on Linux (needs WireGuard kernel module)
  • No duplicate nftables rules after restart toggle (needs Linux)

Key: NAT interface auto-detected via ip route show default, override via WG_NAT_INTERFACE env var.


7. Fix Gaps (nxg-fix-gaps)

Goal: Fix 6 gaps — stale artifacts, Dockerfiles, CI/CD, frontend tests, nftables Drop, crypto debt.

Gap What was done
Stale artifacts Deleted connect_remote.txt (JWT+SSH creds), temp_section*.txt. Confirmed never in git history.
Dockerfiles Created device-agent/Dockerfile (Go multi-stage). Pinned nginx:alpinenginx:1.27-alpine.
Root CI/CD Created .gitea/workflows/ci.yml — 3 jobs: server-core test, device-agent test, dashboard-ui build.
Frontend tests Installed Vitest + vue-test-utils + happy-dom. Config + 2 test files (auth store 5 tests, modal 3 tests). 9/9 pass.
nftables Drop Added conntrack rule (established/related accept). Changed forward policy Drop. Startup recovery loop (re-apply rules from DB). Auto input rule for WG port.
Crypto debt Documented in server-core/AGENTS.md. 69 lines stdlib, 2 callers — keep duplicated.

Files changed:

  • Deleted: connect_remote.txt, temp_section1.txt, temp_section2.txt
  • Modified: package.json, index.html, dashboard-ui/Dockerfile, nftables_linux.go, main.go, models.go, AGENTS.md
  • Created: device-agent/Dockerfile, .gitea/workflows/ci.yml, vitest.config.ts, hello.test.ts, add-peer-modal.spec.ts, auth-store.spec.ts

8. Fix Peers 500 + Delete Device

Goal: Fix HWID unique constraint violation (500 on POST /peers). Add delete button to Devices list.

Root Cause: Device.HWID string with uniqueIndex. Empty string "" collides → SQLSTATE 23505.

Fix: string*string. NULLs are distinct in PostgreSQL unique constraints.

Task Files
Model change internal/models/models.go:63 — HWID *string
CreatePeer fix api/peers.go — remove HWID: "" (nil is correct)
Delete button src/views/Devices.vue — add Delete to Actions column
SQL migration SSH: UPDATE devices SET hwid = NULL WHERE hwid = ''

9. Server-Core Multi-Stage Docker Build

Goal: Single-stage → multi-stage Dockerfile. Clean up orphan binaries.

Task Files
Dockerfile rewrite apps/server-core/Dockerfile — builder (golang:1.25) + prod (alpine:3.20)
.dockerignore apps/server-core/.dockerignore — exclude build artifacts
.gitignore update apps/server-core/.gitignoreserver-core* glob
Untrack binary git rm --cached server-core-linux
Delete binaries 3 files deleted: server-core, server-core-linux, bin/server-core

Key: Dev compose uses target: builder with volume mount at /app for air hot-reload.


10. Deployment Tools (nxg-deployment-tools)

Goal: Makefile + HWID migration on live server.

Task What
Makefile up, down, reset-db, logs, dev, migrate targets.
HWID migration SSH to 172.20.8.191: SQL UPDATE...SET hwid=NULL WHERE hwid=''. Restart container.

11. AGENTS.md Generation (agents-deep-init)

Goal: Generate hierarchical AGENTS.md for root + 3 submodules.

File Lines
./AGENTS.md Root — 109 lines: project overview, structure, code map, conventions, anti-patterns
apps/server-core/AGENTS.md 61 lines: Go backend reference
apps/dashboard-ui/AGENTS.md 58 lines: Vue 3 frontend reference
apps/device-agent/AGENTS.md 50 lines: Go stealth daemon reference

Key Anti-Patterns (Project-wide "Must NOT do")

  • NEVER nft flush table — only atomic add/remove
  • NEVER log plaintext or encryption keys
  • NEVER reopen completed phases/commits — fix forward only
  • NEVER rebuild shared/crypto/encryptor.go — copy identical file (known debt)
  • NEVER commit build artifacts (binaries, dist/)
  • NEVER force push
  • NEVER create cross-phase workarounds
  • NEVER change nftables input chain default (WG UDP listener needs Accept)
  • NEVER write WireGuard config to /etc/wireguard/ (stealth invariant)
  • NEVER use docker-compose (v1) — always docker compose (v2)

Files Modified (Master List)

server-core/ (Go/Gin backend)

main.go, models.go, api/servers.go, api/devices.go, api/peers.go, api/provisioning.go, api/wg.go, api/users.go, api/share.go, api/auth.go, internal/firewall/nftables_linux.go, internal/firewall/nftables_stub.go, internal/firewall/manager.go, internal/wgmanager/manager.go, internal/wgmanager/wgmanager_linux.go, internal/wgmanager/wgmanager_stub.go, internal/ipam/manager.go, internal/models/models.go, migrations/001_init.sql, AGENTS.md, Dockerfile, .dockerignore, .gitignore

dashboard-ui/ (Vue 3 frontend)

package.json, index.html, vitest.config.ts, Dockerfile, src/views/Servers.vue, src/views/Devices.vue, src/views/Users.vue, src/views/DeviceDetail.vue, src/views/ShareConfig.vue, src/views/Dashboard.vue, src/components/AddPeerModal.vue, src/components/PeerConfigModal.vue, src/components/LinkedDevices.vue, src/components/WgStatusCard.vue, src/api/peers.ts, src/api/servers.ts, src/api/users.ts, src/api/devices.ts, src/stores/auth.ts, src/router/index.ts, src/App.vue

device-agent/ (Go stealth daemon)

main.go, Dockerfile, internal/tunnel/wireguard.go

Root

Makefile, .gitea/workflows/ci.yml, AGENTS.md

Deleted (stale artifacts)

connect_remote.txt, temp_section1.txt, temp_section2.txt, apps/server-core/server-core, apps/server-core/server-core-linux, apps/server-core/bin/server-core