Architecture Overview
Purpose
Section titled “Purpose”Give a high-level map of the Get2Dial components and how traffic and data flow between them.
Overview
Section titled “Overview”Get2Dial separates a shared control plane from per-tenant edge nodes. The control plane owns state and orchestration; the edge owns real-time media and carrier connectivity. They communicate over NATS (call events, originate requests) and node-authenticated HTTP (registration, config reads, media/recording sync).
flowchart LR
subgraph Browser
A[Tenant App]
M[Admin Console]
SP[Agent softphone - WebRTC]
end
subgraph Control["Control plane (shared)"]
C[Control API :8080 - Go]
P[Dialer pacer]
DB[(PostgreSQL / TimescaleDB)]
R[(Redis)]
N{{NATS}}
S[(MinIO)]
end
subgraph Edge["Tenant edge (one per tenant)"]
O[OpenSIPS :7443 WSS / :5060]
RE[rtpengine]
F[FreeSWITCH :5066]
CE[Call engine]
NA[Node agent]
end
Carrier[(SIP carrier)]
A --> C
M --> C
SP -. WSS .-> O
C --- DB
C --- R
C --- S
P --- C
C <--> N
N <--> CE
CE -. ESL .-> F
NA -->|register / heartbeat / sync| C
O <--> RE
RE <--> F
O <--> F
F <--> Carrier
The real media chain on the edge is Browser (WSS) → OpenSIPS → rtpengine →
FreeSWITCH → carrier. OpenSIPS is the only SIP entry point; it authenticates,
anchors media in rtpengine, then relays signaling to FreeSWITCH (which listens
on 5066 to avoid colliding with OpenSIPS on 5060).
Configuration
Section titled “Configuration”Each layer is configured independently:
- Control plane — see Infrastructure and the control-plane env vars.
- Edge — see Edge and Edge Registration.
Examples
Section titled “Examples”A bridged outbound call crosses every layer: the pacer (control plane)
publishes an originate to t.<tenant>.node.<NODE_ID>.call.originate, the edge
call engine drives FreeSWITCH to dial the carrier, runs AMD, and on a human
answer bridges the agent leg back through the local OpenSIPS so the WebRTC
softphone rings.
- The control plane is multi-tenant; each edge is single-tenant.
- Tenant identity is stamped on the edge (
g2d_tenant_id, sourced from a SIP header or the node’sNODE_TENANT_ID) and flows back with CDRs — it is never pinned on the shared control plane. - Defense-in-depth tenant isolation: Postgres row-level security keyed on
app.tenant_id, plus per-tenant Redis ACLs and NATS subject permissions scoped tot.<tenant>.>.