The brief was a field-survey app for health workers in rural districts. Records are collected offline all day and synced in the evening, often over a 2G connection.
Why full sync failed
Our first version posted every record as one JSON payload. At 3,000 records that was 4.2 MB, and on a throttled connection the request timed out after 40 seconds with nothing saved.
Send only what changed
We kept a local change log and sent compact diffs in batches of 200, each batch acknowledged before the next. If the connection dropped, the queue resumed from the last acknowledged batch.
for (const batch of chunk(changes, 200)) {
await retry(() => api.push(gzip(batch)));
await log.ack(batch.lastId);
}
The same 3,000 records synced in about six seconds. We placed first, and the client later took the approach into production.
