Lesson 7 of 8 · 58 min
FE system design II — collab editors, feeds, autocomplete
Full RADIO frontend system design for collaborative editors (CRDT/OT, undo, reconnect), infinite feeds (cursors, CLS-safe injection), and autocomplete (debounce, abort, stale races, ARIA combobox).
Lesson 7 · FE system design II
Collab editors, feeds, autocomplete
Harder prompts, same discipline
Prompt C — Collaborative editor (Docs/Notion altitude)
Collab — full RADIO skeleton
1R — REQUIREMENTS & NFRs2 Concurrent multiplayer edits without silent loss; presence cursors;3 offline buffer + reconnect; undo of *my* ops only; large-doc virtualization;4 authz per doc; a11y: announce collab status sparingly (not every remote keystroke)56A — ARCHITECTURE7 EditorView (ProseMirror / CodeMirror / Lexical)8 ↕ binding9 SharedDoc (Y.Doc CRDT / OT doc)10 ↕11 SyncProvider (WebSocket) — auth, state vector exchange12 ↕13 Awareness channel — cursors/names (ephemeral, throttled)14 Persistence: snapshot every N ops + op log; load = snapshot + ops since15 Local UI: find bar, selection chrome; URL: doc id + heading hash1617D — DATA MODEL18 Y.Doc / OT document structure (library-owned)19 AwarenessState { userId, cursor, color, name }20 Snapshot { docId, version, bytes }2122I — INTERFACES23 WS: sync updates (binary Yjs update) + awareness messages24 HTTP: GET snapshot; POST auth token for room2526O — OBSERVABILITY & RISKS27 Metrics: sync lag, reconnect rate, doc size, undo errors28 Risks: whole-doc LWW destroy; offline fork UX; contenteditable a11y hellCRDT vs OT (interview altitude)
- 01OT (Operational Transform) — transforms ops against concurrent ops; often needs a central authority ordering. ShareDB is a classic reference.
- 02CRDT — commutative structures; peer merge friendlier; libraries (Yjs, Automerge) common in product. Figma’s multiplayer blog is a great narrative source.
- 03FE job — bind editor view to shared doc model; presence channel; undo stacks that respect remote ops; reconnect resync.
Collab — reconnect & offline
- 01On disconnect: read-only or buffer local ops in IndexedDB.
- 02On reconnect: exchange state vectors; receive missing ops; resolve with CRDT/OT rules.
- 03Show presence: “reconnecting…”; do not silently drop keystrokes.
- 04Large docs: lazy-load block bodies; virtualize long pages.
- 05A11y: contenteditable is hard — prefer well-tested engines; announce collab status sparingly.
Common mistake
“We will merge with timestamps — last write wins for the whole document.”
Prompt D — Infinite feed (Twitter/Instagram-like)
Feed — full RADIO skeleton
1R — REQUIREMENTS & NFRs2 Infinite scroll home feed; cursor pages; pull-to-refresh; composer;3 mixed media; CLS ≤ 0.1; virtualize; “N new posts” without jump; media LCP careful45A — ARCHITECTURE6 GET /feed?cursor=&limit=20 → { items[], nextCursor }7 Prefer cursor over page=2 (stable under inserts)8 Client: infinite query cache + virtualizer + IO prefetch near end9 Optimistic prepend on create with reserved space OR “new posts” banner10 Images: width/height, blur placeholder, priority only first screen11 State: URL filters optional; server feed pages; local composer draft;12 global toast; badge counts derived from cache when possible1314D — DATA MODEL15 FeedItem { id, type, author, body, media[], createdAt, cursorKey }16 FeedPage { items, nextCursor }1718I — INTERFACES19 GET /feed?cursor&limit20 POST /posts → item (optimistic clientId → server id)21 Optional SSE: feed.invalidate or new-post notifications2223O — OBSERVABILITY & RISKS24 Metrics: CLS on feed, time-to-first-card, duplicate id rate, error retries25 Risks: offset pagination drift; auto-insert jump; missing media dimensionsFeed — CLS-safe injection & anchoring
Key idea
Prompt E — Autocomplete / command palette
Autocomplete — full RADIO skeleton
1R — REQUIREMENTS & NFRs2 Suggest within ~100–200ms perceived; debounce 150–300ms; keyboard full;3 APG combobox; empty/error/min-chars; no stale overwrite; XSS-safe render45A — ARCHITECTURE6 input → debounce → AbortController fetch → rank → listbox7 Optional: client LRU prefix cache; cmd-K local fuzzy for commands8 State: local query + activeIndex; URL q optional for shareable search pages910D — DATA MODEL11 Suggestion { id, label, meta? }12 RequestSeq number for last-write-wins1314I — INTERFACES15 GET /suggest?q= → Suggestion[]1617O — OBSERVABILITY & RISKS18 Metrics: suggest latency, abort rate, stale-drop count, select rate19 Risks: race (slow “rea” overwrites “react”); missing a11y; HTML injection1// Stale-response race — the #1 autocomplete bug2let seq = 03let abortPrev: AbortController | null = null4async function onQuery(q: string) {5 const my = ++seq6 abortPrev?.abort()7 const ctrl = new AbortController()8 abortPrev = ctrl9 const res = await search(q, { signal: ctrl.signal })10 if (my !== seq) return // stale11 setItems(res)12}13// Debounce 150–300ms for typeahead; less for cmd-K local list14// Keyboard: arrow activeDescendant, Enter select, Escape close- 01Debounce vs throttle — debounce for query; throttle for scroll handlers.
- 02AbortController — cancel superseded fetches.
- 03Last-write-wins by sequence number — even if abort fails.
- 04Empty/error/min chars — UX states interviewers watch for.
- 05Security — escape rendering; careful with HTML suggestions.
- 06A11y — role=combobox, aria-expanded, listbox options, aria-activedescendant.
Common mistake
“Debounce alone prevents race conditions.”
Cross-prompt comparison table
1Concern Chat Feed Collab Autocomplete2Transport WS+HTTP HTTP(+WS) WS sync HTTP3Hard problem scroll anchor CLS inject merge/undo stale race4Virtualize yes yes long docs listbox5URL state channel filters doc id q optional6A11y focus live msgs new posts caret/SR comboboxPractice assignment shape
- 01Photo viewer deep dives: image pyramid / tiles, memory under rapid zoom, gesture vs button affordances.
- 02PDP deep dives: LCP hero, variant a11y, multi-tab cart sync, revalidate on price.
- 03Inbox deep dives: URL selection, optimistic read, push + badge derivation, keyboard list nav.
System Design — Design Google Docs / real-time editorSystem design talkCollab RADIO — deep dive scripts
Feed RADIO — deep dive scripts
Autocomplete RADIO — deep dive scripts
1// Week-1 build slices2// Collab: read-only shared doc via Yjs demo provider → then write + awareness3// Feed: cursor list + virtualize → then composer optimistic → then new-post banner4// Autocomplete: local list filter → then remote debounce/abort → then APG keyboard56// Self-score after mock (1–5 each):7// requirements, architecture, NFRs, a11y, perf, failure modesEnd-to-end collab / feed / autocomplete mock scripts
- 01Collab senior signals — CRDT/OT choice with tradeoff; awareness separate; undo origins; reconnect.
- 02Feed senior signals — cursor not offset; virtualize; CLS injection strategy; media dimensions.
- 03Autocomplete senior signals — debounce ≠ race-safe; abort+seq; combobox APG; security of HTML.
- 04Shared — state buckets map; NFRs unprompted; week-1 slice; risks last five minutes.
1// Feed insert without jump (banner path)2// 1. SSE/push: newPostsCount++3// 2. Show button: `${n} new posts` (aria-live polite once)4// 3. onClick: fetch head page; prepend; scrollTo(0) intentionally5// Auto-insert path only if product requires; then scrollTop += insertedHeightCheckpoint
Why is last-write-wins on an entire collab document a bad merge strategy?
Checkpoint
Infinite feed: user is reading mid-list; you auto-insert 5 new posts at the top without adjusting scroll. What fails?
Checkpoint
Autocomplete: slow response for “rea” arrives after fast response for “react”. Risk?
Checkpoint
Best pagination style for a social feed with frequent inserts?
Checkpoint
What is the FE's job in a Yjs-style collab stack?
Can you deep-dive collab merge, feed CLS injection, and autocomplete races in one mock?
Takeaways
- Collab: CRDT/OT choice, presence, undo-of-local-ops, reconnect resync — full RADIO.
- Feed: cursor pages, virtualization, CLS-safe injection, media dimensions.
- Autocomplete: debounce + AbortController + sequence ignore + combobox a11y.
- Whole-doc LWW and offset pagination are common senior traps.
- Practice a third prompt end-to-end with the L1 rubric.
Next: AI-in-the-UI, machine-coding patterns, and the capstone mock.
Sources
Free to read · better with Enzo
Learn it with Enzo
Save your progress, answer the checkpoints, and let Enzo quiz you on what you just read.