Add 'Copy VLANs from Another Switch' — a 3-step modal available on the
VLANs tab of any switch device. Step 1 selects a source switch and which
VLAN IDs to copy (VLAN 1 deselected by default with a management risk
warning). Step 2 lets the user assign interfaces on the target device
per VLAN: clicking a port chip cycles it through None → Tagged → Untagged
→ None, with a live summary and bridge picker per VLAN. Conflict detection
identifies VLANs already present on the target and offers per-VLAN
Skip/Overwrite with the port grid disabling itself when Skip is active.
Step 3 shows the full plan before a single apply call executes all
operations over one device connection and reports per-VLAN results.
Also fix CPU load display on the Devices page for hardware switches that
report 0% CPU via ASIC offloading — the previous filter (v > 0) silently
dropped all valid zero readings; now filters on field presence instead.
New Syslog page under Network Services exposes RouterOS logging actions
and routing rules with full CRUD. Logging actions define destinations
(remote syslog server, memory, disk, echo); logging rules define which
topics route to which action.
Single Device and All Devices modes are functionally identical — All
Devices applies changes across every online device in parallel and
shows per-entry coverage badges indicating which devices have each
action or rule. Toggle enable/disable works in both modes.
Remote actions display address:port with facility/severity in a single
Destination column; memory/disk/echo rows show no irrelevant remote
fields. Syslog KPI card added to the Network Services overview.
Add a right-justified refresh interval dropdown above the client table
with options for Not Updating, 30 s, 1 min, and 3 min. The chosen
interval controls both React Query polling and WebSocket-triggered
invalidations — selecting Not Updating fully freezes the list until
page reload. Preference persists via localStorage.
RouterOS vs RouterBOOT distinction:
- Rename "Firmware Updates" → "RouterOS Updates" everywhere (Config tab,
dashboard banner, devices list tooltip) to accurately reflect what is
being updated
- Add RouterBOOT bootloader upgrade support as a distinct operation:
new DeviceCollector methods checkRouterboardUpgrade() and
installRouterboardUpgrade() using /system/routerboard/print and
/system/routerboard/upgrade
- New API endpoints: POST /api/devices/:id/check-routerboard and
POST /api/devices/:id/install-routerboard
- Daily poller now also checks RouterBOOT upgrade status while already
connected during firmware check cycle, with first-discovery alerts
Config tab update panel:
- Combine RouterOS and RouterBOOT into a single "Software & Firmware
Updates" card with two subsections separated by a divider
- Pre-populate both sections from stored DB state on load — no longer
requires a manual "Check" click to see a known pending update
- Enforce update order: when both are pending, show a blue info banner
explaining RouterOS must be installed first, and disable the
RouterBOOT "Upgrade & Reboot" button until the RouterOS update clears
- Fix GET /api/devices/:id to include firmware_update_available,
latest_ros_version, routerboard_upgrade_available, upgrade_firmware_version
(these were missing from the detail endpoint)
Dashboard & devices list:
- Combined amber banner now shows two distinct rows: RouterOS (N) with
device links and RouterBOOT (N) with device links — one dismiss for both
- Devices list: amber ArrowUpCircle = RouterOS update, blue Cpu icon =
RouterBOOT upgrade, each with distinct tooltips
- Fix GET /api/devices (list) to include routerboard_upgrade_available and
upgrade_firmware_version (these were missing, causing RouterBOOT
notifications to never appear on the dashboard)
DB migration:
- Add routerboard_upgrade_available BOOLEAN DEFAULT FALSE
- Add upgrade_firmware_version VARCHAR(20)
Discovery system fixes:
- Fix duplicate entries: replace single-key (mac || ip || identity) dedup
with three cross-referenced indexes so a neighbor seen via LLDP by one
device and via MNDP by another always merges into one row
- Fix offline devices persisting: handleDeviceFailure now deletes
topology_links for the offline device (same pattern as clients)
- Add periodic stale-link sweep every 15 min that removes topology_links
rows older than 20 min as a safety net for devices that go offline
without cleanly triggering handleDeviceFailure
Documents CORS_ORIGIN env var, credential preset operator access control,
and server-side bulk device add job in README. Bumps version across all
four locations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Squash-merge of PR #28 from @denis-ev. All three review blockers addressed: encryption key management documented, string truncation replaced with skip+warn validation, and undefined return on duplicate merge fixed with proper 500. Local test stack verified against cloned prod DB — migrations, new features, and backend all clean.
Adds a 'Built with Claude AI' badge to the README header and an
'AI Assistance' section acknowledging that the project was designed
and built with Claude by Anthropic. Updates SECURITY.md with an
'AI-Assisted Security Infrastructure' section detailing the specific
security work that was AI-generated — linting rules, unit tests,
CI pipeline, and credential handling design.
Adds a GitHub Actions workflow that builds and pushes backend and nginx
images to GitHub Container Registry on every merge to main and on
releases. Adds docker-compose.ghcr.yml for end users who want to deploy
without cloning the repo, and updates the README with Quick Deploy
instructions alongside the existing build-from-source guide.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>