Field Operations Industry, chapter 09 of 26
The Technician App
The app a technician works from all day: offline first, a command queue, conflicts, shift clocks, timers, trainees, printing, devices and online-only flows.
Everything the office plans arrives at the customer's door through one device: the technician's phone or tablet. It's where the route is read, where the visit starts and ends, where the products applied and the photos taken are recorded, and where the customer's questions get answered. It also runs in the worst conditions any business app faces: basements and crawl spaces with no signal, rural roads between towers, direct sun, gloves, wet hands, a battery that has to last ten hours, and a user whose job is the work, not the app. A web app that assumes a connection fails here a dozen times a day, and each failure is a visit with no record, a technician standing in a driveway, or a customer billed for work nobody can prove.
This chapter is how to build that app so the day keeps moving whatever the network does, and what the server behind it has to accept.
The Day, From the Device#
A technician's day is the same loop, repeated a dozen or more times. Each step has a different relationship with the network:
| Step | What happens | Needs a connection? |
|---|---|---|
| Clock in | Shift starts; the day's route loads | Ideally, to get the latest route |
| Review the route | Stops in order, arrival windows, notes, drive times | No, if preloaded |
| Check in | Arrive at the property; the visit starts | No |
| Work | Timer runs; products applied; photos and notes taken | No |
| Check out | Completion rules run; slip produced | No |
| Sell or book | An upgrade, an add-on, a follow-up visit | Yes |
| Clock out | Shift ends; everything uploaded | Eventually |
Almost everything a technician does can happen offline, and almost everything that can't is selling or booking: reading live availability and prices that only the server has. That split is the design. The app treats the device as the place where the visit is recorded, and the server as the place where it eventually lands. Only a small, explicit set of flows waits for the network (see Flows That Need the Network).
Offline Is the Default#
Build the app as if it's always offline and sometimes lucky, not the other way around. That means a local store (SQLite underneath, through whatever the platform offers: Core Data, Room, WatermelonDB) that holds everything the day needs, and screens that read only from it. The network fills the store; the user never waits on it.
What the day needs is more than the route:
- The route and its stops: order, arrival windows, durations, and the sequence the optimizer chose (Route Optimization).
- Each property: address, gate codes, pets, access notes, photos of the property, where the bait stations are, what was treated last time and what the customer said.
- Each account's flags: an unpaid balance, a complaint, a VIP, a pest problem the salesperson noted at the door.
- Each visit's work: the work orders, what each requires, and which products and methods are allowed for it.
- The catalog: products, their registration numbers and labels, safety data sheets, application methods and target pests, so a material record can be completed in a basement (Regulated Materials).
- The technician's own state: licenses, which matter for what they're allowed to apply and where (Licenses & Permits).
Preload it at clock-in, refresh it whenever the network allows, and show its age. "Route as of 7:42" tells a technician whether the office's last change has reached them; a silently stale route doesn't.
Photos are the heaviest part of the day and the easiest to get wrong. Write them to the device's file storage first, record them in the local store as pending uploads, compress them once, and upload them in the background. A visit's completion shouldn't wait on four photos crossing a weak LTE connection, and a photo should never exist only in memory.
A Queue of Commands, Not a Copy of the Database#
The tempting design is two-way database sync: the device has a copy, the server has a copy, and a sync engine reconciles them. For field work it's usually the wrong one. The server enforces rules the device can't fully know (a route was locked, a visit was cancelled, a product was pulled), and a sync engine that ships rows can't explain to the technician which of their changes were refused and why.
Ship commands instead: intentions with everything needed to apply them. "Check in to visit 812 at 10:14", "Record 2 oz of this product on work order 1033", "Add this note", "Upload this photo". The app applies each command to its local store immediately, so the screen updates, and appends it to a persisted command queue that a background worker drains to the server's API.
The rules that make it hold up:
- Persist before acknowledging. A command is written to disk before the UI says "saved". If the app is killed or the battery dies, the queue is still there on restart.
- Order within a visit, not globally. Commands for one appointment run in sequence: a note on a visit can't arrive before the check-in that created it on the server. Commands for different appointments run independently, so one stuck visit doesn't block the rest of the day.
- Every command carries an idempotency key. The worker will resend after timeouts, and a timeout doesn't mean the server didn't apply it. The server keeps the key and returns the original result for a repeat (Idempotency).
- Coalesce what's redundant. Three edits to the same note before any upload can become one; a photo added and then deleted offline never needs to upload.
- Drain in the background. Android's WorkManager persists scheduled work across app restarts and reboots and supports network constraints and exponential backoff. iOS gives less control: background processing tasks are requests, which the system runs when it chooses. On iOS, drain aggressively whenever the app is in the foreground and treat background time as a bonus.
Retry, Abort or Pause
Each failure response tells the worker what to do with the command, and getting this wrong either loses data or loops forever:
| Result | Meaning | What the queue does |
|---|---|---|
| Network error, timeout | Unknown: it may or may not have applied | Retry with the same idempotency key, with backoff |
| 5xx | The server failed | Retry with backoff, up to a ceiling, then flag for support |
| 429 | Slow down | Retry after the server's Retry-After; don't count it as a failure |
| 401 | The token expired | Refresh the session, then retry |
| 400, 403, 404, 422 | The server understood and refused | Abort the command and show it to the technician |
| 409 | The state changed underneath | Abort, refresh that record, and show what changed |
| Feature disabled | The server has turned this path off | Pause the queue, keep the commands, resume when it's back |
Aborted commands need a home in the UI: a list of what didn't make it and why, in the technician's language ("This visit was cancelled by the office at 9:52; your note was not saved"). A dropped command with no explanation is how a technician learns to keep paper notes. The pause case matters operationally: it gives the server a way to stop a broken client path in the field, through a feature flag, without losing what the devices are holding.
Conflicts#
While a technician is offline in a crawl space, the office keeps working: a dispatcher moves the next stop, a customer cancels from the portal, someone edits the gate code. When the device reconnects, two versions of the day meet. The policy has to be decided per kind of data, not once for everything:
- Plans belong to the office. Route order, time windows, which visits exist: the server wins, the device refreshes, and the technician sees a change notice. A technician can't un-cancel a visit by having been offline.
- Work facts belong to the field. What was applied, what was photographed, when the technician arrived: these happened, and the server can't overrule them. Make them append-only: each record is a new row, corrections are new rows that supersede old ones, and nothing the device recorded is overwritten by a sync.
- Shared descriptive data gets the newest write, with history. Notes and property details can be edited from both sides; keep every version, so a lost edit can be recovered.
The hard case is work recorded against a plan that changed: a technician completes a visit the office cancelled ten minutes earlier. Don't reject the work. The server should accept the record of what happened (the treatment was applied; the regulator cares regardless of what the schedule says) and route the contradiction to a person: revive the visit, or keep it cancelled and handle billing by hand. Some platforms do this automatically, reviving a recently cancelled visit when a technician checks in to it. Either way, the record survives.
Clocking In and the Shift Gate#
The app usually doubles as the time clock, and that makes it a payroll record. Under the Fair Labor Standards Act, travel from job site to job site during the workday counts as hours worked, while ordinary travel from home to work generally doesn't. For a route-based business, that means drive time between stops is paid time, the first stop's commute may not be, and the clock has to capture both correctly. A field technician paid hourly whose clock starts at the first check-in, not when they started driving between jobs, is a wage claim waiting to happen. Get your employment counsel's view on where your shifts start; the app's job is to record it faithfully.
A shift gate ties the work to the clock: visits are read-only until the technician has clocked in and isn't on a break. It stops off-the-clock work, which protects both the technician and the company, and it keeps service records inside shift records.
The gate should fail open. If the clock's state is still loading, the device is offline, or the gate is disabled, let the technician work and reconcile later. A gate that blocks a technician in a driveway because a clock service is slow costs a visit, and a clock-in made offline is just another queued command.
Timers and Pauses#
Every visit has a work timer: start at check-in, pause for a phone call or a trip to the truck, resume, stop at checkout. Record the events (started, paused, resumed, completed), not just a total, and compute durations from them. The pauses matter twice:
- For the customer and regulator, the visit's start and end time may need to be on the record, and some state rules ask for the time an application was completed.
- For planning, actual on-site time per service type, per property size and per technician is the data that sets planned durations. A plan's standard visit length that's never compared to the measured one drifts until routes are fiction (Route Optimization).
Separate on-site time from drive time and from break time. They answer different questions (productivity, routing accuracy, labor law), and a single "shift minutes" number answers none of them.
Trainees and Ride-Alongs#
New technicians learn by riding along, and a route can carry more than one person. Model it on the route: a primary who owns the route, a secondary helping, a trainee learning. Each sees the same stops; what they can do differs:
- A trainee can record but not complete. They take the photos, enter the products and write the notes; checkout shows "review to complete" for the primary or secondary to approve. The record shows who did the work and who signed off.
- Licensing follows the role. Whether someone in training may apply a regulated product at all, and under whose supervision, is set by state licensing rules (Licenses & Permits). The record has to show it: Texas, for example, requires a pesticide use record to name each person applying, training or supervising, with their license numbers.
- Time is paid to everyone. Each person on the route clocks in separately; the visit's work timer is the visit's, not any one person's.
Printing and Leaving Something Behind#
Most visits end with something left for the customer: a service slip on the door, an invoice, a notice that the yard was treated. The app needs three ways to deliver it:
- Print in the truck. A small Bluetooth or Bluetooth Low Energy printer, driven by its manufacturer's SDK (Brother's mobile SDK covers iOS and Android, for example), prints a receipt-width slip anywhere. AirPrint needs the device and printer on the same Wi-Fi network, which a truck usually isn't, so it suits the branch office better than the route.
- Email or text it. The default when the customer has a verified email or phone and has agreed to receive it (Customer Communications).
- Hang a paper door tag. Pre-printed, filled by hand, for when nothing else works.
Render the slip on the device from the visit's local record, so it prints offline. Then render it again on the server from the synced record and keep that copy as the official one. They should match, and when they don't, the server's version is what the regulator sees (Proof of Service).
Devices, Releases and Flags#
Company-owned devices are worth the cost for most field operations. Managed devices give you a known OS version, a known screen size, remote wipe when a truck is broken into, and the power to install updates without asking.
- Enroll them automatically. Apple's business enrollment puts devices into your device management service from first boot and supervises them. Android's dedicated-device mode does the same for single-purpose devices, and its documentation names field service as a use case. Lock task mode can restrict a device to an allowlist of apps.
- Expect old versions in the field. Even managed fleets update over days, and some devices sit in a drawer for a season. The server must accept every client version it hasn't explicitly retired. Retire versions with a minimum-version check that tells the technician to update, never with an API change that breaks them silently. Mobile Releases covers phased rollouts and forced updates.
- Put risky paths behind flags. A new checkout rule or a new upload path should be switchable from the server, per branch, so a bad release can be contained in the field without waiting on an app store review.
- Report crashes and queue health. Crash reporting is table stakes; the number that matters more is per-device queue depth and the age of the oldest unsent command. A device that hasn't drained in two days is a technician whose work isn't on any record.
Flows That Need the Network#
A few flows can't be done honestly offline, and the app should say so instead of queueing them:
- Selling an upgrade or add-on. Price, eligibility and promotions are decided on the server (Pricing & Sales Rules), and the customer agrees to a specific price.
- Taking a payment. Authorization is live by nature, and card data shouldn't sit in a queue (Sensitive Data).
- Booking another visit. Availability changes by the minute (Booking Appointments).
Give these an explicit "needs a connection" state with a way forward: retry when signal returns, or hand it to the office ("Create a callback for the office to book this"). Queuing a sale offline and submitting it hours later at a price that's since changed creates an agreement the customer never saw.
What This Means for the System You Build#
- A local store as the screen's only source, preloaded at clock-in, refreshed opportunistically, with its age shown.
- A persisted command queue, ordered per appointment, idempotent, drained in the background, with retry, abort and pause decided by status class.
- A visible list of refused commands, with reasons in plain language.
- Conflict policy by kind of data: office owns plans, field owns work facts (append-only), notes keep history.
- Work recorded against a cancelled visit is kept and routed to a person.
- Shift clock and work timers as event records, with drive, on-site and break time separated, and a shift gate that fails open.
- Primary, secondary and trainee roles on a route, with trainee work approved by a licensed supervisor.
- Slips rendered on the device for offline printing and re-rendered on the server as the record.
- Managed devices, version retirement by minimum-version check, flags for risky paths, and queue depth as a fleet metric.
- Selling, payments and booking marked online-only, with a handoff when there's no signal.
References#
Specifications
- 29 CFR 785.38: Travel that is part of the day's work, travel from job site to job site counted as hours worked
- 4 Tex. Admin. Code 7.144: Pest Control Use Records, each person applying, training or supervising named with license numbers
- Minnesota Statutes 18B.37: Records, structural applicators recording the time an application was completed
Reference
- Android Developers: Persistent work, WorkManager persistence across restarts and reboots, constraints and exponential backoff
- Apple Developer: BGProcessingTaskRequest, background processing requests with network and power requirements
- Android Developers: Dedicated devices, fully managed single-purpose devices for field service, and lock task mode
- Apple: Platform Deployment, automated device enrollment and supervision
- Apple Support: About AirPrint, printing without drivers on the same Wi-Fi network
In practice
- Brother Mobile SDK, printing to mobile and label printers over Bluetooth, BLE and Wi-Fi from iOS and Android