Architecture
Clients, events and responsibility boundaries
Client → API → data
In the desktop app, QML calls C++ services. ApiClient makes REST requests, WebSocketClient maintains Phoenix Channels, and list models hold view state. The mobile client uses React Native screens, TypeScript services and the shared server contract.
Phoenix separates accounts, teams, chat, devices, calls and encryption into contexts. Controllers check authentication and access; PostgreSQL stores entities and membership. A WebSocket event announces a change rather than replacing server authorization.
Encrypted media delivery
The device encrypts data and uploads the attachment. A message carries an attachment identifier and information needed by an authorized client to decrypt it. Downloading bytes and having the correct key version are separate dependencies; an accessible link alone does not guarantee playback.
Website and media rooms
The public site uses the same Phoenix server, preserving authentication, invitation and download routes. LiveView updates relevant HTML over its connection. For a call, the API checks membership and issues a LiveKit token; audio and video then use LiveKit media transport.
Describes the current implementation. Mobile availability and limitations are documented separately.