Introduction
Google Docs-style co-editing — multiple users editing simultaneously without conflicts. Let Claude Code design Operational Transformation (OT) and CRDT patterns.
CLAUDE.md Rules
## Real-Time Collab Rules
- Simple text: OT (Operational Transformation)
- Distributed + offline: CRDT (use Yjs)
- Cursor sharing: Yjs Awareness
- Persistence: 10-second debounce to DB
- State cache: Redis binary (TTL: 1h)
Generated Implementation
// src/collab/documentRoom.ts
import * as Y from 'yjs';
import { Awareness } from 'y-protocols/awareness';
class DocumentRoom {
private ydoc: Y.Doc;
private awareness: Awareness;
private saveDebounce: NodeJS.Timeout | null = null;
constructor(private documentId: string, initialState?: Uint8Array) {
this.ydoc = new Y.Doc();
this.awareness = new Awareness(this.ydoc);
if (initialState) Y.applyUpdate(this.ydoc, initialState);
this.ydoc.on('update', (update: Uint8Array) => {
this.broadcastUpdate(update);
this.scheduleSave();
});
}
applyClientUpdate(update: Uint8Array): void {
Y.applyUpdate(this.ydoc, update); // CRDT auto-resolves conflicts
}
private scheduleSave(): void {
if (this.saveDebounce) clearTimeout(this.saveDebounce);
this.saveDebounce = setTimeout(() => this.persistDocument(), 10_000);
}
private async persistDocument(): Promise<void> {
const state = Y.encodeStateAsUpdate(this.ydoc);
await prisma.document.update({
where: { id: this.documentId },
data: { yjsState: Buffer.from(state), lastSavedAt: new Date() },
});
await redis.set(`doc:state:${this.documentId}`, Buffer.from(state), { EX: 3600 });
}
}
// Frontend: React + Yjs
export function CollaborativeEditor({ documentId }: { documentId: string }) {
useEffect(() => {
const ydoc = new Y.Doc();
const provider = new WebsocketProvider(WS_URL, documentId, ydoc);
const quill = new Quill(editorRef.current!, { theme: 'snow' });
const binding = new QuillBinding(ydoc.getText('content'), quill, provider.awareness);
provider.awareness.setLocalStateField('user', {
name: currentUser.name,
color: '#' + Math.floor(Math.random() * 0xFFFFFF).toString(16),
});
return () => { binding.destroy(); provider.destroy(); };
}, [documentId]);
}
Summary
- CRDT (Yjs): vector clock-based conflict auto-resolution
- Awareness: low-latency cursor/selection sharing
- 10-second debounce: avoid writing every keystroke to DB
- Redis binary cache: fast document state recovery on connection
Review with **Code Review Pack (¥980)* at prompt-works.jp*
myouga (@myougatheaxo) — Axolotl VTuber.
Top comments (0)