Operations
Bootstrap
Section titled “Bootstrap”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.
rtc.svc -f .rtm.yamlRun flags cover the usual platform wiring: --sid, --datacenter, --cluster, --config_url, --config_apikey, --servicediscovery_url, --svccert, --svckey, --rootcacert, --jwt_public_key, --zerotrust, -p/--port.
Message bus
Section titled “Message bus”Real-time fan-out runs over NATS. Choose in-process (dev) or external (production):
# dev — embedded bus, single nodestreammanager: type: nats nats: inprocess: truewritetimeout: 10spingpong: enabled: true delay: 30s# production — shared external bus for a clusterstreammanager: type: nats nats: inprocess: false url: nats://nats.internal:4222writetimeout: 10spingpong: enabled: true delay: 30sConnection keepalive is a server-initiated ping on the pingpong.delay interval; writetimeout bounds each socket write.
Clustering
Section titled “Clustering”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 sharedurl, a message published on any instance reaches members connected to any other instance.
Content and notification wiring
Section titled “Content and notification wiring”Two sibling blocks are wired through tenant config:
| Tenant config key | Points at | Used for |
|---|---|---|
| content service URL | Content | File upload/download/list in chats |
| notify service URL | Notifications | The 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).
Client usage
Section titled “Client usage”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 messageconn.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.
Health
Section titled “Health”GET /health, GET /ready. Supervised deployments run it as service rtc with default state up.
Dependencies
Section titled “Dependencies”data (persistence), meta (schema delivery), config (tenant config), IAM (JWT identity), Vault (mTLS material), Content (files), Notifications (in-app), and NATS for the bus.