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 (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.
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:
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.
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
Nexxus es la plataforma de monitoreo de red en la que trabajo en Osnet, un WISP en Colombia. Es un espacio de trabajo operativo en tiempo real donde los operadores del NOC monitorean 200+ dispositivos de red -- routers MikroTik, access points Ubiquiti y Cambium, switches HPE, equipos Juniper -- todos visualizados en mapas interactivos con actualizaciones de estado en vivo.
Que hace
El nucleo es un editor de mapas basado en React Flow. Cada mapa muestra dispositivos de red como nodos y sus conexiones fisicas/inalambricas como aristas. Los operadores pueden crear multiples mapas con sub-mapas anidados para diferentes segmentos de red, agregar anotaciones de texto con un editor Tiptap, y navegar entre niveles.
Mapa (padre)
├── NodoRed (router MikroTik) ── estado: up/down via SSE
├── NodoRed (AP Cambium) ── estado: up/down via SSE
├── SubMapa (Distribucion Centro) ── click para explorar
│ ├── NodoRed (switch)
│ ├── NodoRed (access point)
│ └── ...mas dispositivos
├── Etiqueta (anotacion) ── texto enriquecido via Tiptap
└── Aristas (fibra / wireless / cable) ── visualizacion de trafico
Los dispositivos se consultan via SNMP/ICMP desde el backend NestJS, y los cambios de estado llegan al frontend a traves de streams SSE -- uno para estado de dispositivos, otro para estado de enlaces. La UI se actualiza en tiempo real sin polling.
Integraciones
Osnet ya tenia herramientas establecidas para distintas partes de la gestion de red antes de que existiera Nexxus. En lugar de pedirle a los operadores que las abandonaran de golpe, Nexxus se conecta a estas plataformas -- trayendo sus datos al contexto del mapa. La mayoria de estas integraciones estan planificadas para ser reemplazadas por funcionalidades propias de Nexxus a medida que la plataforma madura; por ahora, permiten trabajar desde una sola interfaz sin una migracion disruptiva.
- Cambium cnMaestro -- metricas de rendimiento de APs, stats de radio, conteo de clientes (proxy OAuth2 a traves de rutas API de Next.js con refresh automatico de tokens)
- UISP/UNMS -- telemetria de dispositivos Ubiquiti
- Unimus -- diffs de backups de configuracion y tracking de cambios
- Ubersmith -- integracion de tickets (badges de tickets se renderizan directamente sobre los nodos de dispositivos)
- LibreNMS -- datos extendidos de monitoreo
Detalles de UX del mapa
El mapa es mas que un visor de grafos simple. Algunas de las funcionalidades operativas:
- Nivel de detalle -- los nodos se renderizan diferente segun el zoom: solo un punto de estado en zoom bajo, icono + nombre en medio, detalle completo con IP, badges, integraciones en zoom alto
- Menus contextuales -- click derecho en nodos, aristas, etiquetas, selecciones, o canvas vacio abre diferentes menus con acciones relevantes
- Handles de aristas en 8 direcciones -- las aristas se conectan desde el lado optimo del nodo
- Offset de aristas paralelas -- multiples enlaces entre el mismo par de dispositivos se separan visualmente
- Waypoints de aristas -- puntos de ruteo personalizados para topologias complejas
- Visualizacion de trafico -- el color y grosor de las aristas cambian segun la utilizacion de ancho de banda
- Conexiones entre sub-mapas -- enlaces que conectan sub-mapas entre si a nivel del mapa padre
- Deshacer/rehacer -- historial completo de edicion en modo edicion
- Auto-layout -- algoritmos de layout en grilla, jerarquico y dirigido por fuerzas
- Busqueda -- paleta de comandos para encontrar dispositivos a traves de mapas
- Alertas y canales -- reglas de alerta configurables con canales de notificacion (Teams, etc.)
- Log de eventos -- historial de cambios de estado para auditoria y troubleshooting
- i18n -- soporte completo ingles/espanol via next-intl
El problema de rendimiento
Cuando me uni al proyecto, el mapa era lento. Caidas de frames durante pan y zoom, lag visible en eventos SSE, y la UI se ahogaba cuando los dispositivos superaban los 100.
El equipo habia comenzado a explorar un mapa V3 construido con Konva (HTML5 Canvas) para reemplazar React Flow, bajo la suposicion de que la libreria de renderizado era el cuello de botella.
Cada evento SSE -- incluso un solo dispositivo pasando de up a down -- disparaba re-renders en todo el arbol de componentes. Las stores de Zustand no eran suficientemente granulares. Las actualizaciones de estado se propagaban a traves de selectores compartidos, asi que nodos que no habian cambiado igual se re-renderizaban.
La solucion
El mapa V2 fue reestructurado con una separacion clara:
Componente Mapa
├── Capa ViewModel ── convierte store → nodos/aristas ReactFlow
│ ├── Estado de nodos ── actualizaciones aisladas por dispositivo
│ └── Estado de aristas ── actualizaciones aisladas por enlace
├── Capa de acciones ── todas las interacciones del usuario
│ ├── Layout ── deshacer/rehacer, auto-layout
│ ├── Persistencia ── guardar posiciones al backend
│ ├── Seleccion ── multi-select, alinear, distribuir
│ └── Edicion de aristas ── waypoints, direccion de handles
└── Secciones de UI
├── Header, barra de estado
├── Tooltips, menus contextuales
├── Modales (dispositivo, arista, etiqueta, ticket, clasificacion)
└── Sidebars
El store de datos usa Map<string, T> para busquedas O(1) de dispositivos. Los selectores se suscriben a IDs individuales de dispositivos, asi que una actualizacion SSE para un dispositivo solo re-renderiza ese nodo. La reescritura V3 con Konva se volvio innecesaria.
Stack
Frontend: Next.js 14, React 18, TypeScript, React Flow, Zustand, TanStack Query, Tiptap, Framer Motion, next-intl, next-auth
Backend: NestJS, MongoDB, polling SNMP/ICMP, streams SSE