Skip to content

A field inspection app that keeps working when the signal doesn't

A native inspection app that keeps working with zero signal in the field, syncing photos and checklists the moment a connection returns, with push alerts routed through each platform's store-approved channels.

10:47
Transformer T2Harlan Creek Sub · Substation quarterly v7 · RND-3318
No signal since 7:48 AM · nothing is waiting on itEvery answer and photo is written to this handset as you go
9 of 14 answered · 1 failed 4 held · 11 photos
Site & access3/3
Transformer T21 failed5/5
Oil level gauge62 %10:39
Pressure relief device10:41
Cooling fansFan 2 stalled10:44
2 photos on this handsetWritten to disk on capture Fault
Bushings & gaskets10:45
Silica gel breather10:46
Switchgear1/3
Breaker operations counter4,81210:47
SF6 gas pressure—
Panel heaters—
Protection & earthing0/3
RoundsInspectQueue4Assets

The shape of the work

Industry

Home & Field Services

Duration

10 weeks

Cooperation model

Fixed price

Services
Native app buildOffline-first syncStore release
Integrations
StripeSendGridSegmentSentry
Technologies
React NativeSQLiteWatermelonDBAPNsFirebase Cloud MessagingNode.js
Team
1 Project lead1 Product designer2 Mobile engineers1 Backend engineer

Client name withheld under NDA. Engagement details are shown to the extent our agreement permits.

Offline-First Storage Engine

Persists photos, audio notes and complex checklists locally, with no cell connection needed.

WatermelonDB over SQLite holds the whole inspection locally (photos, audio notes, nested checklists), so the app behaves identically with or without signal. There's no read-only mode to degrade into. Photos are compressed and written to disk on capture, never held in memory, which is what lets an inspector shoot four hundred frames in a day without the OS killing the app.

What shipped
  • Full local model: photos, audio and nested checklists
  • Photos compressed to disk on capture, never held in memory
  • Identical behavior on and off signal
10:52
Fan 2 locked rotorFLT-0926 · T2 cooling fan bank · Harlan Creek Sub
Written locally · 10:52 AM · no signal needed to save
Readings against limits3 of 6 over limit
Top-oil temperaturelimit ≤ 85 °C91 °COver
Winding hot-spotlimit ≤ 110 °C112 °COver
Fan 2 motor currentlimit ≤ 4.0 A5.9 AOver
Fan 1 motor currentlimit ≤ 4.0 A3.6 AIn limit
Enclosure ambientlimit ≤ 40 °C38 °CIn limit
Oil levellimit ≥ 40 %62 %In limit
Evidence · on this handset
Voice note0:41
Flag as safety hazardPriority alert leaves first, the moment any signal appears
PhotoSave to handset
On screen

The fault sheet filled in at the enclosure: six readings against their limits with three over, three photographs and a voice note on the handset, the hazard flag set, and all of it written locally.

1:26
QueueHS-14 · Dana Okafor · signal back 1:26 PMEmpty
Everything in6.5 s after signal5 h 38 min dark · acknowledged by the server, not just sent7/7Inspections22/22Photographs0Records lost
Captured today, offlineLedger
Line 14 · MLV-23 valve stationINS-4466 · 8:06 AM · 9 checks · 3 photosAcked
Line 14 · MLV-26 valve stationINS-4467 · 8:51 AM · 9 checks · 2 photosAcked
Pike Road regulator stationINS-4468 · 9:40 AM · 11 checks · 3 photosAcked
Harlan Creek Sub · Transformer T2INS-4469 · 10:31 AM · 14 checks · 5 photosAlert first
Harlan Creek Sub · Switchgear bay 2INS-4470 · 11:28 AM · 12 checks · 3 photos1 field
Line 14 · CP-31 test postINS-4471 · 12:15 PM · 6 checks · 2 photosAcked
Dry Fork pump stationINS-4472 · 12:58 PM · 13 checks · 4 photosAcked
INS-4470: one verdict queued for R. Lindqvist
RoundsInspectQueueAssets

