← All notes
WebNode.jsHomelab

How Chore Calendar syncs every phone in about a second

No accounts, no polling, no WebSockets. Each phone keeps one plain HTTP stream open, and the server pushes the chore list down it whenever anything changes.

Chore Calendar runs in a small Docker container on the home Wi-Fi. Every phone in the house opens the same page, and when someone checks off a chore, every other phone shows it within about a second. Nobody signs in.

I expected that to need WebSockets. It didn't: browsers already have a built-in way to hold a connection open and receive updates, called Server-Sent Events.

One stream per phone

When a phone loads the page, it opens a request the server never finishes. The server sends the current state right away, keeps the response in a set of listeners, and writes to every listener whenever something changes.

server.js
// each phone keeps this stream open for live updates
function stream(req, res) {
  res.writeHead(200, { "Content-Type": "text/event-stream" });
  res.write(`event: state\ndata: ${JSON.stringify(publicState())}\n\n`);
  listeners.add(res);
  req.on("close", () => listeners.delete(res));
}

Why not WebSockets?

The phones only need to hear about changes; checking something off goes up as a normal request. Server-Sent Events are one-way, run over plain HTTP, and reconnect on their own when a phone wakes up.

What carried over to StarChores

The native app syncs through iCloud instead, but the idea stayed the same: one source of truth, and every device listens.

The project this is about

Chore Calendar

The web app StarChores grew out of. A shared family chore calendar that runs on the home Wi-Fi.

shipped

Questions about this one?

No comments here, but I read every email.