Devlog: Building Synchronized Focus Rooms
Focus Rooms let a group of people share the same Pomodoro session in real time — one person hosts, everyone else's timer follows along automatically. Here's what building that actually involved.
The Goal
Solo Pomodoro timers are easy: a countdown running in the browser, no server needed. A shared timer is a different problem entirely — every participant's client needs to agree on exactly where the timer is, handle people joining mid-session, and recover cleanly if someone's connection drops. We wanted it to feel instant, not like a synced video call with lag.
Why Supabase Realtime
Since the rest of the app already runs on Supabase for auth and data, Realtime was the natural choice for the messaging layer — it uses Postgres under the hood and integrates directly with the existing user and room tables, avoiding a separate real-time infrastructure stack.
Private Channels and RLS
The trickiest part wasn't the timer logic — it was locking channels down correctly. Recent changes to how Supabase handles Realtime access mean that without explicit RLS policies on realtime.messages and the private: true flag set on the channel, connections can silently degrade. A channel would work fine in testing and then quietly transition to CLOSED in production with no obvious error — which meant early versions of Focus Rooms would desync without warning. Adding proper row-level security policies scoped to room membership fixed this and made the connection state reliable.
Host-Controlled Timer
Rather than have every client run its own countdown and try to stay in sync, one participant is designated host. The host's timer state — running, paused, remaining time — is what gets broadcast, and everyone else's UI just reflects it. This avoids drift between clients and keeps the logic simple: there's exactly one source of truth per room at any moment.
Handling Disconnects
Real-time connections drop — wifi hiccups, laptops sleep, tabs get backgrounded. The client needed auto-reconnect logic that re-subscribes to the room channel and re-syncs the current timer state without the user having to refresh or rejoin manually. Getting this right took a few iterations, since a naive reconnect would sometimes grab a stale timer snapshot instead of the current one.
Opt-in by Design
Synced timers aren't for everyone — some people just want to sit in a room with others without a shared countdown dictating their break schedule. So the synchronized timer is an opt-in toggle rather than a forced default, and rooms work fine with everyone running independent timers if the host doesn't enable it.
// TIP FROM CYBERDORO
Focus Rooms are live now — create one, invite a friend or study group, and optionally sync your Pomodoro sessions together in real time.
Try Cyberdoro →What's Next
The current version handles the core sync reliably, but there's more to build — room-wide achievement tracking, better reconnect UX, and support for larger group sizes are all on the roadmap as more people start using rooms daily.