Automatic Reconnect Sync

On screen

Signal returns and the queue empties itself: seven inspections and twenty-two photographs acknowledged by the server 6.5 seconds later, zero records lost, and one verdict held back for a supervisor.

Background sync with automatic conflict resolution, clearing in under 8 seconds once signal is back.

Sync is a background task that resumes where it stopped, so a truck driving in and out of coverage makes steady progress instead of thrashing. Conflicts resolve per field, with last-write-wins on scalars and union on collections, and anything genuinely ambiguous is queued for a supervisor. Nothing gets silently picked. A full day's backlog clears in under eight seconds on a normal connection.

What shipped
  • Resumable background sync that picks up where it dropped
  • Per-field resolution: last-write on scalars, union on lists
  • Ambiguous conflicts queued for a supervisor, never guessed

Urgent Safety Push Alerts

APNs and FCM integration for instant routing of flagged utility hazards to supervisors.

A flagged hazard doesn't wait for the sync queue. It takes a dedicated priority path straight to APNs and FCM the moment any connectivity appears, carrying the location and a photo thumbnail in the payload so a supervisor can triage from the lock screen. Delivery is acknowledged back to the device, and an unacknowledged alert re-sends. Nothing is assumed received.

What shipped
  • Priority path that jumps the ordinary sync queue
  • Location and thumbnail carried in the notification payload
  • Unacknowledged alerts re-send until delivery is confirmed
1:27
Priority alertFLT-0926 · Fan 2 locked rotor · Harlan Creek Sub
Jumped the sync queueSent at 1:26 PM, before 7 held inspections
What the supervisor's lock screen shows
1:27
Groundfile · HazardnowFan 2 locked rotor · Transformer T2Top-oil 91 °C · 3 of 6 readings over Bay T2 · 38.2417° N, 104.6089° W
Delivery · receipts back to HS-14
Hazard flagged at the enclosureNo signal · held on the priority path10:52 AM
Signal returnsAlert leaves ahead of the 7 queued inspections1:26 PM
FCM · M. Ortega, on callDelivery receipt back to HS-141:26 PM
APNs · R. Lindqvist, supervisorNo receipt · not assumed delivered1:26 PM
APNs re-sentDelivery receipt back to HS-141:27 PM
No receipt means re-send, never “probably delivered”
RoundsInspectQueueAssets
On screen

The hazard's priority path: the alert as the supervisor's lock screen shows it, with location and photo thumbnail, sent ahead of the queue, and an APNs send with no delivery receipt re-sent instead of assumed delivered.

Introduction

What we were brought in to do

Inspectors work substations and pipelines with no cell coverage for hours at a time. We built a native iOS and Android app that captures full inspections offline and reconciles everything the moment a signal returns.

A utility's inspection contractor covering substations and pipeline runs where crews are out of coverage for four to six hours at a stretch. The previous app had been written for an office network and taken into the field unchanged. The engagement began after an audit found inspection records with photographs missing and no way to tell whether they had ever existed.

Mobile Engineering

Where the old way broke

The previous app assumed connectivity and silently dropped photos and checklist entries in dead zones, so inspectors redid work back at the office and supervisors couldn't trust the record.

The old app buffered in memory and posted on save. In a dead zone the post failed, the buffer was discarded on the next screen, and the interface reported success, so an inspector genuinely believed the work was recorded. Supervisors had learned not to trust the record, which meant crews were re-photographing sites they had already documented.

We built an offline-first data layer that persists every photo, note and checklist entry locally, then syncs and resolves conflicts automatically once the device reconnects. Push notifications run through APNs and FCM for urgent flagged issues.

The solution

