Skip to content

feat: Local-First Data Layer & Offline Support #7

@danisharora099

Description

@danisharora099

Local-First Data Layer & Offline Support

Goal

Make the forum usable even when the Waku network is unavailable by caching data in the browser (IndexedDB) and automatically syncing when connectivity is restored.


Motivation

Today, all forum content is fetched live from Waku and kept only in memory (messageCache).
If the user reloads while offline – or loads the site before peers are discovered – the UI is empty.
Making the app local-first will:

  • Deliver instant page loads from local data.
  • Let users browse / write posts & comments offline.
  • Reduce network load & perceived latency even when online.

High-Level Design

Layer Responsibility
IndexedDB (via Dexie) Persistent store for all message types (cells, posts, comments, votes, moderations).
MessageManager (src/lib/waku/index.ts) – Persist every received message to IndexedDB.
– Maintain an outbox collection of locally-created messages with isPublished = false.
Sync Engine – On startup: hydrate messageCache from IndexedDB before touching the network.
– While offline: queue outgoing messages → outbox.
– When MessageManager.isReady === true: replay outbox, mark isPublished = true, then delete.
UI (ForumContext, pages) – Renders immediately from hydrated cache.
– Shows a small “Offline” banner when isNetworkConnected is false.
– Shows a “⟳ syncing n items…” indicator while flushing the outbox.

Implementation Plan

  • Set up Dexie wrapper (src/lib/storage/db.ts)

    ```ts
    export const db = new Dexie("opchan");
    db.version(1).stores({
      cells: "id, timestamp",
      posts: "id, cellId, timestamp",
      comments: "id, postId, timestamp",
      votes: "&[targetId+author], timestamp",
      moderations: "targetId, timestamp",
      outbox: "id, type, timestamp" // unsent msgs
    });
    ```
    
  • Hydrate on bootstrap
    In ForumContext, before initializeNetwork() call:
    1. Load all tables into messageManager.messageCache.
    2. updateStateFromCache() so the UI renders instantly.

  • Persist incoming messages
    Extend MessageManager.updateCache() to await db.<table>.put(message).

  • Offline detection
    The existing messageManager.onHealthChange() already emits readiness; surface this in UI (banner).

  • Outbox queue
    1. sendMessage() detects offline → db.outbox.put({...msg, isPublished:false}).
    2. When health flips to online, iterate outbox, push via ephemeralProtocolsManager.sendMessage(), then db.outbox.delete(id).

  • Conflict handling (simple)
    If Waku later returns a message with the same id, just overwrite local copy – messages are immutable.

  • Unit tests for the storage layer (Dexie mock) & sync logic.

  • E2E smoke test:
    1. Load site → disconnect network → create post.
    2. Reload (still offline) → post is visible.
    3. Reconnect network → post is published and visible on a second device.


Acceptance Criteria

  • App loads fully offline using previously cached data.
  • Users can create posts/comments while offline; they appear with a “pending” style.
  • Pending items are automatically published within 10 s of regaining connectivity.
  • No data loss after browser refreshes (validated across Chrome/Firefox).
  • Lighthouse “Offline” audit passes.
  • No TypeScript errors or ESLint warnings.

References & Inspiration


Related Code Pointers

  • src/lib/waku/index.ts – TODO at top about IndexedDB storage.
  • src/contexts/ForumContext.tsx – initial loading flow & updateStateFromCache.
  • src/contexts/forum/network.ts – health monitoring utilities.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions