Reconnect by reading current state
Maya's laptop sleeps while another member completes three tasks. When the laptop wakes, Socket.IO reconnects. Establishing a new connection does not prove that Maya received the changes made during the gap.
Taskboard's client model treats reconnection as a reason to fetch current project state over HTTP. The task list becomes correct because it reads Postgres-backed data, not because it assumes the event stream was complete.
Notifications can be repeated
A worker emits a task notification and then crashes before completing the durable job. After the lease expires, another attempt emits the same notification. A frontend that blindly appends on every event can show duplicate items.
The safer behavior is to invalidate or replace data by its stable task ID. If an event includes a task version, the client can also avoid overwriting newer local state with an older observed version.
socket.on("connect", () => refetchProjectTasks());
socket.on("task.changed", () => invalidateProjectTasks());
These calls describe a simplified client pattern. A reconnect also needs to send an authorized subscribe message for the current project because the new socket starts without its former subscription. Taskboard's small reference client illustrates API use; it is not intended as a complete SaaS frontend. The server provides the data and notifications needed for this recovery pattern.
A refetch can overlap an event
Maya begins a refetch, then another change commits. The fetch might represent state before that change. A later notification should trigger another invalidation, and the query layer must handle overlapping requests without replacing a newer result with an older one.
This is a familiar frontend race, now connected to backend delivery semantics. Request cancellation, version checks, and library query invalidation behavior help the client resolve it.
For much larger event histories, an application can assign durable event IDs and let clients request events after a saved cursor. That requires retention, pagination, ordering, and authorization rules. Taskboard's activity records provide history, but they do not automatically establish a resumable socket protocol.
A realtime status label should also be honest. "Connected" describes transport state. "Up to date" requires successful synchronization, and even then describes a point in time rather than a permanent guarantee.
Inspect notifications in Read api/src/realtime.ts and authoritative task reads in Read api/src/tasks.ts.
After reconnection, read current state. Handle repeated events by stable identity, and never treat a temporary connection as a complete durable history.
Should the client increment a completed-task counter for every notification?
Not without deduplication and ordering rules. A repeated event could increment twice. Refetching the count or recomputing it from authoritative tasks avoids that assumption.