What we built together

  1. 01

    Designed local-first storage so a full inspection survives a dead zone entirely

    Local-first was scoped against the routes with the worst coverage, because the worst route is the one that decides the design.

  2. 02

    Built background sync with conflict resolution for entries edited on two devices

    Sync resumes where it stopped, and conflicts resolve per field (last write on scalars, union on collections), with anything genuinely ambiguous queued for a supervisor.

  3. 03

    Wired push notifications through APNs/FCM for flagged safety issues

    A flagged hazard takes a priority path that jumps the sync queue entirely, carrying the location and a thumbnail so a supervisor can triage from the lock screen.

  4. 04

    Prepared signing, store metadata, and privacy declarations for a clean first review

    Signing, store metadata and privacy declarations were prepared alongside the build, which is why both reviews passed on first submission.

Process

Phase by phase

  1. Phase 1: Field Audit & Dead Zone Specs

    Zero-Signal Offline Architecture

    Accompanied utility inspectors into remote substations to map offline photo capture, audio note recording, and checklist persistence requirements.

    • Offline Architecture Spec
    • Dead Zone Usability Matrix
    • Data Schema
  2. Phase 2: Local Persistence Layer

    SQLite & Sync Engine Engineering

    Engineered local SQLite and WatermelonDB storage capable of holding hundreds of high-res inspection photos offline with automatic background sync.

    • Local Sync Engine
    • Conflict Resolution Logic
    • Storage Encryption Layer
  3. Phase 3: Push Alerts & Native Build

    Safety Alerts & APNs/FCM Integration

    Integrated APNs and FCM push messaging to route urgent safety flags and hazardous site warnings directly to supervisors.

    • Push Notification Pipeline
    • Native iOS & Android Builds
    • Safety Alert Rules
  4. Phase 4: Store Submission & Deployment

    App Store Review & Fleet Rollout

    Prepared store metadata, privacy declarations and code signing, and passed Apple App Store and Google Play Store review on the first attempt.

    • App Store & Play Store Clearances
    • MDM Fleet Deployment
    • Inspector Onboarding
1:31
Conflict · INS-4470SF6 gas pressure · Harlan Creek Sub · Switchgear bay 2
In the fieldD. Okafor11:34 AM · offlineIn the officeR. Lindqvist12:02 PM · office
Resolved per field
ReadingLast write0.52 MPa0.55 MPa0.55 MPa · 12:02 PM
PhotographsUnion21All 3 kept
NotesUnion11Both kept
VerdictAmbiguousFailPassQueued for supervisor
Scalars take the last write, collections keep both. A verdict that disagrees is never picked for you.
Keep PassKeep Fail
On screen

The same check answered twice, once offline in the field and once in the office, resolved per field: the reading takes the last write, photographs and notes keep both, and the disagreeing verdict waits for a supervisor.

Operational results after launch

0

Inspections lost to dead zones

< 8s

Sync time on reconnect

Passed 1st try

Store review

Inspections lost is a count from the reconciliation ledger over the first six months, not a survey. Sync time is measured from the device regaining signal to a full day's backlog being acknowledged by the server, at the ninetieth percentile. Store review is the first submission on each platform.

Client name withheld under NDA. Figures are approximate, drawn from the engagement’s own reporting.

Ways of working

About our collaboration

A cross-functional team of 4 worked on a fixed price basis over 10 weeks, covering Native app build, Offline-first sync, Store release. We shipped in two-week increments, each one releasable and reviewed live before it merged. Decisions were written down as they were made, so the reasoning outlived the people who made it.

The build was tested in the field: two inspectors carried builds on real routes from week three, including the routes with the worst coverage. Store submission was prepared alongside the work, with signing, metadata and privacy declarations in place before the first release candidate, which is why review passed the first time.

What it settled

What we'd carry into the next one

Zero inspection loss in dead zones ended the rework and the supervisors' skepticism.

The rework disappeared along with the uncertainty. Crews hadn't been re-photographing sites because records were lost, but because nobody could tell which ones were.

Background conflict resolution synced inspection photos and checklists in under 8 seconds upon reconnect.

Resumable sync mattered more than fast sync. A truck moving in and out of coverage makes progress on every fragment, where a restart-on-drop design would start over each time.

Compliant store release pipelines passed Apple App Store and Google Play Store reviews on first submission.

