Offline-first patterns
NodalMerge is built for local-first interaction, but good offline UX still depends on application design. This guide covers implementation patterns that prevent sync surprises.Core principle
Users should be able to keep working when transport is unavailable. That requires:- Local write acceptance
- Durable local state caching
- Predictable reconnect reconciliation
- Clear UI communication of sync status
Pattern 1: explicit sync state machine
Model client sync states explicitly:onlinereconnectingoffline-localresyncingerror-needs-action
Pattern 2: optimistic write lane
Apply local writes immediately and queue/push through SDK. Pair this with canonical refinement model:- Intent lane for optimistic actions
- Canonical lane for accepted truth
Pattern 3: persistence ownership
Define what is cached and when:- Local graph/content cache
- Outbound buffered operations
- Blob byte cache behavior (if used)
Pattern 4: reconnect-safe rendering
After reconnect:- Let handshake/diff complete
- Recompute derived UI projections
- Reconcile pending optimistic states
Pattern 5: conflict and rejection visibility
Offline-heavy workflows increase chance of visible merge/rejection outcomes. Provide:- User-readable conflict/rejection indicators
- Non-destructive retry/correct flows
- Operator/debug context capture
Pattern 6: idempotent action design
Model UI actions so retrying after reconnect is safe. Examples:- Include operation nonces/ids where app logic needs dedupe
- Prefer state-setting actions over ambiguous toggle actions
- Keep server-side side effects bounded and replay-aware
Testing matrix
Before shipping, test:- Start offline, perform edits, reconnect
- Long offline window with concurrent remote edits
- App reload during offline mode
- Blob references requested while offline
- Auth/token refresh during reconnect loop
Common mistakes
- Treating reconnect as instant full synchronization
- Hiding offline mode from users
- Failing to persist enough local state for meaningful offline continuation
- Ignoring rejection/conflict UX in offline scenarios