C.W.K.
Stream
Lesson 02 of 04 · published

Server-Owned CRUD With an Offline Cache

~12 min · crud, cache, sync, ownership

Level 0Dead Zone
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"The server owns the macro list; the device keeps a cache. One is the truth, the other is a fast, offline-friendly copy that knows it's a copy."

Where Macros Live

Macros are the same ownership story as conversations, one scale smaller. The canonical macro set is server-owned: create, read, update, and delete all resolve against the backend, so your macros follow you across devices and there's one authoritative list. But you also want them available instantly and offline — you shouldn't lose access to your saved prompts just because the signal dropped. So the device keeps an offline cache of the macro list, plus a pending-sync marker for edits made while offline. The cache is explicitly a copy that knows it's a copy: fast and available, but never the source of truth.

The Cache Knows Its Place

This split works only because the roles are unambiguous. The server list is authoritative; the device cache is a convenience layer that defers to it:

  • Read: render from the cache instantly (offline-friendly), refresh from the server when reachable.
  • Write offline: apply to the cache, mark it pending-sync, and reconcile with the server on reconnect.
  • Conflict: the server list wins as the authority; the cache re-derives from it. The cache never overrides the truth just because it's local.

Notice the echo of the whole quest: capture/act locally for responsiveness, but let the canonical store own the truth. Macros are conversations' pattern in miniature — a local layer for speed and offline, a server layer for authority.

First Sync Adopts, Doesn't Clobber

One graceful detail worth stealing: when a server-side macro store meets a device that already has locally-created macros, the first sync should adopt the device's existing list, not wipe it. A new backend store arriving shouldn't punish the user for having started offline. Adoption-on-first-sync is a small kindness that reflects the same respect for the user's input running through the whole client: their work — even macros made before the server knew about them — is preserved, folded in, never discarded. The cache is a copy, but the user's intent inside it is still treated as precious.

Code

Cache for speed/offline; server for authority·typescript
// Read: instant from cache, refreshed from the authoritative server list.
async function listMacros(): Promise<PromptMacro[]> {
  const cached = await cache.getMacros();      // instant, works offline
  refreshFromServerInBackground();             // reconcile when reachable
  return cached;
}

// Write offline: apply to cache, mark pending, reconcile on reconnect.
async function saveMacro(m: PromptMacro) {
  await cache.upsert(m, { pendingSync: true }); // available immediately
  if (navigator.onLine) await syncMacro(m);     // server is the authority
}

// First sync ADOPTS device-local macros instead of clobbering them —
// a new server store folds in work the user made before it existed.

External links

Exercise

Design the sync states for a single macro edited offline: applied-to-cache, pending-sync, synced, conflicted. Then handle the first-sync-meets-existing-local-macros case: write the rule that folds the device list into the new server store without losing any. Finally, decide what happens when the same macro was edited on two devices offline — which authority resolves it, and how does each cache re-derive?
Hint
The device cache is always subordinate: it can hold pending edits, but the server list resolves conflicts and both caches re-derive from the winner. First sync is the one moment the device gets to seed the server — adopt, don't overwrite — after which the server is the standing authority.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.