Skip to content
Back to skills

Realtime Patterns

ASecurity

Use when Real-time application mastery. WebSockets, Server-Sent Events (SSE), CRDTs for conflict-free collaboration, presence systems, optimistic updates, live cursors, multiplayer state sync, reconnection strategies, and real-time database patterns (Supabase Realtime, Firebase). Use when building chat, live collaboration, dashboards, or multiplayer features.

  • 5 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
ai-agentstypescriptbashreactnodenodejsexpressapidatabasebackendsecurity

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned September 27, 2026

npx -y skills add Harmitx7/tribunal-kit --skill realtime-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Realtime Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Realtime Patterns
[![Security: A β€” Skills Directory](https://www.skillsdirectory.com/api/skills/harmitx7-realtime-patterns-tribunal-kit/badge)](https://www.skillsdirectory.com/skills/harmitx7-realtime-patterns-tribunal-kit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: realtime-patterns
description: "Use when Real-time application mastery. WebSockets, Server-Sent Events (SSE), CRDTs for conflict-free collaboration, presence systems, optimistic updates, live cursors, multiplayer state sync, reconnection strategies, and real-time database patterns (Supabase Realtime, Firebase). Use when building chat, live collaboration, dashboards, or multiplayer features."
version: 5.0.0
last-updated: 2026-09-13
skills:
  - api-patterns
  - backend-security-expert
  - nodejs-best-practices
tools: Read, Grep, Glob, Bash, Edit, Write
scripts-binding:
  - .agent/scripts/lint_runner.js
  - .agent/scripts/verify_all.js
---

# Real-Time Patterns β€” Live Application Mastery

---

## πŸ› οΈ Technical Architecture & Reference Recipes

---

---

## Protocol Selection

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              When to Use What                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ SSE (Server-Sent Events)                                    β”‚
β”‚   βœ… Server β†’ Client only (one-way)                        β”‚
β”‚   βœ… AI token streaming                                    β”‚
β”‚   βœ… Live feeds, notifications, dashboards                  β”‚
β”‚   βœ… Auto-reconnection built in                             β”‚
β”‚   βœ… Works through HTTP proxies and CDNs                    β”‚
β”‚                                                              β”‚
β”‚ WebSocket                                                    β”‚
β”‚   βœ… Bidirectional (client ↔ server)                        β”‚
β”‚   βœ… Chat, gaming, collaborative editing                    β”‚
β”‚   βœ… High-frequency updates (< 100ms intervals)            β”‚
β”‚   ❌ Doesn't work through some proxies/CDNs                β”‚
β”‚   ❌ No auto-reconnection (must implement)                  β”‚
β”‚                                                              β”‚
β”‚ HTTP Polling                                                 β”‚
β”‚   βœ… Simplest implementation                                β”‚
β”‚   βœ… Works everywhere                                       β”‚
β”‚   ❌ Latency (poll interval)                                β”‚
β”‚   ❌ Wasted requests when nothing changed                   β”‚
β”‚                                                              β”‚
β”‚ WebTransport (emerging)                                      β”‚
β”‚   βœ… UDP-based, lowest latency                              β”‚
β”‚   βœ… Multiplayer gaming, video streaming                    β”‚
β”‚   ❌ Limited browser support (2024+)                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

❌ HALLUCINATION TRAP: Don't default to WebSocket for everything
   AI streaming β†’ SSE (one-way, auto-reconnect)
   Notifications β†’ SSE (one-way)
   Chat β†’ WebSocket (bidirectional)
   Live dashboard β†’ SSE (one-way)
   Collaborative editing β†’ WebSocket + CRDT
```

---

## Server-Sent Events (SSE)

```typescript
// Server (Node.js/Express)
app.get('/api/events', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  res.setHeader('X-Accel-Buffering', 'no'); // disable nginx buffering

  // Send initial connection event
  res.write(`data: ${JSON.stringify({ type: 'connected' })}\n\n`);

  // Heartbeat to keep connection alive
  const heartbeat = setInterval(() => {
    res.write(': heartbeat\n\n'); // comment line, ignored by client
  }, 15000);

  // Subscribe to events
  const handler = (event: AppEvent) => {
    res.write(`event: ${event.type}\n`);
    res.write(`data: ${JSON.stringify(event.data)}\n`);
    res.write(`id: ${event.id}\n\n`); // enables auto-resume
  };
  eventBus.subscribe(handler);

  // Cleanup on disconnect
  req.on('close', () => {
    clearInterval(heartbeat);
    eventBus.unsubscribe(handler);
  });
});

// Client
const eventSource = new EventSource('/api/events');

eventSource.addEventListener('notification', e => {
  const data = JSON.parse(e.data);
  showNotification(data);
});

// Auto-reconnection is built-in!
// The browser automatically reconnects with Last-Event-ID header
eventSource.onerror = () => {
  console.log('Connection lost β€” auto-reconnecting...');
};
```

---

## WebSocket

```typescript
// Server (ws library)
import { WebSocketServer, WebSocket } from 'ws';

const wss = new WebSocketServer({ server: httpServer, path: '/ws' });

// Connection management
const clients = new Map<string, WebSocket>();

wss.on('connection', (ws, req) => {
  const userId = authenticateFromHeaders(req);
  clients.set(userId, ws);

  ws.on('message', raw => {
    try {
      const message = JSON.parse(raw.toString());
      handleMessage(userId, message);
    } catch (e) {
      ws.send(JSON.stringify({ error: 'Invalid message format' }));
    }
  });

  ws.on('close', () => {
    clients.delete(userId);
    broadcastPresence();
  });

  ws.on('pong', () => {
    // Client is alive
  });
});

// Heartbeat β€” detect dead connections
const interval = setInterval(() => {
  wss.clients.forEach(ws => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.ping();
    }
  });
}, 30000);

