Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    WebRTC Calls & STUNner TURN
    News Module
    Member Blogs
    Public Profile Pages
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)

    Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    WebRTC Calls & STUNner TURN
    News Module
    Member Blogs
    Public Profile Pages
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)

    Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    WebRTC Calls & STUNner TURN
    News Module
    Member Blogs
    Public Profile Pages
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)
    1. Docs
    2. /Features
    3. /WebRTC Calls & STUNner TURN

    Updated Jul 10, 20264 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Docs
    2. /Features
    3. /WebRTC Calls & STUNner TURN

    Updated Jul 10, 20264 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Docs
    2. /Features
    3. /WebRTC Calls & STUNner TURN

    Updated Jul 10, 20264 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    WebRTC Calls & STUNner TURN

    Use Founder / Developer tabs in the docs sidebar to filter this page. Sidebar visibility is curated in lib/docs/audience-curated-docs.ts.

    Ring messenger can place 1:1 audio and video calls inside a direct conversation. Signaling rides the existing Tunnel channel conversation:{id}. Media uses the browser RTCPeerConnection. NAT traversal uses STUNner (STUN/TURN) on the cluster, with ICE servers delivered by an authenticated API — credentials never ship in NEXT_PUBLIC_*.

    LayerRole
    UIPhone / Video on conversation header → full-screen call overlay
    SignalingTunnel events call:invite … call:hangup on conversation:{id}
    ICEGET /api/webrtc/ice-servers (session required)
    TURNSTUNner Gateway TURN-UDP:3478 (e.g. turn.ring-platform.org)

    Related: Messaging · Tunnel Protocol · Real-time architecture

    Why this matters for your clone

    Members close deals faster when they can talk without leaving your Ring. Calls stay inside the same conversation that already carries opportunity, entity, or store context.

    Messaging

    Conversations, groups, and Tunnel live chat.

    Tunnel Protocol

    The realtime pipe calls reuse for invite / accept / hangup.

    Self-hosted deploy

    Where STUNner and env wiring live for k8s clones.

    Operator checklist (k3s / Ringdom cloud)

    1. STUNner control plane installed (stunner-system) and Gateway programmed in namespace stunner.

    Architecture

    Verified modules

    PathResponsibility
    app/api/webrtc/ice-servers/route.tsAuth’d ICE config from WEBRTC_* env
    features/chat/lib/fetch-ice-servers.tsClient fetch via apiClient
    features/chat/lib/call-types.tsSignal event / payload types
    hooks/use-webrtc-call.tsRTCPeerConnection + Tunnel publish/subscribe
    features/chat/components/call-overlay.tsxFull-screen controls (mute / camera / end)
    features/chat/components/conversation-header.tsxPhone / Video actions (direct only)

    Backlog

    Related documentation

    Messaging

    Conversations REST + Tunnel chat UI.

    Tunnel Protocol

    useTunnelChannel SSOT and transports.

    Messaging API

    Conversation and typing HTTP contracts.

    Real-time architecture

    TunnelProvider ownership and consumers.

    WebRTC Calls & STUNner TURN

    Use Founder / Developer tabs in the docs sidebar to filter this page. Sidebar visibility is curated in lib/docs/audience-curated-docs.ts.

    Ring messenger can place 1:1 audio and video calls inside a direct conversation. Signaling rides the existing Tunnel channel conversation:{id}. Media uses the browser RTCPeerConnection. NAT traversal uses STUNner (STUN/TURN) on the cluster, with ICE servers delivered by an authenticated API — credentials never ship in NEXT_PUBLIC_*.

    LayerRole
    UIPhone / Video on conversation header → full-screen call overlay
    SignalingTunnel events call:invite … call:hangup on conversation:{id}
    ICEGET /api/webrtc/ice-servers (session required)
    TURNSTUNner Gateway TURN-UDP:3478 (e.g. turn.ring-platform.org)

    Related: Messaging · Tunnel Protocol · Real-time architecture

    Why this matters for your clone

    Members close deals faster when they can talk without leaving your Ring. Calls stay inside the same conversation that already carries opportunity, entity, or store context.

    Messaging

    Conversations, groups, and Tunnel live chat.

    Tunnel Protocol

    The realtime pipe calls reuse for invite / accept / hangup.

    Self-hosted deploy

    Where STUNner and env wiring live for k8s clones.

    Operator checklist (k3s / Ringdom cloud)

    1. STUNner control plane installed (stunner-system) and Gateway programmed in namespace stunner.

    Architecture

    Verified modules

    PathResponsibility
    app/api/webrtc/ice-servers/route.tsAuth’d ICE config from WEBRTC_* env
    features/chat/lib/fetch-ice-servers.tsClient fetch via apiClient
    features/chat/lib/call-types.tsSignal event / payload types
    hooks/use-webrtc-call.tsRTCPeerConnection + Tunnel publish/subscribe
    features/chat/components/call-overlay.tsxFull-screen controls (mute / camera / end)
    features/chat/components/conversation-header.tsxPhone / Video actions (direct only)

    Backlog

    Related documentation

    Messaging

    Conversations REST + Tunnel chat UI.

    Tunnel Protocol

    useTunnelChannel SSOT and transports.

    Messaging API

    Conversation and typing HTTP contracts.

    Real-time architecture

    TunnelProvider ownership and consumers.

    WebRTC Calls & STUNner TURN

    Use Founder / Developer tabs in the docs sidebar to filter this page. Sidebar visibility is curated in lib/docs/audience-curated-docs.ts.

    Ring messenger can place 1:1 audio and video calls inside a direct conversation. Signaling rides the existing Tunnel channel conversation:{id}. Media uses the browser RTCPeerConnection. NAT traversal uses STUNner (STUN/TURN) on the cluster, with ICE servers delivered by an authenticated API — credentials never ship in NEXT_PUBLIC_*.

    LayerRole
    UIPhone / Video on conversation header → full-screen call overlay
    SignalingTunnel events call:invite … call:hangup on conversation:{id}
    ICEGET /api/webrtc/ice-servers (session required)
    TURNSTUNner Gateway TURN-UDP:3478 (e.g. turn.ring-platform.org)

    Related: Messaging · Tunnel Protocol · Real-time architecture

    Why this matters for your clone

    Members close deals faster when they can talk without leaving your Ring. Calls stay inside the same conversation that already carries opportunity, entity, or store context.

    Messaging

    Conversations, groups, and Tunnel live chat.

    Tunnel Protocol

    The realtime pipe calls reuse for invite / accept / hangup.

    Self-hosted deploy

    Where STUNner and env wiring live for k8s clones.

    Operator checklist (k3s / Ringdom cloud)

    1. STUNner control plane installed (stunner-system) and Gateway programmed in namespace stunner.

    Architecture

    Verified modules

    PathResponsibility
    app/api/webrtc/ice-servers/route.tsAuth’d ICE config from WEBRTC_* env
    features/chat/lib/fetch-ice-servers.tsClient fetch via apiClient
    features/chat/lib/call-types.tsSignal event / payload types
    hooks/use-webrtc-call.tsRTCPeerConnection + Tunnel publish/subscribe
    features/chat/components/call-overlay.tsxFull-screen controls (mute / camera / end)
    features/chat/components/conversation-header.tsxPhone / Video actions (direct only)

    Backlog

    Related documentation

    Messaging

    Conversations REST + Tunnel chat UI.

    Tunnel Protocol

    useTunnelChannel SSOT and transports.

    Messaging API

    Conversation and typing HTTP contracts.

    Real-time architecture

    TunnelProvider ownership and consumers.

  1. Public UDP 3478 reachable (host firewall / cloud firewall).
  2. DNS for TURN host (example production: turn.ring-platform.org A/AAAA → node LB IP).
  3. App ConfigMap / Secret wired: WEBRTC_STUN_URL, WEBRTC_TURN_URL, WEBRTC_TURN_USERNAME, WEBRTC_TURN_CREDENTIAL.
  4. Members use direct chats with Tunnel connected — Phone / Video appear in the header.
  5. Typical scenarios

    • Two matched professionals jump from text to a short voice call without switching apps.
    • A vendor clarifies an order face-to-face over video while the thread stays the SSOT.
    • Strict NATs still connect because TURN relays via STUNner (when credentials are configured).

    Calls require a live Tunnel session. If realtime is disconnected, the UI refuses to start a call — fix Tunnel first (Tunnel Protocol).

    features/messages/components/messages-shell.tsx
    Wires hook + overlay
    infrastructure/k3s-or/stunner/GatewayClass, GatewayConfig, Gateway manifests
    k8s/ENV-PROD-WIRING.mdProd env table for WEBRTC_*

    ICE API

    GET /api/webrtc/ice-servers — requires Auth.js session (401 if anonymous).

    Response shape (verified):

    STUN falls back to stun:stun.l.google.com:19302 when WEBRTC_STUN_URL is unset. TURN is added only when all of WEBRTC_TURN_URL, WEBRTC_TURN_USERNAME, and WEBRTC_TURN_CREDENTIAL are set.

    Env vars (verified)

    VariableWhereNotes
    WEBRTC_STUN_URLConfigMapOptional; Google STUN default in route
    WEBRTC_TURN_URLConfigMape.g. turn:turn.ring-platform.org:3478?transport=udp
    WEBRTC_TURN_USERNAMESecret ring-platform-org-secretsMatches STUNner auth Secret
    WEBRTC_TURN_CREDENTIALSecretNever NEXT_PUBLIC_*

    Examples: k8s/secrets.example.yaml, wiring notes: k8s/ENV-PROD-WIRING.md.
    env.local.template does not yet list these keys — use the k8s examples for local/prod parity.

    Tunnel signaling events

    Published on channel conversation:{conversationId} (same channel as typing):

    EventPurpose
    call:inviteOutgoing ring
    call:accept / call:rejectCallee decision
    call:offer / call:answerSDP
    call:iceICE candidates
    call:hangupTear down

    Subscribe with useTunnelChannel — do not raw-subscribe in effects (Tunnel Protocol).

    STUNner install order (k3s-or)

    1. 1

      Install operator (pulls Gateway API + STUNner CRDs):

    2. 2

      Create auth Secret (type=static, username, password) and apply infrastructure/k3s-or/stunner/gateway.yaml (GatewayClass + GatewayConfig + Gateway with protocol TURN-UDP).

    3. 3

      Wire app Secret/ConfigMap + ensure Deployment env refs for WEBRTC_TURN_USERNAME / WEBRTC_TURN_CREDENTIAL (k8s/deployment.yaml). Restart the app Deployment.

    4. 4

      Smoke: external STUN Binding to :3478; authenticated GET /api/webrtc/ice-servers; two browsers on the same direct conversation.

    Listener protocol must be TURN-UDP, not bare UDP. Realm in GatewayConfig is alphanumeric + hyphen (e.g. ring-platform-org). Empty UDPRoute backendRefs are invalid — peer TURN does not need a UDPRoute until an SFU (LiveKit) exists.

    Scope of the shipped MVP

    • In: 1:1 direct audio/video; overlay controls; ICE via server route; STUNner TURN foundation.
    • Out (see backlog): incoming call when the peer is not viewing that thread; group/multi-party; LiveKit SFU; call system messages; IPv6 TURN path hardening.

    Connect Platform’s RTVS / FastTransponder stack is not ported — only control UX patterns (mute / camera / end) were absorbed.

    json
    
    {
      "success": true,
      "data": {
        "iceServers": [
          { "urls": "stun:…" },
          { "urls": "turn:…", "username": "…", "credential": "…" }
        ],
        "turnConfigured": true
      }
    }
  6. Public UDP 3478 reachable (host firewall / cloud firewall).
  7. DNS for TURN host (example production: turn.ring-platform.org A/AAAA → node LB IP).
  8. App ConfigMap / Secret wired: WEBRTC_STUN_URL, WEBRTC_TURN_URL, WEBRTC_TURN_USERNAME, WEBRTC_TURN_CREDENTIAL.
  9. Members use direct chats with Tunnel connected — Phone / Video appear in the header.
  10. Typical scenarios

    • Two matched professionals jump from text to a short voice call without switching apps.
    • A vendor clarifies an order face-to-face over video while the thread stays the SSOT.
    • Strict NATs still connect because TURN relays via STUNner (when credentials are configured).

    Calls require a live Tunnel session. If realtime is disconnected, the UI refuses to start a call — fix Tunnel first (Tunnel Protocol).

    features/messages/components/messages-shell.tsx
    Wires hook + overlay
    infrastructure/k3s-or/stunner/GatewayClass, GatewayConfig, Gateway manifests
    k8s/ENV-PROD-WIRING.mdProd env table for WEBRTC_*

    ICE API

    GET /api/webrtc/ice-servers — requires Auth.js session (401 if anonymous).

    Response shape (verified):

    STUN falls back to stun:stun.l.google.com:19302 when WEBRTC_STUN_URL is unset. TURN is added only when all of WEBRTC_TURN_URL, WEBRTC_TURN_USERNAME, and WEBRTC_TURN_CREDENTIAL are set.

    Env vars (verified)

    VariableWhereNotes
    WEBRTC_STUN_URLConfigMapOptional; Google STUN default in route
    WEBRTC_TURN_URLConfigMape.g. turn:turn.ring-platform.org:3478?transport=udp
    WEBRTC_TURN_USERNAMESecret ring-platform-org-secretsMatches STUNner auth Secret
    WEBRTC_TURN_CREDENTIALSecretNever NEXT_PUBLIC_*

    Examples: k8s/secrets.example.yaml, wiring notes: k8s/ENV-PROD-WIRING.md.
    env.local.template does not yet list these keys — use the k8s examples for local/prod parity.

    Tunnel signaling events

    Published on channel conversation:{conversationId} (same channel as typing):

    EventPurpose
    call:inviteOutgoing ring
    call:accept / call:rejectCallee decision
    call:offer / call:answerSDP
    call:iceICE candidates
    call:hangupTear down

    Subscribe with useTunnelChannel — do not raw-subscribe in effects (Tunnel Protocol).

    STUNner install order (k3s-or)

    1. 1

      Install operator (pulls Gateway API + STUNner CRDs):

    2. 2

      Create auth Secret (type=static, username, password) and apply infrastructure/k3s-or/stunner/gateway.yaml (GatewayClass + GatewayConfig + Gateway with protocol TURN-UDP).

    3. 3

      Wire app Secret/ConfigMap + ensure Deployment env refs for WEBRTC_TURN_USERNAME / WEBRTC_TURN_CREDENTIAL (k8s/deployment.yaml). Restart the app Deployment.

    4. 4

      Smoke: external STUN Binding to :3478; authenticated GET /api/webrtc/ice-servers; two browsers on the same direct conversation.

    Listener protocol must be TURN-UDP, not bare UDP. Realm in GatewayConfig is alphanumeric + hyphen (e.g. ring-platform-org). Empty UDPRoute backendRefs are invalid — peer TURN does not need a UDPRoute until an SFU (LiveKit) exists.

    Scope of the shipped MVP

    • In: 1:1 direct audio/video; overlay controls; ICE via server route; STUNner TURN foundation.
    • Out (see backlog): incoming call when the peer is not viewing that thread; group/multi-party; LiveKit SFU; call system messages; IPv6 TURN path hardening.

    Connect Platform’s RTVS / FastTransponder stack is not ported — only control UX patterns (mute / camera / end) were absorbed.

    json
    
    {
      "success": true,
      "data": {
        "iceServers": [
          { "urls": "stun:…" },
          { "urls": "turn:…", "username": "…", "credential": "…" }
        ],
        "turnConfigured": true
      }
    }
  11. Public UDP 3478 reachable (host firewall / cloud firewall).
  12. DNS for TURN host (example production: turn.ring-platform.org A/AAAA → node LB IP).
  13. App ConfigMap / Secret wired: WEBRTC_STUN_URL, WEBRTC_TURN_URL, WEBRTC_TURN_USERNAME, WEBRTC_TURN_CREDENTIAL.
  14. Members use direct chats with Tunnel connected — Phone / Video appear in the header.
  15. Typical scenarios

    • Two matched professionals jump from text to a short voice call without switching apps.
    • A vendor clarifies an order face-to-face over video while the thread stays the SSOT.
    • Strict NATs still connect because TURN relays via STUNner (when credentials are configured).

    Calls require a live Tunnel session. If realtime is disconnected, the UI refuses to start a call — fix Tunnel first (Tunnel Protocol).

    features/messages/components/messages-shell.tsx
    Wires hook + overlay
    infrastructure/k3s-or/stunner/GatewayClass, GatewayConfig, Gateway manifests
    k8s/ENV-PROD-WIRING.mdProd env table for WEBRTC_*

    ICE API

    GET /api/webrtc/ice-servers — requires Auth.js session (401 if anonymous).

    Response shape (verified):

    STUN falls back to stun:stun.l.google.com:19302 when WEBRTC_STUN_URL is unset. TURN is added only when all of WEBRTC_TURN_URL, WEBRTC_TURN_USERNAME, and WEBRTC_TURN_CREDENTIAL are set.

    Env vars (verified)

    VariableWhereNotes
    WEBRTC_STUN_URLConfigMapOptional; Google STUN default in route
    WEBRTC_TURN_URLConfigMape.g. turn:turn.ring-platform.org:3478?transport=udp
    WEBRTC_TURN_USERNAMESecret ring-platform-org-secretsMatches STUNner auth Secret
    WEBRTC_TURN_CREDENTIALSecretNever NEXT_PUBLIC_*

    Examples: k8s/secrets.example.yaml, wiring notes: k8s/ENV-PROD-WIRING.md.
    env.local.template does not yet list these keys — use the k8s examples for local/prod parity.

    Tunnel signaling events

    Published on channel conversation:{conversationId} (same channel as typing):

    EventPurpose
    call:inviteOutgoing ring
    call:accept / call:rejectCallee decision
    call:offer / call:answerSDP
    call:iceICE candidates
    call:hangupTear down

    Subscribe with useTunnelChannel — do not raw-subscribe in effects (Tunnel Protocol).

    STUNner install order (k3s-or)

    1. 1

      Install operator (pulls Gateway API + STUNner CRDs):

    2. 2

      Create auth Secret (type=static, username, password) and apply infrastructure/k3s-or/stunner/gateway.yaml (GatewayClass + GatewayConfig + Gateway with protocol TURN-UDP).

    3. 3

      Wire app Secret/ConfigMap + ensure Deployment env refs for WEBRTC_TURN_USERNAME / WEBRTC_TURN_CREDENTIAL (k8s/deployment.yaml). Restart the app Deployment.

    4. 4

      Smoke: external STUN Binding to :3478; authenticated GET /api/webrtc/ice-servers; two browsers on the same direct conversation.

    Listener protocol must be TURN-UDP, not bare UDP. Realm in GatewayConfig is alphanumeric + hyphen (e.g. ring-platform-org). Empty UDPRoute backendRefs are invalid — peer TURN does not need a UDPRoute until an SFU (LiveKit) exists.

    Scope of the shipped MVP

    • In: 1:1 direct audio/video; overlay controls; ICE via server route; STUNner TURN foundation.
    • Out (see backlog): incoming call when the peer is not viewing that thread; group/multi-party; LiveKit SFU; call system messages; IPv6 TURN path hardening.

    Connect Platform’s RTVS / FastTransponder stack is not ported — only control UX patterns (mute / camera / end) were absorbed.

    json
    
    {
      "success": true,
      "data": {
        "iceServers": [
          { "urls": "stun:…" },
          { "urls": "turn:…", "username": "…", "credential": "…" }
        ],
        "turnConfigured": true
      }
    }