Architecture
Technical overview of Scanopy's system design and components.
Technical overview of Scanopy's system design, components, and data flows.
Components
Server
Purpose: Central hub for data storage, API, and web UI serving
Responsibilities:
- Store network discovery data in PostgreSQL
- Serve REST API for daemons and UI
- Generate topology visualizations
- Manage user authentication and sessions
- Orchestrate scheduled discoveries
- Handle organization and user management
- Provide real-time updates via Server-Sent Events
Implementation:
- Language: Rust
- Framework: Axum (async web framework)
- Database: PostgreSQL 17 with sqlx
- Authentication: tower-sessions + OIDC (openidconnect crate)
- Frontend bundling: Integrated Svelte build in Docker image
Runs as: Docker container (recommended) or standalone binary
Daemon
Purpose: Distributed discovery agent that scans networks and reports findings
Responsibilities:
- Scan IPv4 addresses on configured subnets
- Detect open TCP ports
- Identify services via pattern matching
- Connect to Docker socket for container discovery
- Report host interfaces and capabilities
- Maintain server connection via periodic polling (each poll implicitly updates the daemon's health status)
- Execute scheduled discovery tasks
Implementation:
- Language: Rust
- Network scanning: Custom async TCP scanner with tokio
- Docker API: bollard crate for Docker socket communication
- Service detection: Pattern matching engine with 200+ definitions
- Configuration: JSON file + environment variables + CLI args
Runs as: Docker container (Linux only) or standalone binary (all platforms)
UI
Purpose: Web-based interface for viewing and managing network data
Responsibilities:
- Display interactive topology diagrams
- Provide CRUD interfaces for all entities
- Monitor discovery sessions in real-time
- Manage users and organizations
- Configure discovery schedules
- Export topology visualizations
Implementation:
- Framework: Svelte 5 + SvelteKit
- State management: Svelte stores with derived reactivity
- Visualization: @xyflow/svelte for topology rendering
- Forms: svelte-forms with custom validation
- Styling: Tailwind CSS
- Real-time: Native EventSource for SSE
Runs as: Static files served by the server (bundled in Docker image)
Data Flows
DaemonPoll Mode
DaemonPoll is the default mode. The daemon initiates all connections to the server, making it ideal for daemons behind NAT or firewalls.
Initialization (DaemonPoll)
Runtime Polling (DaemonPoll)
Discovery Flow (DaemonPoll)
- User triggers a scan via the UI or API — the server creates a discovery session in Pending state
- On its next polling cycle, the daemon receives the pending session as part of the
request-workresponse - The server transitions the session to Starting to prevent re-dispatch to other polls
- The daemon executes the discovery (network scan, Docker scan, or self-report depending on type)
- The daemon sends periodic progress updates to the server, including discovered entities
- The server processes entities immediately — deduplicating and persisting via upsert
- The server broadcasts progress to the UI via SSE
- The daemon sends a terminal phase (Completed or Failed) to end the session
ServerPoll Mode
ServerPoll mode is for DMZ deployments where the daemon cannot make outbound connections. The server initiates all connections to the daemon. Requires the daemon to be network-accessible from the server.
Initialization (ServerPoll)
Runtime Polling (ServerPoll)
Discovery Flow (ServerPoll)
Mode Comparison
| Aspect | DaemonPoll | ServerPoll |
|---|---|---|
| Connection direction | Daemon → Server | Server → Daemon |
| Setup | Daemon self-registers | Admin provisions in UI |
| Firewall requirements | Outbound only from daemon | Inbound to daemon (port 60073) |
| Best for | NAT/firewall environments | DMZ deployments |
| Entity handling | Immediate processing | Buffered with confirmation |
Discovery Pipeline
Network Scanning
Network scanning runs in three phases:
- ARP Discovery — The daemon sends ARP broadcasts across configured subnets to discover active hosts. This is the primary mechanism for finding devices on the local network, returning IP and MAC address pairs.
- Deep Scanning — Each discovered host is scanned in detail:
- TCP and UDP port scanning on configurable port lists
- DNS reverse lookup for hostname resolution
- SNMP queries for system information (if credentials are configured)
- Service detection by matching open ports against 235 service definitions
- Grace Period — A brief window after deep scanning completes to catch any late ARP responses. Newly discovered hosts receive a full deep scan before the session completes.
The UI displays real-time progress across all three phases via Server-Sent Events.
Docker Discovery
For implementation details, see the source code.