Offline-First Design
debt(d7/e9/b7/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints list Lighthouse, Workbox, and Chrome DevTools. Lighthouse can flag some offline gaps (e.g., no service worker, no manifest), but missing conflict resolution, lack of sync status feedback, or unencrypted IndexedDB storage are not caught by these tools automatically — they require careful code review and manual testing under simulated network loss conditions. The code_pattern listed (app showing error on network loss, all reads requiring server roundtrip) is partially detectable by Lighthouse but not comprehensively.
Closest to 'architectural rework' (e9). The quick_fix description ('Design for offline first: store data locally with IndexedDB, sync with your PHP backend when connectivity returns, show optimistic UI') reveals this is not a patch — it requires introducing a local data layer, a sync engine, conflict resolution strategy, background sync, and UI feedback. Common mistakes (conflict resolution, encryption, sync status) each compound the rework. Adding offline-first to an app originally designed around server-round-trips is a fundamental architectural rework touching data flow, UI, backend sync endpoints, and error handling throughout the codebase.
Closest to 'strong gravitational pull' (b7). The applies_to context is web broadly, and tags include architecture and pwa. Once offline-first is adopted, every future feature must account for local storage, sync state, conflict resolution, and optimistic UI — shaping every data-touching decision. The design philosophy reaches across UI components, data access patterns, and backend API design. It does not quite define the system's entire shape (b9) since some areas like authentication still follow normal patterns, but the gravitational pull on data and UX is very strong.
Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field explicitly states developers assume offline-first is only for mobile apps, missing that web apps in poor-connectivity environments (travel, remote work, field service) benefit equally. Common mistakes reinforce additional traps: assuming IndexedDB is safe for sensitive data without encryption, and assuming offline-first is compatible with real-time features like chat. These are well-documented gotchas in PWA/offline-first literature that developers typically encounter and learn the hard way, placing this squarely at t5.
Also Known As
TL;DR
Explanation
Offline-first assumes the network is unreliable — store everything locally first, then sync to the server when connectivity is available. Technologies: IndexedDB (client-side structured storage), Service Worker (intercept requests and serve from cache), Background Sync API (defer network requests until online), CRDTs (Conflict-free Replicated Data Types) for conflict-free merging. Patterns: optimistic updates (show change immediately, sync in background), conflict resolution (last-write-wins, server-wins, or manual merge), and sync queue (pending operations stored and retried).
Common Misconception
Why It Matters
Common Mistakes
- No conflict resolution strategy — concurrent offline edits from multiple devices corrupt data.
- Storing sensitive data in IndexedDB without encryption — IndexedDB is not encrypted by default.
- No user feedback on sync status — users need to know when their data is saved vs pending sync.
- Offline-first for real-time features — chat and live collaboration require constant connectivity.
Code Examples
// No offline support — data lost when network drops:
async function saveNote(note) {
await fetch('/api/notes', {
method: 'POST',
body: JSON.stringify(note),
});
// If fetch fails: error, data lost, user frustrated
}
// Offline-first: save locally, sync in background:
async function saveNote(note) {
const db = await openDB('notes-store', 1);
await db.put('notes', { ...note, synced: false }); // Save locally first
showUI('Saved locally');
if (navigator.onLine) {
await syncToServer(note);
await db.put('notes', { ...note, synced: true });
showUI('Synced');
} else {
// Background Sync: retry when online:
await navigator.serviceWorker.ready.then(sw =>
sw.sync.register('sync-notes')
);
}
}