Skip to main content

Technical Requirements: Offline-First and Client Synchronization (Platform)

Domain: Platform cross-cutting
Version: 1.0
Date: 2026-03-28
Service surfaces: Client applications (e.g. ehr-web, future native), Kong, owning NestJS services

References:


1. Technology assumptions

AreaChoice / note
TransportHTTPS only to Kong-exposed APIs for browser and mobile clients
AuthBearer JWT (Keycloak / IAM); session refresh before sync burst
Server idempotency storeRedis or equivalent cache manager where implemented (e.g. registration patient create TTL 24h)
Client persistenceTechnology-agnostic; MUST be encrypted at rest when PHI is stored per COMPLIANCE_SECURITY.md

2. Technical requirements (TR-OFF-###)

IDRequirement
TR-OFF-001Every queued mutation intended for replay SHALL include a stable clientMutationId (UUID v4 or ULID recommended) generated once per logical user action.
TR-OFF-002Server APIs that adopt offline replay SHALL accept Idempotency-Key (HTTP header) and/or clientMutationId in the request body where documented; dedupe key SHALL be scoped by tenant (and user where required).
TR-OFF-003Idempotent success responses SHALL be byte-stable for the same key (same JSON shape and domain ids) to simplify client reconciliation.
TR-OFF-004Ordering: mutations affecting the same aggregate (e.g. same patientId) SHOULD be sent in causal order; parallel races are resolved via optimistic versioning or module-specific rules.
TR-OFF-005BFF routes (e.g. Next.js app/api/**) SHALL forward Idempotency-Key from client to upstream service when the owning API supports it.
TR-OFF-006Kong routes SHALL not strip Idempotency-Key or Authorization headers needed for sync; rate limits apply as for online traffic.
TR-OFF-007On 401/403 during sync, clients SHALL NOT infinitely retry; refresh token or prompt re-login per IAM policy.
TR-OFF-008On 429, clients SHALL use exponential backoff with jitter.
TR-OFF-009Structured error bodies from services SHALL include code where possible so clients can branch (conflict, duplicate, validation) without string matching.
TR-OFF-010NATS publishing remains server-only; clients never connect to the broker from the public internet.

3. Reference implementation: patient registration

Owning service: registration

ItemImplementation
EndpointPOST /v1/patients
IdempotencyHeader Idempotency-Key or body clientMutationId; duplicate returns cached 201 payload
StorageRedis-backed cache (see service PatientsController + CACHE_MANAGER)
Module gate@ModuleKey('ehr.registration') + ModuleEntitlementGuard

Documentation: registration API_DOCS.md.

Gap: Client-side outbox in ehr-web not yet wired to send clientMutationId on every registration submit; platform FR-OFF-002 is satisfied at the API layer first.


4. Client outbox (target architecture)

When implemented for a shell (e.g. ehr-web):

FieldPurpose
idLocal primary key
clientMutationIdIdempotency token
tenantIdFrom session; never trust local queue without session binding
operatione.g. POST /v1/patients
payloadSerialized JSON
statuspending / syncing / completed / failed / conflict
serverResponseLast 2xx snapshot or error code for UX
createdAt / updatedAtFor retention and ordering

Retention: PHI in the queue SHALL follow device wipe and session policies.


5. Security

TopicRequirement
Encryption at restLocal DB + secure storage for tokens; see COMPLIANCE_SECURITY.md § offline.
IntegrityOptional signed envelopes for offline audit buffers when audit module requires.
Tenant isolationQueue rows filtered by tenant; no shared cache across tenants on device.

6. Observability

TopicRequirement
CorrelationPropagate correlationId from client (if provided) through BFF to service for support.
LoggingNo raw PHI in application logs; use ids and codes.

7. Appendix: HTTP headers (convention)

HeaderUse
AuthorizationBearer access token
Idempotency-KeyOpaque string; same semantics as Stripe-style idempotency for POST
X-Correlation-IdOptional; trace across sync attempts

8. Appendix: Error codes (client handling)

Clients SHOULD handle at least:

CodeTypical HTTPAction
OPTIMISTIC_LOCK_CONFLICT409Refresh + merge
DUPLICATE_DETECTED409User review (registration)
MODULE_NOT_ACTIVE / licensing403Disable offline queue for module or show upgrade
PATIENT_SEARCH_INSUFFICIENT_CRITERIA400Broaden search inputs

Exact codes are defined per module TECHNICAL_REQUIREMENTS.md.