Offline-first laboratory platform with two-level sync
A laboratory management architecture for field technicians, local lab servers, and delayed cloud synchronization during connectivity outages.
The system supports laboratories that process samples from food, industrial plants, rivers, and animals. It tracks the lifecycle from sample entry through testing methods, pathogen or disease checks, and final status reporting.
Challenge
The platform needed two offline modes, not just a generic "save later" experience. Field technicians can be away from Wi-Fi and still capture sample metadata, test progress, and supporting notes locally on a mobile device. Entire laboratories can also lose cloud connectivity and continue working against in-house servers without stopping sample intake or delaying testing.
That distinction mattered because the failure modes are different. A mobile device reconnects frequently and usually has a single user's work to reconcile. A laboratory outage can involve many users, several modules, and a longer queue of business events that must be replayed without duplicating reports or corrupting sample state.
Architecture
Device-level offline work uses RxDB in the browser. Laboratory-level offline work uses local services and RabbitMQ federation to synchronize with cloud RabbitMQ when connectivity returns.
The application is a modular monolith with clear module boundaries. Identity is distributed as an independent service to support future Single Sign-On work. Modules communicate through a service bus and use the Inbox/Outbox pattern in both local and cloud environments.
The local laboratory installation owns the operational path during an outage. Users can receive samples, attach testing methods, record observations, and move work through internal statuses. When the cloud connection returns, the local broker federates events back to the cloud broker and the platform reconciles state through idempotent handlers.
Engineering decisions
The architecture deliberately keeps most business capability inside the modular monolith. That choice reduces distributed transaction pressure and keeps domain rules close to the data they protect. The system still uses asynchronous messaging for integration boundaries, but it does not split every module into a separate deployable service before the operational need is clear.
Identity is the exception. It was separated early because authentication, authorization, and future Single Sign-On integration have a different lifecycle than laboratory workflow modules. Keeping Identity independent also makes it easier to support multiple clients and environments without coupling login concerns to sample processing releases.
Reliability patterns
Inbox and Outbox tables protect the message flow on both sides of the connection. A command that changes sample state can commit together with the outbound event record, then a background dispatcher publishes the event to RabbitMQ. Consumers record processed message identifiers before applying side effects, so replay after reconnect is expected behavior rather than an exceptional recovery path.
Conflict handling is designed around business ownership. Device-level conflicts are resolved near the technician's work because the device usually owns the most recent field observation. Laboratory-level synchronization is stricter: central sample status, report status, and method assignment changes move through server-side rules so multiple users cannot silently overwrite critical decisions.
Outcome
The resulting design supports technicians, local laboratory teams, and cloud operators without forcing one synchronization model onto every use case. It gives the product room to grow toward Single Sign-On, more laboratory modules, and stronger integration workflows while keeping the first production architecture understandable for the engineering team.