Nexxus

Frontend Developer2025
Active
ReactTypeScriptReact FlowZustandSSE

Nexxus is the network monitoring platform I work on at Osnet, a WISP in Colombia. It's a real-time operational workspace where NOC operators monitor 200+ network devices -- MikroTik routers, Ubiquiti and Cambium access points, HPE switches, Juniper gear -- all visualized on interactive maps with live status updates.

What it does

The core is a React Flow-based map editor. Each map shows network devices as nodes and their physical/wireless connections as edges. Operators can create multiple maps with nested sub-maps for different network segments, add text annotations with a Tiptap rich text editor, and navigate between levels.

Map architecture
Map (parent)
├── NetworkNode (MikroTik router)     ── status: up/down via SSE
├── NetworkNode (Cambium AP)          ── status: up/down via SSE
├── SubMap (Distribution Centro)      ── click to drill down
│   ├── NetworkNode (switch)
│   ├── NetworkNode (access point)
│   └── ...more devices
├── Label (annotation)                ── rich text via Tiptap
└── Edges (fiber / wireless / cable)  ── traffic visualization

Devices are polled via SNMP/ICMP by the NestJS backend, and status changes push to the frontend through SSE streams -- one for device status, one for link status. The UI updates in real time without polling.

Integrations

Osnet already had established tools for different parts of network management before Nexxus existed. Rather than asking operators to abandon them overnight, Nexxus bridges into these platforms -- surfacing their data in context, on the map. Most of these integrations are planned to be replaced by Nexxus-native features as the platform matures; for now, they let operators work from a single interface without a disruptive migration.

  • Cambium cnMaestro -- AP performance metrics, radio stats, client counts (OAuth2 proxy through Next.js API routes with automatic token refresh)
  • UISP/UNMS -- Ubiquiti device telemetry
  • Unimus -- config backup diffs and change tracking
  • Ubersmith -- ticketing integration (ticket badges render directly on device nodes)
  • LibreNMS -- extended monitoring data

Map UX details

The map is more than a simple graph viewer. Some of the operational features:

  • Level of Detail -- nodes render differently based on zoom: just a status dot at low zoom, icon + name at medium, full detail with IP, badges, integrations at high zoom
  • Context menus -- right-click on nodes, edges, labels, selections, or empty canvas each open different context menus with relevant actions
  • 8-direction edge handles -- edges connect from the optimal side of the node
  • Parallel edge offset -- multiple links between the same pair of devices spread out visually
  • Edge waypoints -- custom routing points for complex topologies
  • Traffic visualization -- edge color and thickness change based on bandwidth utilization
  • Sub-map connections -- map links connect sub-maps to each other at the parent level
  • Undo/redo -- full edit history in edit mode
  • Auto-layout -- grid, hierarchical, and force-directed layout algorithms
  • Search -- command palette for finding devices across maps
  • Alerts and channels -- configurable alert rules with notification channels (Teams, etc.)
  • Event log -- status change history for audit and troubleshooting
  • i18n -- full English/Spanish support via next-intl

The performance problem

When I joined the project, the map was slow. Frame drops during pan and zoom, visible lag on SSE events, and the UI choking as device count climbed past 100.

The team had started exploring a V3 map built with Konva (HTML5 Canvas) to replace React Flow, under the assumption that the rendering library was the bottleneck.

Profiling told a different story. React Flow was fine. The real problem was the state layer.

Every SSE event -- even a single device flipping from up to down -- triggered re-renders across the entire component tree. The Zustand stores weren't granular enough. State updates cascaded through shared selectors, so nodes that hadn't changed were still re-rendering.

The fix

The V2 map was restructured with a clear separation:

Refactored map layers
Map Component
├── ViewModel layer        ── converts store → ReactFlow nodes/edges
│   ├── Node state         ── isolated per-device updates
│   └── Edge state         ── isolated per-link updates
├── Actions layer          ── all user interactions
│   ├── Layout             ── undo/redo, auto-layout
│   ├── Persistence        ── save positions to backend
│   ├── Selection          ── multi-select, align, distribute
│   └── Edge editing       ── waypoints, handle direction
└── UI sections
    ├── Header, status bar
    ├── Tooltips, context menus
    ├── Modals (device, edge, label, ticket, classification)
    └── Sidebars

The data store uses Map<string, T> for O(1) device lookups. Selectors subscribe to individual device IDs, so an SSE update for one device only re-renders that one node. The V3 Konva rewrite became unnecessary.

After the state refactoring, the map runs at consistent 60 FPS with 200+ devices. The rendering layer was always capable -- it just needed clean state.

Stack

Frontend: Next.js 14, React 18, TypeScript, React Flow, Zustand, TanStack Query, Tiptap, Framer Motion, next-intl, next-auth

Backend: NestJS, MongoDB, SNMP/ICMP polling, SSE streams