Designing Data-Intensive Applications
Case 9

Presence and Permissions

See who is online, what they are editing, and whether they may change it — without leaking document content.

Collaboration tools combine real-time transport with authorization. A user without edit permission must not apply operations even if they bypass the UI.

In practice

Figma stores file permissions in Postgres; presence in Redis. Notion blocks embed share settings per page tree. All validate ops server-side against ACL snapshot.

typescript — Presence heartbeat
// Redis presence with TTL heartbeat
async function heartbeat(docId: string, userId: string, cursor: Cursor) {
  await redis.setex(`presence:${docId}:${userId}`, 30, JSON.stringify(cursor));
  await redis.publish(`doc:${docId}`, JSON.stringify({ type: "cursor", userId, cursor }));
}
Key Takeaways
  • Presence heartbeats in Redis with TTL; disconnect clears avatar.
  • Document ACLs: owner, editor, commenter, viewer enforced on every op.
  • Cursors and selections are ephemeral broadcast, not durable history.
  • Share links map tokens to roles with expiration.
  • Audit log records permission changes, not every keystroke.
  • Google Docs 'anonymous animals' are presence UX on top of WebSocket fan-out.
presenceACLRedispermissionsWebSocket