feat: add 3CX telephony provider with Asterisk ARA provisioning

Registers a new `three_cx` provider that fronts a 3CX cloud PBX through
an intermediate Asterisk bridge. Save-time hook writes the matching
PJSIP endpoint/aor/auth/registration and dialplan rows to the Asterisk
Realtime Architecture Postgres (via `ASTERISK_ARA_DSN`), so a config
change in the Dograh UI is immediately picked up by Asterisk without a
`pjsip reload`. Strip prefix is honoured at the dialplan layer.

Inbound calls are matched back to a configuration by the dialled
extension (`account_id_credential_field="extension"`), allowing one
shared Asterisk to serve multiple Dograh orgs without collision.

Touches `providers/__init__.py` and `schemas/telephony_config.py` only
— per `providers/AGENTS.md`. Provider/transport/strategies are
duplicated from `ari/` rather than imported, in line with the
cross-provider-import prohibition. See `docs/providers/three_cx.md` for
the Asterisk ARA setup runbook.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
stefandsl 2026-05-26 13:07:50 +02:00
parent 3df5730076
commit 533a873ab7
13 changed files with 1916 additions and 0 deletions

View file

@ -28,6 +28,10 @@ from api.services.telephony.providers.telnyx.config import (
TelnyxConfigurationRequest,
TelnyxConfigurationResponse,
)
from api.services.telephony.providers.three_cx.config import (
ThreeCxConfigurationRequest,
ThreeCxConfigurationResponse,
)
from api.services.telephony.providers.twilio.config import (
TwilioConfigurationRequest,
TwilioConfigurationResponse,
@ -50,6 +54,7 @@ TelephonyConfigRequest = Annotated[
CloudonixConfigurationRequest,
PlivoConfigurationRequest,
TelnyxConfigurationRequest,
ThreeCxConfigurationRequest,
TwilioConfigurationRequest,
VobizConfigurationRequest,
VonageConfigurationRequest,
@ -73,6 +78,7 @@ class TelephonyConfigurationResponse(BaseModel):
cloudonix: Optional[CloudonixConfigurationResponse] = None
ari: Optional[ARIConfigurationResponse] = None
telnyx: Optional[TelnyxConfigurationResponse] = None
three_cx: Optional[ThreeCxConfigurationResponse] = None
# ---------------------------------------------------------------------------
@ -142,6 +148,8 @@ __all__ = [
"TelephonyConfigurationResponse",
"TelnyxConfigurationRequest",
"TelnyxConfigurationResponse",
"ThreeCxConfigurationRequest",
"ThreeCxConfigurationResponse",
"TwilioConfigurationRequest",
"TwilioConfigurationResponse",
"VobizConfigurationRequest",