Skip to content
Talk to our solutions team

Operations

Build produces rtc.svc; run it with -f .rtm.yaml. Ports and TLS are chassis-managed. The entity schema (chats, threads, messages, seen-state, bots) is embedded and applied per tenant through the data layer.

Terminal window
rtc.svc -f .rtm.yaml

Run flags cover the usual platform wiring: --sid, --datacenter, --cluster, --config_url, --config_apikey, --servicediscovery_url, --svccert, --svckey, --rootcacert, --jwt_public_key, --zerotrust, -p/--port.

Real-time fan-out runs over NATS. Choose in-process (dev) or external (production):

# dev — embedded bus, single node
streammanager:
type: nats
nats:
inprocess: true
writetimeout: 10s
pingpong:
enabled: true
delay: 30s
# production — shared external bus for a cluster
streammanager:
type: nats
nats:
inprocess: false
url: nats://nats.internal:4222
writetimeout: 10s
pingpong:
enabled: true
delay: 30s

Connection keepalive is a server-initiated ping on the pingpong.delay interval; writetimeout bounds each socket write.

Client connections are held per instance, so horizontal scale requires the external bus:

  • With inprocess: true, each replica has its own embedded bus and replicas cannot see each other — single node only.
  • With inprocess: false + a shared url, a message published on any instance reaches members connected to any other instance.

Two sibling blocks are wired through tenant config:

Tenant config keyPoints atUsed for
content service URLContentFile upload/download/list in chats
notify service URLNotificationsThe in-app notification template for mentions/reactions

Asset stores and media folders for chat files are resolved from the tenant config (chat.assets, chat.mediafolder, and the default.* fallbacks).

A browser client connects, then handles frames by status and action:

const conn = new WebSocket(`wss://${host}/chat/join?token=${jwt}`)
conn.addEventListener("open", () => {
conn.send(JSON.stringify({ action: "listchats", body: {} }))
})
conn.addEventListener("message", ev => {
const m = JSON.parse(ev.data)
if (m.status !== "success") return
if (m.action === "listchats") renderChats(m.response.data.rtmchat)
if (m.action === "getmessages") setMessages(m.response.data.rtmchatthreadmessage)
if (m.action === "publishmessage") appendMessage(m.response.data.rtmchatthreadmessage)
})
// send a message
conn.send(JSON.stringify({
action: "publishmessage",
body: { chatid, threadid, message: "hello", blocks: { data: [] }, clientidentifier: crypto.randomUUID() }
}))

Reconnect on close (except a normal 1001 going-away) after a short backoff.

GET /health, GET /ready. Supervised deployments run it as service rtc with default state up.

data (persistence), meta (schema delivery), config (tenant config), IAM (JWT identity), Vault (mTLS material), Content (files), Notifications (in-app), and NATS for the bus.