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
| Table | What it stores |
|---|---|
topology_nodes | servers, VMs, switches, external SaaS — 30+ node types |
topology_edges | connections with protocol, port, encryption, criticality |
topology_zones | network zones / VLANs / subnets / cloud-VPCs |
topology_certificates | TLS certs associated with edges (CN, SAN, expiry) |
topology_node_configs | device-specific configs (markdown), version history |
topology_snapshots | point-in-time JSONB dumps for change tracking |
topology_changes | append-only audit log of who changed what when |
topology_detected_connections | intermediate 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:
- Creates a
topology_nodefor eachis_active=trueagent that doesn’t have one (label = name, type = server, managed_by_monsys = true) - Expands
agent_connections×inventory_ports(only non-loopback) to per-port detection rows intopology_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_edgewithis_documented = true.
This way the diagram grows organically: each new connection gets a “approve this”-moment for the operator.
API
| Method | Path |
|---|---|
GET /api/v1/topology/nodes | list nodes with agent_status + last_seen |
POST /api/v1/topology/nodes | new node (manual — SaaS, switch, …) |
PATCH /api/v1/topology/nodes/:id | update (whitelist on editable fields) |
DELETE /api/v1/topology/nodes/:id | delete |
GET /api/v1/topology/edges · POST · DELETE /:id | edges CRUD |
GET /api/v1/topology/zones · POST | zones CRUD |
GET /api/v1/topology/detected[?unmatched=1] | auto-detected list |
POST /api/v1/topology/detected/:id/promote | promote → edge |
GET /api/v1/topology/snapshots · POST | snapshots |
GET /api/v1/topology/export/mermaid | Mermaid graph download |
UI
Dashboard has 4 tabs:
- Diagram — React Flow canvas with drag-to-position (position is saved via
PATCH /nodes/:idon each drag-end), drag-to-connect between nodes (creates new edge), keyboardDeleteto 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
Related
- 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