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
- Send heartbeats to maintain connection
- 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)
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 Scan
Docker Discovery
For implementation details, see the source code.