Commit Graph
94 Commits
Author SHA1 Message Date
2GT-RichandClaude Fable 5 6f0fbdb74f chore(deps): dependency upgrades — react-router 7, eslint 10, TS 6, plugin-react 6; drop unused zod (v0.16.5-beta)
Applies the open dependabot PRs in one validated pass:

- react-router-dom 6.30 -> 7.18 (drop-in for our API surface; verified
  in-browser: login, sidebar routing, ?type= deep-links, legacy redirects)
- react + react-dom -> 19.2.7, axios -> 1.18.0, lucide-react -> 1.21.0
- actions/checkout v6 -> v7 across all workflows
- backend: eslint 10 + @eslint/js 10 (fix 5 new no-useless-assignment
  findings), typescript 6.0.3 (explicit types: ["node","jest"] in
  tsconfig — TS 6 no longer auto-includes @types), remove zod (unused)
- frontend: @vitejs/plugin-react 6

Not taken: ioredis 5.11.1 (#55) — bullmq pins ioredis to exactly 5.10.1
(including latest bullmq 5.79), so the bump nests a second ioredis and
breaks BullMQ connection types.

Validation: backend tsc/lint/build + 92 tests green; frontend tsc/lint/
build + 11 tests green; docker stack rebuilt and browser-verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 20:35:21 -07:00
2GT-RichandClaude Fable 5 dd1b6b7d13 feat(ui): navigation reorganization — consolidate duplicate pages, grouped sidebar (v0.16.4-beta)
UI/UX consolidation pass to reduce nav sprawl (~24 destinations -> ~17):

- Merge Router Settings + Switch Settings (copy-paste duplicates) into one
  Network Services > Discovery & SNMP page with an All/Routers/Switches
  scope selector; LLDP + SNMP status tables merge both fleets with a
  type pill, apply fans out per scope
- Retire Routers/Switches overview pages; the Devices type filter now
  lives in the URL (?type=AP|SW|RTR) and legacy routes redirect to the
  pre-filtered view. Wireless overview kept (RF Health / Rogue APs are
  unique content)
- Fold Wireless Clients into Clients: All/Wired/Wireless segmented
  filter (URL-synced); wireless view swaps the Type column for SSID +
  signal quality columns
- Regroup sidebar into Monitor / Network / Services / Operations
  sections; Devices and Wireless are collapsible groups (auto-open on
  active section, manual collapse always wins); Wireless group renders
  only when wireless APs exist
- Rename Syslog -> Logging with a cross-link to live Events; group the
  Settings tabs into Platform / My Account / Fleet sections
- Legacy routes (/routers, /switches, /routers/settings,
  /switches/settings, /wireless/clients) redirect so bookmarks keep
  working

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 08:07:08 -07:00
2GT-RichandClaude Opus 4.8 9dfb8a5333 feat: Guest WiFi, network intelligence, firmware orchestration, platform automation, api-ssl (v0.16.3-beta)
Guest WiFi (Hotspot): one-click captive-portal wizard that creates the guest
SSID (virtual AP per radio), VLAN/bridge segregation + L3 VLAN interface, pool,
DHCP, portal, rate-limited guest profile, and masquerade; vouchers with limits +
printable sheets; live guest sessions; walled garden.

Network intelligence: per-client device fingerprinting (vendor/hostname →
category) with a persisted per-client override on the detail page; rogue/neighbor
AP detection from stored AP scans (evil-twin flagging); Mist-style anomaly
insights (client-count/CPU vs same-hour 14-day baseline + error bursts) in the
Operations engine.

Firmware orchestration: staged wave-based RouterOS rollouts (canary first) with
pre-upgrade backup, reboot-ride-out, version verification, halt-on-failure, and
scheduling; live per-device progress + cancel.

Platform & automation: scoped API tokens (mtm_, read/write, hashed at rest,
Bearer auth in requireAuth); outbound webhooks (12 events, HMAC-signed) fired
from the alert pipeline + firmware orchestrator; scheduled email reports.

api-ssl: RouterOSClient negotiates TLS on port 8729 and accepts RouterOS's
default self-signed certs (rejectUnauthorized:false), so SSL-secured API devices
connect without manual cert trust. Fixes #57.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 21:58:02 -07:00
2GT-RichandClaude Opus 4.8 6cfca387d8 feat(ops): operations insights engine + working quick actions; fix global search (v0.16.2-beta)
Global search:
- Clicking/Enter on a client result now opens that client's detail page
  (/clients/<mac>) instead of dumping to the clients list.

Operations dashboard (new backend route /api/operations):
- GET /insights: server-side attention engine (offline, updates, CPU/memory
  pressure, missing backups, recent outages, weak WiFi clients, co-channel
  overlap, high TX retries, error events) + per-device capacity + merged
  activity feed (config changes, audit actions, alerts; login noise filtered).
- POST /backup-all and /sync-all: fleet-wide actions over online devices.
- Quick Actions now execute: Run discovery, Backup all, Sync config, and
  Open terminal (device picker -> live SSH TerminalModal); inline status.
- New cards: Capacity & health meters, Security posture rollup (reuses
  per-device posture, cached), Recent activity feed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:12:16 -07:00
2GT-Rich 4e6c9f481e feat(wireless+ports): RF Health panels + physical per-port clients (v0.16.1-beta)
Wireless RF Health (fleet Wireless page + per-AP Radios tab):
- Channel usage map across 2.4/5/6 GHz with co-channel overlap; operating
  channel resolved live from /interface/wifi/monitor on the wifi package
  (auto-channel radios report no frequency in /print).
- AP deployment density: client RSSI distribution on the -90..-30 dBm scale
  with a coverage-gap warning.
- AP radio TX retries histogram (0%->35%+) with band selector, derived from
  per-client CCQ (new wireless_radio_quality InfluxDB series).
- WiFi connectivity success funnel (Association/Auth/DHCP) derived from logs.

Per-port connected clients (Ports tab):
- New card lists clients physically connected to a selected port (host/MAC/
  IP/VLAN/connection time, linked to client pages).
- Distinguishes physical clients from the raw MAC table: uplink/trunk ports
  are auto-detected (topology neighbor, multi-VLAN MAC spread, or high MAC
  count) and show an uplink explainer + "view MAC table" disclosure instead
  of every reachable MAC.
- Added clients.first_seen ("connected since"); set once, preserved across polls.
2026-06-25 15:37:08 -07:00
2GT-RichandClaude Opus 4.8 1be161e67a feat(ui): modern clients pagination + unified syslog page (v0.16.0-beta)
Clients:
- Replace Previous/Next buttons with a "Show N entries" dropdown
  (25/50/100/200, persisted to localStorage) and numbered page selection
  with prev/next chevrons and ellipses for long ranges.

Syslog (Network Services):
- Drop the Single Device / All Devices mode toggle; always show the
  fleet-aggregated view with coverage badges.
- Add a per-section device dropdown + "Add to device" button beside
  "Add to All Devices" for targeting a single device (direct save).
- Edit / enable-disable / remove remain coverage-scoped, so single-device
  management is preserved without the separate mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 08:53:19 -07:00
2GT-RichandClaude Opus 4.8 6e56048f2f chore(deps): bump axios, react-query, lucide-react, pg (v0.15.1-beta)
Validated dependency updates (Dependabot #41, #42, #43, #48):
- axios 1.16.0 → 1.16.1
- @tanstack/react-query 5.95.2 → 5.101.0
- lucide-react 1.16.0 → 1.17.0
- pg 8.20.0 → 8.21.0

Holding ioredis at 5.10.1: 5.11.1 (#45) breaks the backend build via a
type mismatch with BullMQ's bundled ioredis copy; leave until BullMQ
bumps its pinned ioredis.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 16:44:30 -07:00
2GT-RichandClaude Opus 4.8 b1dd62bd1f feat(traffic): protocol breakdown layout + inbound packets chart + flow source health (v0.15.0-beta)
- Traffic by Application: donut + legend side-by-side, larger donut with
  center total label, percentage in tooltip; card now sizes to its content
- New Inbound Packets area chart below the throughput chart (packets field
  now summed per direction in /traffic/timeseries)
- New Flow Sources & Data Health card: collector listening state, packets
  received, flows attributed, attribution rate, per-exporter flow/packet
  counts and last-seen; low-attribution hint for NAT-in-path exporters
- /traffic/apps now returns per-app packets alongside bytes
- Restructured bottom row: Top Talkers (left) | Application + Data Health
  stacked (right) for alignment
- Tightened Top Talkers row spacing

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 16:32:17 -07:00
2GT-RichandClaude Opus 4.8 d79eb13119 feat(ui): theme-aware logo, dashboard bar graph, server-side client sorting (v0.14.1-beta)
UI/UX refinements on top of v0.14.0-beta, all validated on the test server:

- Logo: new theme-aware compass iconmark (light/dark SVGs swapped via the
  dark class), sized to 45px; favicon updated to match. Wordmark casing
  corrected to "MikroTik Manager" (font size unchanged).
- Navigation icons enlarged 15 -> 17px.
- Dashboard: "Connected clients" line chart converted to a bar chart with a
  category axis + light downsampling so bars stay readably thick across ranges.
- Clients: sorting is now server-side across the whole dataset (was sorting
  only the current page, so Type/others appeared to do nothing on a uniform
  page); table uses a fixed column layout + keepPreviousData so columns no
  longer jump or blank out when sorting/paging. Backend clients route gains
  whitelisted sort/dir params (safe numeric IP sort, deterministic tiebreaker).
- Connections tab: surfaces the live /ip/firewall/connection/tracking state
  (on/auto/off pill) and clearer empty-state copy explaining auto-mode.

Lint/typecheck/build/jest green in both workspaces; npm audit --audit-level=high
clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:37:11 -07:00
2GT-RichandClaude Opus 4.8 ee9c9ff9f7 feat(security): Security Center — firewall, NAT, bandwidth, posture, connections (v0.14.0-beta)
A dedicated top-level Security section plus a Meraki/UniFi-grade firewall built
on the full RouterOS feature set.

Security Center (new /security page)
- Fleet hardening scores, per-device posture list, and a "Common Findings"
  rollup aggregating identical issues across the fleet
- "Manage" deep-links into the device's Security tab (?tab= support added)

Firewall & NAT (per device + in Security Center)
- Friendly rule builder: Allow/Drop/Reject chips, Any/Address/Address-List
  pickers, port presets, connection-state chips, logging, live plain-English
  preview
- Address lists as reusable objects, referenced from rules
- Rule reordering (/ip/firewall/{filter,nat}/move); per-rule hit counters
  (print stats) with dead-rule highlighting + reset
- NAT wizards: Port Forward / Masquerade / 1:1 NAT + Custom
- Safe-apply lockout guard: backend 409 on an unscoped input drop/reject that
  would sever management; UI confirms before forcing (detectLockoutRisk, tested)

Access & security
- Security posture audit: graduated, de-duplicated scoring that never proposes
  disabling the management service the platform connects through (no self-
  lockout); switch-aware input-firewall severity; service hardening table
- Bandwidth: simple-queue CRUD + one-click "Limit this client" on client detail
- Active connections viewer

These L3 features are available on all managed RouterOS devices (routers,
switches, APs), not gated by device type.

Backend: DeviceCollector address-list/move/stats/connections/queues/service
methods; device routes for all of the above; firewallSafety + firewallSummary
utils with unit tests (19 new).

Security: bump nodemailer 8 -> 9.0.1 to clear GHSA-p6gq-j5cr-w38f (our
createTransport/sendMail usage is unaffected by the advisory's raw-option path).

Verified live against RouterOS devices; lint/typecheck/build/jest green in both
workspaces; npm audit --audit-level=high clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 09:24:22 -07:00
2GT-RichandClaude Opus 4.8 623e54120d chore(deps): clear high-severity npm audit findings (v0.13.3-beta)
CI Security Audit (npm audit --audit-level=high) was failing. Resolved all
high-severity advisories via non-breaking transitive bumps (npm audit fix,
no --force, no direct-dependency or source changes):

- frontend: form-data, ws (via socket.io-client), @babel/core,
  react-router-dom, js-yaml — now 0 vulnerabilities
- backend: form-data, ws (via socket.io) — 0 high-severity remaining

Only package-lock.json files changed plus the version bump. Verified both
workspaces: npm ci, lint, type-check, build, and backend jest (73 tests)
all pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 19:51:45 -07:00
2GT-RichandClaude Opus 4.8 e777276e41 fix(clients): unify client traffic chart timeframes to 2h/24h/7d and stop App Traffic card vanishing (v0.13.2-beta)
The two per-client usage charts exposed different time windows: "Wireless
Usage" offered 2h/24h/7d while "App Traffic (NetFlow)" offered 1h/24h/7d/30d.
Worse, selecting 1h (or any range with no flows in window) made the whole
App Traffic card unmount — including its range buttons, so it couldn't be
recovered without reloading.

- AppTrafficCard now uses 2h/24h/7d (default 24h), matching Wireless Usage
- Card visibility latches on first non-empty result, so switching to an
  empty range shows an inline "No traffic data yet for this range" state
  instead of unmounting the card (latch derived via guarded setState in
  render — no effect)
- Backend /api/traffic/* now accepts the '2h' range (rangeToFlux +
  windowForRange: 2h -> 2m buckets); previously '2h' silently fell back to 24h

Verified in the live stack with Playwright: ranges render as 2h/24h/7d (no
1h/30d), and clicking 2h on a client with data only outside the 2h window
keeps the card mounted with an empty-state and recovers on switching back.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 19:38:16 -07:00
2GT-RichandClaude Fable 5 368b4e83b6 feat(dashboard): unify Top Talkers with NetFlow traffic data (v0.13.1-beta)
The Dashboard "Top talkers" card and the Traffic page previously used
different data sources: the card ranked clients by device-reported
since-connection byte counters (wireless-centric, reset on reconnect, no
time window), while the Traffic page uses NetFlow-measured bytes.

The card now prefers the NetFlow top-clients data (last 24h — identical
numbers to the Traffic page) and falls back to the legacy counters only
when the collector has no data, with the source labeled in the card
header ("by bytes · 24h" vs "since connection"). Rows now click through
to the client detail page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 17:31:59 -07:00
2GT-RichandClaude Fable 5 b841eb6e7b feat: NetFlow/IPFIX traffic analytics — per-client usage, app breakdown, built-in collector (v0.13.0-beta)
Adds Meraki-style traffic analytics powered by MikroTik Traffic Flow:

Backend
- Built-in NetFlow v9 + IPFIX collector (UDP 2055) with hand-rolled decoder,
  template caching, enterprise-field and IPv6 support
- Flow attribution: client IP → MAC via the clients table, upload/download
  direction, NAT-duplicate records dropped
- App classification by protocol/port (~25 categories: HTTPS, QUIC, DNS,
  SSH, Email, WireGuard, ...)
- Deduplication: per-client best-exporter-per-window so flows crossing two
  managed routers are never double-counted
- NAT-tolerant ingest: flows from sources matching no managed device (NAT /
  Tailscale subnet routers in path) are accepted as per-source unidentified
  exporters instead of silently dropped (netflow_accept_unknown setting)
- Storage: InfluxDB client_traffic time-series (bounded cardinality via
  top-N fold) + Postgres client_traffic_daily rollups; daily retention purge
- One-toggle device config push via RouterOS API (/ip traffic-flow + target)
- New /api/traffic/* analytics endpoints + /api/network-services/netflow
- docker-compose: NETFLOW_PORT (default 2055/udp) published on the backend

Frontend
- New Traffic page: fleet up/down chart, top talkers with client
  click-through, app-category donut, 1h–30d ranges
- New NetFlow config page: collector settings, live ingest stats,
  per-device export toggles with health badges, NAT-source banner
- Client detail: App Traffic card (auto-hides without data)
- Clients page: sortable "Data (today)" column
- Settings: NetFlow retention controls

Includes 17 unit tests (decoder fixtures, dedup, attribution, classifier);
verified end-to-end against live RouterOS devices.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:58:41 -07:00
2GT-RichandClaude Opus 4.8 367034c2d6 feat: config history (diff/rollback) + friendly backup scheduling (v0.12.3-beta)
Configuration History:
- Per-device snapshots from the full RouterOS /export (.rsc) — config-only, so
  counters/operational state no longer cause phantom changes; deduped by content hash
- New Config History tab: snapshot timeline, readable line diff, on-demand Capture
  (with honest 'no changes' feedback), one-click rollback via the linked .rsc backup
- Snapshot and its backup are one artifact: badged 'Config Snapshot' on the Backups
  page, FK ON DELETE CASCADE keeps them in lockstep; delete is gated by a warning modal
- New config_drift alert event (off by default); periodic snapshot poll with
  configurable cadence/retention (config_snapshot_interval_min/_retention)
- New endpoints under /api/config-history (list/get/diff/capture/rollback/delete)

Scheduled Backups:
- Replaced the raw cron textbox in Settings with Frequency (Daily/Weekly/Monthly)
  + time + day pickers; cron is generated/parsed behind the scenes
- Fixed cronMatchesNow to evaluate day-of-month/month/day-of-week (it previously
  only checked minute/hour, so weekly/monthly schedules ran every day)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:01:58 -07:00
2GT-RichandClaude Sonnet 4.6 914ded24b0 chore(deps): upgrade to React 19, react-dom 19, lucide-react v1, helmet v8 (v0.11.11 Beta)
- React + @types/react bumped to v19 (merged Dependabot PRs #22, #23, #25)
- react-dom + @types/react-dom aligned to v19 (PR #26 had conflicts; applied manually)
- lucide-react upgraded from 0.309 → 1.16 to satisfy React 19 peer deps (no API changes for our icon usage pattern)
- helmet upgraded 7 → 8; contentSecurityPolicy: false option unchanged
- jest + @types/jest bumped (dev-only, no runtime impact)
- TypeScript clean, Vite build passes, zero new errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 16:17:42 -07:00
2GT-RichandClaude Sonnet 4.6 fc27f2a4a2 fix: resolve CodeQL security alerts (v0.11.10 Beta)
Log injection (3 errors fixed):
- errorHandler.ts: sanitize req.path before logging (strip \r\n)
- clients.ts: sanitize mac param in two Flux error log lines

Dismissed as false positives or won't-fix with justifications:
- Insecure Helmet config: CSP intentionally disabled (self-hosted,
  Vite/React inline styles require complex allowlist)
- Permissive CORS: wildcard only active when admin explicitly sets
  CORS_ORIGIN=*, documented as unsafe
- Network data to file (cert.ts x2): intentional cert upload feature
- File system race (oui.ts): trusted startup URL, no attack surface
- Insecure temp file (oui.ts): server-side OUI DB, not user-accessible
- Remote property injection (DeviceCollector.ts): data from trusted
  RouterOS API on admin-credentialed device, not user HTTP input
- Rate limiting (19): all routes behind JWT; login already rate-limited

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 15:55:11 -07:00
2GT-Rich 3eb85087f2 fix: SNMP status table no longer vanishes after back/return navigation (v0.11.9 Beta)
Root cause: backend filtered switches by status='online', so a mid-poll-cycle
device (briefly 'unknown') caused the endpoint to return [] — and the frontend
rendered nothing when the array was empty.

- Backend: query ALL switch devices (not just online ones); unreachable devices
  already fall through to the Promise.allSettled error path and render with an
  error badge, so no data is lost
- Frontend: replace silent `length > 0 &&` guard with a three-way ternary that
  shows a "No managed switches found" message when the array is empty, so the
  user always sees feedback instead of a blank section
- Frontend: add staleTime: 60_000 to the SNMP query to prevent the hair-trigger
  background refetch that raced with the poller on every navigation
2026-05-17 20:04:33 -07:00
2GT-Rich b1e4944823 feat: version update check — notify when newer version is on GitHub (v0.11.8 Beta)
Backend: GET /api/system/version-check fetches frontend/package.json from
the main branch on GitHub, caches result in app_settings for 24 hours,
and compares semver against the running version. Fails silently (no banner)
for air-gapped or firewalled deployments.

Frontend: dismissible blue update banner in SecurityBanners (rendered
between TopBar and main content) — only visible when a newer version is
detected. Shows target version and docker compose update command.
2026-05-17 19:38:25 -07:00
2GT-Rich bf62b9e10f docs: update README for v0.11.7 Beta — all new features documented
Added sections for: Device Tags, Availability Tracking, Network Topology
improvements (LLDP-authoritative, manual links, orphan detection), Device
Network Tools table (Ping/Traceroute/IP Scan/WoL/Packet Capture/Bandwidth
Test), Scheduled Backups, Maintenance Windows, Audit Log, Configuration
Templates, and TOTP 2FA. Alert delivery channels listed. Project structure
updated to note audit middleware. Version bumped to 0.11.7 Beta.
2026-05-16 16:56:42 -07:00
2GT-RichandClaude Sonnet 4.6 63a7f4d785 feat: improve network topology — LLDP-authoritative, manual links, orphan handling (v0.11.6 Beta)
- Backend: 7-step pipeline — per-neighbor best-protocol dedup, bidirectional
  LLDP pair merging, LLDP-covered set suppression of noisy CDP/MNDP links,
  shared-segment heuristic limited to genuinely unresolved non-LLDP links
- Backend: manual_topology_links table + POST/DELETE endpoints for user-drawn connections
- Frontend: ManualEdge custom edge type (purple dashed + × delete button)
- Frontend: Connect Mode toggle — blue crosshair handles, onConnect creates DB-persisted link
- Frontend: orphan nodes in dedicated bottom row with orange warning banner
- Frontend: legend updated, canvas height increased

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 16:13:20 -07:00
2GT-RichandClaude Sonnet 4.6 64bb8b1b93 feat: packet capture, bandwidth test (v0.11.5 Beta)
- Packet capture: RouterOS sniffer + SFTP download to PCAP for Wireshark analysis
- Bandwidth test: RouterOS /tool/bandwidth-test with TX/RX Mbps result display
- Both exposed in the Tools tab on device detail pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:50:31 -07:00
2GT-RichandClaude Sonnet 4.6 a1ca4d0a44 feat: 2FA/TOTP, config templates (v0.11.4 Beta)
- 2FA: TOTP setup wizard in Settings, QR code enrollment, login second-step, password-confirmed disable
- Config templates: reusable DNS/NTP/syslog config sets pushed to selected devices via RouterOS API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:44:23 -07:00
2GT-RichandClaude Sonnet 4.6 49ab1b002e feat: audit log, device tags, maintenance windows (v0.11.3 Beta)
- Audit log: middleware captures all write operations, paginated admin UI in Settings
- Device tags: full CRUD, device assignment, filter bar and chips on Devices page
- Maintenance windows: alert suppression during planned downtime, Settings management UI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:33:15 -07:00
2GT-RichandClaude Sonnet 4.6 6a4ab1fc5f feat: scheduled backups, availability tracking, PoE power metrics (v0.11.2 Beta)
P1 — Scheduled Backups
- BackupService.createBackup() now accepts a `type` param (manual/scheduled)
- PollerService: cronMatchesNow() parser + runScheduledBackups() + Redis 1h gate
- Settings page: backup schedule toggle + cron expression input with examples

P2 — Uptime/Availability Tracking
- DB: device_availability table (went_offline_at, came_back_online_at, duration_seconds)
- PollerService: inserts outage rows on offline detection, closes them on recovery
- GET /api/metrics/device/:id/availability?range=30d endpoint
- /api/metrics/summary now includes fleet 30-day uptime %
- DeviceDetailPage: 30-day availability card (uptime %, outage count, longest outage)
- DashboardPage HealthBar: Uptime 30d mini-stat

P3 — PoE Power Draw Metrics
- DeviceCollector.collectPoePower() queries /interface/ethernet/poe/monitor for switches
- Writes poe_power measurement to InfluxDB (tags: device_id, port; fields: watts, current_ma, voltage_v)
- GET /api/metrics/device/:id/poe endpoint (current per-port + 1h history)
- SwitchPortDiagram: amber watt badge on PoE-active ports
- HardwareTab: PoE budget section showing active ports and total watts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:19:58 -07:00
2GT-RichandClaude Sonnet 4.6 e692a1d7cd fix: syslog coverage count exceeding device total + remove decorative live indicator (v0.11.1 Beta)
- aggregateRules/aggregateActions: deduplicate coverage per device using a per-device seenKeys set,
  preventing a device with duplicate topic|action rules from inflating the coverage count above total
- executePush (add path): skip devices that already have an identical rule/action before pushing to
  all devices, preventing duplicate RouterOS logging entries from being created in the first place
- TopBar: remove hardcoded decorative 'live' indicator that had no backend connection logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 16:39:07 -07:00
2GT-Rich 4abc96f015 Change login page screenshot width to 100%
Updated the width of the login page screenshot to 100%.
2026-05-15 16:13:53 -07:00
2GT-Rich d3aa72c488 feat: Copy VLANs wizard + CPU display fix for hardware switches (v0.11.0 Beta)
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.
2026-05-15 14:43:53 -07:00
2GT-Rich 3a7ac1d023 Minor UI Rework + Introduction of Operations view. 2026-05-11 16:46:36 -07:00
2GT-Rich e5f630ef2f feat: add Syslog configuration to Network Services (v0.10.8 Beta)
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.
2026-04-24 15:40:20 -07:00
2GT-Rich ac39598257 feat: add configurable refresh interval to Clients page (closes #32)
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.
2026-04-23 16:20:22 -07:00
2GT-Rich 68d88d0306 feat: RouterBOOT upgrade support, update UI overhaul, discovery fixes (v0.10.6 Beta)
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
2026-04-23 13:46:20 -07:00
2GT-Rich 138d7a935b chore: bump version to v0.10.5 Beta
Follows security fixes from #33: trust proxy, login rate limiting,
and default secret banners.
2026-04-22 09:31:01 -07:00
2GT-RichandClaude Sonnet 4.6 0350a76232 chore: bump version to v0.10.4 Beta and update docs for PR #31 features
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>
2026-04-21 19:57:47 -07:00
Denis 30bf691596 feature(devices,topology,tz): devices bulk-add, duplicate safety, and firmware/timezone fixes
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.
2026-04-21 16:52:04 -07:00
2GT-Rich 5562ac31dd Fixing typo in README.md. Thanks to @JustinClift for pointing it out! 2026-04-20 17:16:15 -07:00
2GT-Rich 3efdf4c76e Add AI attribution to README and SECURITY docs
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.
2026-04-20 11:38:24 -07:00
2GT-RichandClaude Sonnet 4.6 25ae3854b4 Add GHCR publish workflow and pre-built image deployment
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>
2026-04-19 10:21:21 -07:00
2GT-Rich ab9572122e missed point release update. 2026-04-15 09:33:03 -07:00
2GT-Rich 20fd3b9329 Clairified API connectivity in README.md 2026-04-14 08:30:01 -07:00
2GT-Rich a0faa35a59 Fixing typo in README.md 2026-04-14 08:26:39 -07:00
Rich Teslow e16e86a0cf Updated README 2026-04-13 18:24:45 -07:00
Rich Teslow 6b0fc9fdf1 Initial commit baby! 2026-04-13 18:15:41 -07:00
2GT_BK 10e6227931 Initial commit 2026-04-13 19:05:01 -06:00