Skip to main content

Offline-First and Client Synchronization

Purpose: Normative patterns for disconnected or intermittent connectivity (e.g. field clinics, unstable links).
Authority: Complements ARCHITECTURE_BASELINE.md and MODULE_SHARED_STANDARDS.md. Module SPEC.md / TECHNICAL_REQUIREMENTS.md define which workflows are offline-capable.

Extended specification pack: Detailed FR/NFR/TR, solution design, and traceability live under offline-first/ (SPEC.md, TECHNICAL_REQUIREMENTS.md, SOLUTION_DESIGN.md, TRACEABILITY_MATRIX.md). This document remains the short spine; avoid duplicating long requirement tables here.


1. Goals

  • Allow authorized users to capture and queue work while offline or degraded.
  • Synchronize to the server when connectivity returns without corrupting tenant boundaries or clinical safety.
  • Make conflicts explicit and resolvable per policy (never silent data loss for regulated data).

2. Client local store (technology-agnostic)

Deployments MAY use local-first databases (e.g. Realm, Couchbase Lite, SQLite, Ditto) or equivalent per product decision. The server remains the authority for:

  • Global uniqueness constraints that span clients (e.g. certain identifiers).
  • Inventory/stock quantities and controlled-substance rules where applicable.
  • Final licensing and access-policy decisions.

Clients MUST hold tenant context and actor identity in a tamper-resistant way (no cross-tenant merge of local databases).


3. Mutation identity and idempotency

  • Client-originated writes SHOULD carry a clientMutationId (or equivalent) stable across retries.
  • Server APIs MUST treat duplicate (tenantId, clientMutationId) as idempotent (same response semantics as first success) where this pattern is adopted for a module.
  • REST writes SHOULD also support Idempotency-Key where documented in module technical requirements (aligned with architecture baseline).

4. Sync model (high level)

  1. Local commit — UI and domain logic persist to the local store immediately (optimistic UX).
  2. Outbound queue — Operations eligible for sync are queued with ordering constraints per aggregate (e.g. per patient, per visit) as defined by the module.
  3. Upload — On connectivity, the client pushes queued mutations to the Kong-exposed API (or dedicated sync endpoint behind Kong) with auth tokens refreshed per IAM policy.
  4. Server validation — Server enforces RBAC/ABAC, licensing, business rules, and tenant isolation; rejects or branches conflicts.
  5. Reconciliation — Client applies server outcomes: success, rejection with reason, or conflict payload for user resolution.

5. Conflict handling

  • Default: optimistic versioning (e.g. version / etag) with server rejection on stale writes unless merge rules are explicitly defined.
  • Modules MAY define domain-specific merge (e.g. append-only notes) vs manual resolution (e.g. duplicate patient match).
  • Audit: sync conflicts that affect PHI MUST emit audit events when resolved.

6. Events and NATS

  • Successful server-side commits SHOULD publish domain events on NATS JetStream per module EVENT_MODEL.md.
  • Clients MUST NOT publish directly to NATS from the public internet; only trusted services publish broker events.

7. Security and compliance

  • Local stores MUST use encryption at rest where the deployment class requires it (device policy).
  • PHI on device MUST respect retention, wipe, and session timeout policies.
  • Offline buffers (e.g. audit envelopes) MUST be integrity-protected (sign or sealed envelope) where required by audit or compliance policy.

8. Testing

  • Modules claiming offline support MUST define automated tests for: queue replay, idempotency, conflict paths, and tenant isolation in TRACEABILITY_MATRIX.md.
  • See TESTING_STANDARDS.md for sync/offline and Kong contract expectations.

9. Mapping to existing modules

Authoritative per-domain behavior remains in:

  • specs/modules/<module>/SPEC.md
  • specs/modules/<module>/TECHNICAL_REQUIREMENTS.md

Narrative consolidated supplements (legacy import) live under specs/reference/consolidated-packages/ and MUST NOT override module specs where they differ unless the module spec is explicitly updated.