CloudFly Helpdesk
Concepts

What the system is made of

The three services behind the CloudFly Helpdesk console, the path a message takes through them, and why losing the realtime link is not losing a message.

View .mdOpen llms.txt

The console you open each morning is one of three services that run independently of one another. Knowing how the three divide the work is enough to read two familiar situations: a colleague's message appearing the instant they send it, and the status line reporting a lost connection.

This page describes the shape of the system at the level a console user needs, not at the level of whoever deploys it. Ports, environment variables and build steps live in the README.md file in the source tree.

Three services, three different jobs

ServiceWhat it doesWhat it does not do
Console (the web interface)Draws the queue, sends REST requests, holds one Socket.IO connectionNever reads the database directly
api-engineAnswers every REST request and is the only writer to the databaseDoes not push data into a browser on its own
ws-engineReplays events down to the browsers watching a given conversationNever writes to the database

The three share no code. They meet in exactly two places: Postgres, where everything is stored, and Redis, the internal line between the two engines.

The chat panel on a customer's website talks to api-engine as well, through its own widget door and with its own token. One body of data, two entrances, and each entrance has its own reach.

The path a message takes

  1. A customer or you sends a message. The request reaches api-engine over REST.
  2. api-engine writes the message into Postgres and waits for the write.
  3. Once the row is committed, it publishes a message.created event on the Redis chat_events channel.
  4. ws-engine, listening on that channel, turns it into a new_message event and pushes it into the room for that conversation.
  5. Every browser holding that conversation open appends the message, with no page reload.

That is why a message shows up almost instantly in a colleague's window: it waits for nobody to press refresh, it travels the Redis line down to the socket.

Write first, publish second

The order of steps 2 and 3 is a promise the system keeps, not an accident. The realtime event is born after the row is already in the database.

Two consequences worth remembering. First: a message you watch land in the thread has been stored, and a page reload still shows it. Second: the reverse cannot happen, because ws-engine holds no write access, so no message ever lives on the socket alone.

Losing the realtime link costs you live updates, not data. Messages are still written as usual and all of them are there when you reopen the conversation, because that read goes over REST rather than over the socket.

What you observe when a part stops

Part that stopsWhat you observe
ws-engine or RedisMessages still send and still store; open windows stop updating themselves and need a reload to show new traffic
api-engineNothing sends and no queue opens: every REST request goes through it
PostgresNo service can work at all, since this is where the data lives

The table gives you something an operations engineer can act on: "I can send but I cannot see other people's messages" and "I cannot send" point at two different broken areas.

On this page