Skip to content

Topology & Architecture

/topology displays a graph of nodes (servers, network equipment, external services) and edges (connections between them). Two sources populate this graph:

  • Auto-detected — Monsys-agents report their own IPs and listening ports; the hub deduces potential connections between agents in the same subnet
  • Manual — external services that do not run an agent (SaaS, ISP-uplink, CDN, external cloud-provider) are added manually via the UI or API

Data Model

TableWhat it stores
topology_nodesservers, VMs, switches, external SaaS — 30+ node types
topology_edgesconnections with protocol, port, encryption, criticality
topology_zonesnetwork zones / VLANs / subnets / cloud-VPCs
topology_certificatesTLS certs associated with edges (CN, SAN, expiry)
topology_node_configsdevice-specific configs (markdown), version history
topology_snapshotspoint-in-time JSONB dumps for change tracking
topology_changesappend-only audit log of who changed what when
topology_detected_connectionsintermediate table: auto-detected but not yet documented

Tenant isolation via Postgres RLS — each row has a tenant_id and the policy matched that against current_setting('app.current_tenant') on each query.

Auto-Bootstrap

TopologyMatcherWorker runs every 10 minutes and:

  1. Creates a topology_node for each is_active=true agent that doesn’t have one (label = name, type = server, managed_by_monsys = true)
  2. Expands agent_connections × inventory_ports (only non-loopback) to per-port detection rows in topology_detected_connections

A new Monsys-agent thus appears automatically in the diagram as soon as it pushes inventory (~5 minutes after install).

Detected vs. Documented

Auto-detected connections have is_documented = false. In the Detected tab of the UI (or GET /api/v1/topology/detected?unmatched=1) you see per connection:

  • src agent + dest IP + port + protocol
  • First/last time seen
  • Button Promote → to choose a target_node. That creates an actual topology_edge with is_documented = true.

This way the diagram grows organically: each new connection gets a “approve this”-moment for the operator.

API

MethodPath
GET /api/v1/topology/nodeslist nodes with agent_status + last_seen
POST /api/v1/topology/nodesnew node (manual — SaaS, switch, …)
PATCH /api/v1/topology/nodes/:idupdate (whitelist on editable fields)
DELETE /api/v1/topology/nodes/:iddelete
GET /api/v1/topology/edges · POST · DELETE /:idedges CRUD
GET /api/v1/topology/zones · POSTzones CRUD
GET /api/v1/topology/detected[?unmatched=1]auto-detected list
POST /api/v1/topology/detected/:id/promotepromote → edge
GET /api/v1/topology/snapshots · POSTsnapshots
GET /api/v1/topology/export/mermaidMermaid graph download

UI

Dashboard has 4 tabs:

  • Diagram — React Flow canvas with drag-to-position (position is saved via PATCH /nodes/:id on each drag-end), drag-to-connect between nodes (creates new edge), keyboard Delete to delete edges
  • Detected — promote-flow (see above)
  • Snapshots — point-in-time snapshots with node/edge counts
  • Nodes & edges — read+delete table-view

Edge styling:

  • green solid = encrypted and documented
  • red solid + animated = critical
  • amber dashed = auto-detected but not documented
  • Diagrams — uses this topology as input for PNG/SVG/PDF export with layout algorithms
  • Blast radius — uses the same edges for 3-hop reachability per host