// Broadcast to room
function broadcastToRoom(roomId: string, message: unknown, excludeUser?: string) {
  const roomMembers = getRoomMembers(roomId);
  for (const memberId of roomMembers) {
    if (memberId === excludeUser) continue;
    const ws = clients.get(memberId);
    if (ws?.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify(message));
    }
  }
}

// Client with reconnection
class ReconnectingWebSocket {
  private ws: WebSocket | null = null;
  private retryCount = 0;
  private maxRetries = 10;

  connect(url: string) {
    this.ws = new WebSocket(url);
    this.ws.onopen = () => {
      this.retryCount = 0;
    };
    this.ws.onclose = () => {
      this.reconnect(url);
    };
    this.ws.onerror = () => {
      this.ws?.close();
    };
  }

  private reconnect(url: string) {
    if (this.retryCount >= this.maxRetries) return;
    const delay = Math.min(1000 * 2 ** this.retryCount, 30000);
    this.retryCount++;
    setTimeout(() => this.connect(url), delay);
  }
}
```

---

## Optimistic Updates

```typescript
// React pattern: update UI immediately, reconcile on server response
async function toggleLike(postId: string) {
  // 1. Optimistic update (instant UI feedback)
  setLiked(prev => !prev);
  setLikeCount(prev => (liked ? prev - 1 : prev + 1));

  try {
    // 2. Server request
    await api.post(`/posts/${postId}/like`);
  } catch (error) {
    // 3. Rollback on failure
    setLiked(prev => !prev);
    setLikeCount(prev => (liked ? prev + 1 : prev - 1));
    toast.error('Failed to update. Please try again.');
  }
}

// With React Query / TanStack Query:
const likeMutation = useMutation({
  mutationFn: (postId: string) => api.post(`/posts/${postId}/like`),
  onMutate: async postId => {
    await queryClient.cancelQueries({ queryKey: ['post', postId] });
    const previous = queryClient.getQueryData(['post', postId]);
    queryClient.setQueryData(['post', postId], (old: Post) => ({
      ...old,
      liked: !old.liked,
      likeCount: old.liked ? old.likeCount - 1 : old.likeCount + 1,
    }));
    return { previous };
  },
  onError: (err, postId, context) => {
    queryClient.setQueryData(['post', postId], context?.previous);
  },
  onSettled: (data, err, postId) => {
    queryClient.invalidateQueries({ queryKey: ['post', postId] });
  },
});
```

---

## Presence System

```typescript
// Track who's online, typing, viewing

interface PresenceState {
  userId: string;
  status: 'online' | 'away' | 'offline';
  cursor?: { x: number; y: number };
  lastSeen: number;
}

// Server-side presence manager
class PresenceManager {
  private presence = new Map<string, PresenceState>();
  private readonly TIMEOUT_MS = 30_000;

  update(userId: string, state: Partial<PresenceState>) {
    this.presence.set(userId, {
      ...this.presence.get(userId),
      userId,
      status: 'online',
      lastSeen: Date.now(),
      ...state,
    } as PresenceState);
  }

  getActive(): PresenceState[] {
    const now = Date.now();
    return [...this.presence.values()].filter(p => now - p.lastSeen < this.TIMEOUT_MS);
  }

  remove(userId: string) {
    this.presence.delete(userId);
  }
}
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…