Preparing the store submission during the build turned two weeks of unpredictable review cycles into a single pass on each platform.

One round, through a dead zone

Five and a half hours without signal, seven inspections, and nothing that depends on the network to exist.

Step through the day on one handset: the signal drops, every check and photograph is written locally, the signal comes back and the hazard leaves first, then the queue drains to the server. Pick a moment, or use the arrow keys once a tab is focused.

7 inspections · 22 photographs · 5 h 38 min without signal

Row-by-row timings are illustrative; the 6.5 s drain is the recorded run

HS-14 · Dana OkaforNo signal
  • Line 14 · MLV-23 valve stationINS-4466 · 8:06 AM · 3 photosPlanned
  • Line 14 · MLV-26 valve stationINS-4467 · 8:51 AM · 2 photosPlanned
  • Pike Road regulator stationINS-4468 · 9:40 AM · 3 photosPlanned
  • Harlan Creek Sub · Transformer T2INS-4469 · 10:31 AM · 5 photosPlanned
  • Harlan Creek Sub · Switchgear bay 2INS-4470 · 11:28 AM · 3 photosPlanned
  • Line 14 · CP-31 test postINS-4471 · 12:15 PM · 2 photosPlanned
  • Dry Fork pump stationINS-4472 · 12:58 PM · 4 photosPlanned
On handset00 photographs
Acknowledged00 photographs
Lost0records, at every step
No hazards flaggedPriority path idle
The old appCarries on as if connected. Entries sit in memory until a save tries to post them.
GroundfileNothing changes. There's no online mode to fall out of, so the round starts the same way.
  1. 7:48 AMLast bar of signal leaving the depot road
  2. 7:48 AM7 inspections planned on the round, all cached
Architecture

The handset is the record. The network only copies it upward.

React Native on iOS and Android, WatermelonDB over SQLite on the device, a Node.js service behind it, and APNs and FCM for alerts. The old app buffered in memory and posted on save; here nothing shows as saved until it's on disk.

  1. 01 · Capture
    Photo, note, checklist entryPhotos are compressed and written to disk on capture, never held in memory, so a long day of frames doesn't get the app killed by the OS.
  2. 02 · State
    WatermelonDB over SQLiteThe whole inspection lives on the handset (photos, audio notes, nested checklists) behind an encrypted storage layer. The app behaves the same with or without signal.
  3. 03 · Queue
    Resumable background syncResumes rather than restarts, so a truck moving in and out of coverage makes progress. A full day's backlog clears in < 8 s (p90) on reconnect.
  4. 04 · Engine
    Per-field reconcile, Node.jsLast write wins on scalars, union on collections. Anything genuinely ambiguous is queued for a supervisor, never silently picked.
  5. 05 · Edge
    APNs and FCM priority pathA flagged hazard skips the sync queue with location and thumbnail in the payload. Delivery is acknowledged back; no receipt means it re-sends.

A record supervisors can trust

No silent losses, no guessed merges & no alerts lost in transit

Saved means on disk

The previous app buffered in memory, lost the buffer on the next screen, and still reported success. Here every photo, note and checklist entry is persisted on the handset the moment it's captured. Inspections lost to dead zones, counted from the reconciliation ledger over the first six months:0.

Conflicts are resolved, or asked about

When the same entry is edited on two devices, scalars take the last write and collections keep both sides. Anything genuinely ambiguous is queued for a supervisor, so a record never quietly changes its verdict.

A hazard alert is confirmed, never assumed

A flagged safety issue skips the sync queue and goes to APNs and FCM the moment any connectivity appears, with location and a thumbnail. Delivery is acknowledged back to the device; an unacknowledged alert re-sends.

Are your crews re-doing inspections because nobody can tell which records made it back? Scope your build in 3 minutes.

Scope your build
Have a project?

Let's talk

Running a large platform, shaping a first MVP, or getting a product ready for a funding round? Tell us where you are. We'll shape the process around it, and stay with you after launch.