ADR-0207 : Navin Enterprise Telephony & Voice AI Agent, téléphonie d'entreprise et voix IA au-dessus du Control Plane
- Statut : proposé (2026-11-05)
- Décideurs : équipe plateforme Navin Enterprise AI, mission brief 01 (
agent_uses_cases/tel_note_meeting/01_NAVIN_AGENT_TELEPHONIQUE_COMPLET.md) - Références : ADR-0173 (couche moteur de téléphonie de la plateforme : Asterisk, Kamailio, LiveKit SIP, SeaweedFS,
multi-tenant et HA, lue seulement), ADR-0101 (politique de licences), ADR-0205 (Notes, modèle de produit à interface
propre), conventions du produit
navin-enterprise-telephony/CONVENTIONS.md, audit de l'existantdocs/fr/guides/telephony/existing-audit.md, scénarios réelsdocs/fr/guides/telephony/scenarios.md, paquet OPAeai.telephony_agent(deploy/policies/opa/telephony_agent.rego, teststelephony_agent_test.rego, clételephony_agentdedeploy/policies/opa/data.json), fragment OpenFGAdeploy/policies/openfga/products/telephony.fga(+telephony.tests.fga.yaml,telephony.tuples.yaml), gabarit Managernavin-telephony-agent(navin-manager/agent-templates/navin-telephony-agent.yaml,published: false,navin-enterprise-telephony/navin-integration/template/manifest.yaml).
Contexte
Le brief 01 demande un produit de téléphonie d'entreprise complet : PBX, SVI, centre de contact (ACD), softphone WebRTC, trunks SIP, supervision, campagnes légitimes, enregistrement et transcription avec consentement, fonctions IA après appel, agents vocaux IA multilingues, outils métier, intégrations CRM, FinOps, haute disponibilité, installation par le Navin Manager et publication du gabarit seulement après validation explicite du propriétaire. Il fixe les règles de topologie (section 3) : Asterisk est le PBX, Kamailio le bord SIP, LiveKit le cadre temps réel et voix IA (jamais un PBX), LiveKit SIP un service distinct jamais supposé présent ; Kamailio est facultatif sur un petit site.
La couche moteur existe déjà. L'ADR-0173 (accepté le 2026-11-03) a ajouté au catalogue du Manager les services
asterisk, kamailio, rtpengine, livekit-sip, livekit-egress, livekit-ingress et livekit-agents, et au
Control Plane le domaine eai.domains.telephony : ressources PBX par tenant, compilation et publication par AMI,
JSONRPC et Twirp avec versions et retour arrière, appels (CDR et CEL), enregistrements vers SeaweedFS, anti-fraude,
WebRTC éphémère, worker vocal navin-voice. L'audit du 3 novembre 2026 (existing-audit.md) a fixé ce qui est réutilisé
et le banc réel (Asterisk 20.6.0, Kamailio 5.7.4 et 6.0.8, RTPengine, SIPp 3.7.2) a exécuté 29 des 31 scénarios de
bout en bout, les deux autres (S30, S31 : voix IA par LiveKit SIP et transfert IA vers humain) étant bloqués faute de
binaire LiveKit SIP. Il manque la couche métier que le brief demande : gouvernance, centre de contact, IA vocale
gouvernée, campagnes, consentements, qualité, FinOps, interface et intégration Manager.
Décision
- Deux couches. La couche moteur reste celle de la plateforme (ADR-0173) et n'est jamais reconstruite. Le
produit
navin-enterprise-telephony/(id produittelephony, secteurcross_industry, servicenavin-telephony-agent) est construit au-dessus du Control Plane : il pilote les moteurs uniquement par l'API/v1/telephonyet le SDKenterprise_ai(client.telephony), jamais par AMI, ARI ou JSONRPC directement, et n'installe, ne compile ni ne configure aucun moteur. Frontend propre Next.js 16 + React 19 + MUI 9 (softphone, tableau mural en direct, éditeur de SVI), sansproduct.manifest.jsonà la racine, comme l'ADR-0205. - Jamais une seconde source de configuration PBX. La configuration des moteurs (trunks, numéros, extensions,
routage, SVI, files, agents vocaux, pools, versions publiées) vit dans le Control Plane. Le produit garde les
métadonnées de gouvernance, les versions soumises, les approbations et les références
cp_*_id, puis demande la prévisualisation, la publication et le retour arrière au Control Plane. Les événements LiveKit et Asterisk sont reçus par le Control Plane, pas par le produit. - Extensions de la couche moteur (section 2.1 des conventions, lot TEL-3).
POST /v1/telephony/originatedans le contexte sortant du tenant (toutes les règles sortantes s'appliquent, numéro présenté uniquement un numéro du tenant), contrôle de l'enregistrement d'un appel actif (MixMonitor), parcage et supervision (listen,whisper,bargepar ChanSpy), pause et état des files (QueuePause, QueueStatus), objettuningdes agents vocaux (moderealtimerefusé partelephony_realtime_unavailable), outils vocaux du registre de la plateforme avec réponsepending_approval, rôles de moindre privilègetelephony_supervisorettelephony_agentet portées de clé de service explicitestelephony:read,telephony:originate,telephony:record,telephony:supervise. - Identités (section 2.2). Chemin de requête : le BFF transmet le jeton d'accès de l'utilisateur (audience
navin-telephony-api), le produit résout le contexte parGET /v1/meet réutilise ce jeton vers le Control Plane pour la durée de la requête seulement (administration partenant_admin, libre-service des agents et superviseurs). Chemin de fond : le worker utilise la clé d'API de service de l'instance (référenceopenbao://ouenv://) après que le produit a autorisé la tâche à sa création ; la tâche garde l'identifiant du demandeur pour l'audit. Aucun jeton d'utilisateur n'est stocké dans Redis, une tâche, un journal ou la base. Le tenant ne vient jamais du navigateur ni des en-têtes SIP d'un appel entrant. - Modèle de données. PostgreSQL, schéma
telephony, tables de la section 23 du brief (call_sessions,campaigns, ...),tenant_idetproject_idsur chaque table, RLS activée et forcée partelephony.current_tenant()/telephony.current_project(), rôlesnavin_telephony_migrate(DDL),navin_telephony_app(NOBYPASSRLS) etnavin_telephony_worker; Alembic à révisions nommées (0001_foundation,0002_pbx_calls,0003_ai_campaigns_finops). Numéros en E.164 sous RLS avec une empreinte SHA-256 salée pour la déduplication, les désinscriptions et les exclusions, masqués partout ailleurs. Montants en décimales avec devise, tarifs fournis par le client avec leur source, jamais inventés. - Autorisation en deux couches via le Control Plane. OpenFGA pour les relations :
telephony_instance(rôlestenant_admin,telephony_admin,supervisor,cc_agent,quality_reviewer,campaign_manager,compliance_officer,auditor,viewer),telephony_queue(membres et superviseurs de file),telephony_call(instance, file,handler),telephony_campaign,telephony_voice_agent; le backend ne vérifie que les relationscan_*et écrit lui-même les tupleshandleretqueued'un appel. OPAeai.telephony_agentpour les décisions au-dessus des relations : publication PBX et changement de trunk (quatre yeux, route d'urgence jamais retirée ni interceptée), appel sortant (préfixes autorisés, international et surtaxé seulement avec la permission de l'instance, numéro présenté qui est un numéro du tenantcli_allowed, contact désinscrit ou exclu, heures calmes dans le fuseau du contact, budget en circuit ouvert), enregistrement (consentement exigé par le mode et la juridiction, pause pendant un paiement), supervision (modes autorisés par la gouvernance, chuchotement et intrusion pour les superviseurs seulement), transfert externe (préfixes autorisés), accès aux enregistrements (finalité), suppression (legal hold, rétention minimale), export de transcription, outils par niveau de risque et d'authentification, campagnes, SMS, écritures CRM, publication d'agent vocal (modèles autorisés pour la classification, budget, annonce IA), réglages protégés, rétention et levée de legal hold. Fail closed, raisons triées, obligations (audit, masquage, lien expirant, annonce d'enregistrement, champs minimaux, vérification avant annonce), chaque décision auditée. Les listes configurables sont sous la clételephony_agentdedata.json; les règles de consentement par juridiction (FR, BE, CH, GB, DE et une liste d'exemple d'États américains à consentement de toutes les parties) sont un exemple configurable à faire valider par le conseil du client, pas un avis juridique ; une juridiction inconnue exige le consentement explicite. - Voix IA en cascade par défaut. Le worker
navin-voice(LiveKit Agents) enchaîne STT, LLM et TTS par la passerelle de modèles de la plateforme (LiteLLM seulement), VAD Silero, gestion des interruptions et réglages de tour de parole ; le mode temps réel parole à parole est refusé (realtime_unavailablecôté produit,telephony_realtime_unavailablecôté Control Plane) tant que la passerelle ne porte pas une session temps réel gouvernée. Douze préréglages (accueil, standard IA, support, qualification, rendez-vous, rappel, suivi de commande, contrat après authentification, assistance sinistre, confirmation, FAQ interne, après-vente) avec annonce IA, opérations bancaires et d'assurance refusées sousauth_level = strong, transfert immédiat vers un humain sur urgence ou détresse. - Outils par la passerelle de la plateforme. Les 21 outils typés (section 8 des conventions) sont enregistrés
comme manifestes d'outils du registre de la plateforme ; le worker vocal les atteint par la passerelle d'outils
(portées, OPA, DLP, approbation, limitation, audit) et le produit les exécute avec ses propres contrôles
(relation,
telephony.tool.execute, idempotence, délai, coupe-circuit, validation après exécution). Un outil qui attend une approbation est annoncé « soumis », jamais « fait » ; aucune écriture CRM, réservation ou message n'est annoncé avant son exécution vérifiée. - Consentement, urgence et paiement. Mode de consentement
explicit,announceounot_recordedpar instance, annonce de la nature IA de l'agent lorsque la juridiction ou les réglages l'exigent, consentements et désinscriptions enregistrés avec leur preuve. Les numéros d'urgence sont routés par le plan d'appel compilé par le Control Plane, jamais par un modèle ; le produit refuse un nœud, une règle ou un agent qui les intercepterait. Le produit ne stocke aucune donnée de carte, met l'enregistrement en pause pendant une étape de paiement selonpci_pause_on_paymentet ne revendique aucune conformité PCI-DSS. - Licences. Asterisk (GPL-2.0 avec l'exception des protocoles de liaison), Kamailio (GPL-2.0 ou ultérieure) et
RTPengine (GPL-3.0 ou ultérieure) restent des programmes séparés, utilisés par leurs interfaces réseau (SIP, AMI,
ARI, JSONRPC) ; aucun code sous copyleft n'est lié au produit, qui n'est jamais annoncé « 100 % MIT/Apache ».
LiveKit et ses services sont sous Apache-2.0. Chaque nouvelle dépendance est vérifiée et listée dans
docs/LICENSES.md. - Observabilité. Grafana, Loki et Tempo, cités par le brief, sont sous AGPL et refusés par l'ADR-0101 : ils sont remplacés par Prometheus et Alertmanager (métriques et alertes), Alloy et OpenSearch (journaux), OpenTelemetry et Jaeger (traces) et Opik (traces des appels de modèles). Aucun numéro en clair, texte de transcription, lien d'enregistrement ou secret dans les journaux et les métriques.
- Intégration Manager. Cinq composants
runtime, migrate, backend, worker, web(stratégiededicated, servicenavin-telephony-agent), ports de développement web 3491, API 8493, santé du worker 8494, Redis 6411 ; les moteurs sont des services du catalogue requis par référence (asteriskrequis,kamailiofacultatif sur un petit site et requis en HA,rtpenginefacultatif,livekit,livekit-sip,livekit-agents,livekit-egressfacultatif). Le gabarit resteprepared/published: false; les artefacts sontpendingtant qu'ils ne sont pas construits.
Conséquences
- Le produit dépend des routes ajoutées par TEL-3 ; tant qu'elles ne sont pas fusionnées, les lots du produit les
appellent par
ControlPlane.requestavec les chemins exacts de la section 2.1 et les testent contre le faux Control Plane (tests/fakes/controlplane.py), et TEL-15 les vérifie contre le vrai Control Plane et les vrais moteurs. - Une seule source de vérité par donnée : le Control Plane pour la configuration des moteurs, les appels (CDR, CEL), les enregistrements et les médias ; PostgreSQL du produit pour la gouvernance, le centre de contact, les résultats IA, les campagnes, les consentements et la FinOps ; OpenFGA pour les relations.
- Toute nouvelle action sensible passe par une relation
can_*et une décisioneai.telephony_agent; une action absente de la politique est refusée (unknown_action). - Les règles de consentement, les préfixes, les juridictions de campagne et les heures calmes sont des valeurs par défaut configurables par tenant ; le client les valide avec son conseil avant la mise en production.
- Le gabarit reste absent du catalogue tant qu'aucune validation explicite n'est donnée.
Alternatives écartées
- Compiler le plan d'appel ou la configuration PJSIP dans le produit : écarté, ce serait une seconde source de configuration PBX en concurrence avec le compilateur du Control Plane (versions, retour arrière, isolation des contextes par tenant déjà testés).
- Parler directement à AMI, ARI, JSONRPC ou à l'API Twirp de LiveKit : écarté, les identifiants des moteurs resteraient dans le Control Plane et l'isolation, les quotas, l'anti-fraude et l'audit seraient contournés.
- LiveKit comme PBX ou à la place d'Asterisk : écarté (règle 2 de la section 3 du brief) ; Asterisk garde la messagerie vocale, le SVI classique, l'ACD, les extensions, l'enregistrement PBX et les transferts.
- Kamailio obligatoire : écarté pour un petit site (règle 5) ; il est requis en haute disponibilité ou fort volume.
- Mode temps réel parole à parole par défaut : écarté tant que la passerelle ne gouverne pas une session temps réel (DLP, budget, audit).
- Garder le jeton de l'utilisateur pour les tâches de fond : écarté, la clé de service à portées explicites est utilisée après l'autorisation de la tâche à sa création.
- Shell frontend partagé de l'ADR-0180 : écarté comme pour Notes, un softphone, un tableau mural en direct et un éditeur de SVI ne se décrivent pas par un manifeste de produit.
- Grafana, Loki, Tempo : écartés (AGPL, ADR-0101).
- CPaaS propriétaire en nuage pour la téléphonie ou la voix : écarté, le brief interdit d'imposer des services cloud propriétaires.
Éléments connus BLOQUÉS et NON DISPONIBLES
| Capacité | Statut | Raison |
|---|---|---|
| Voix IA par SIP via LiveKit SIP (S30) | BLOCKED | LiveKit SIP ne publie qu'une image de conteneur, pas de binaire, et aucun moteur de conteneur n'est disponible ici ; prouvé seulement contre un faux serveur Twirp |
| Transfert IA vers humain par SIP REFER (S31) | BLOCKED | même raison ; TransferSIPParticipant prouvé contre un faux serveur Twirp |
| Parole à parole temps réel | BLOCKED | tant que la passerelle de la plateforme ne porte pas une session temps réel gouvernée |
| Trunk réel d'un opérateur | NOT AVAILABLE | aucun trunk d'opérateur autorisé ici ; les tests utilisent SIPp et des opérateurs de bouclage, jamais un appel réel vers une personne |
| Saisie DTMF sécurisée par un prestataire spécialisé | NOT AVAILABLE | absente de cette livraison ; l'enregistrement est mis en pause pendant le paiement |
Liens
- Brief :
agent_uses_cases/tel_note_meeting/01_NAVIN_AGENT_TELEPHONIQUE_COMPLET.md(sections 1, 2, 3, 14, 18, 27, 30, 31) - Conventions :
navin-enterprise-telephony/CONVENTIONS.md - Couche moteur :
docs/architecture/ADRs/ADR-0173-plateforme-telephonie-asterisk-kamailio-livekit.md,docs/fr/guides/telephony/existing-audit.md,docs/fr/guides/telephony/scenarios.md - Politiques :
deploy/policies/openfga/products/telephony.fga,deploy/policies/opa/telephony_agent.rego - Gabarit :
navin-enterprise-telephony/navin-integration/template/manifest.yaml,navin-manager/agent-templates/navin-telephony-agent.yaml - Version anglaise :
docs/architecture/ADRs/en/ADR-0207-navin-enterprise-telephony-agent.md