HomeCase studiesA Mobile Field Inspection and Automated Reporting...

Case study · Calgary, Canada

A Mobile Field Inspection and Automated Reporting Platform for a Distributor Network

Automotive aftermarket — consumable products and services sold into vehicle retail and reconditioning through a distributor network

A manufacturer selling a consumable treatment programme through independent distributors had no reliable view of what happened during a field visit, and no artefact to leave behind proving the service had been delivered. Our team built a field-service platform where a representative captures an entire site visit on a phone — vehicles scanned, standardised checks recorded, photographs taken, signature applied — and the system composes a branded inspection report, stores it, emails it to the account and tracks whether it was opened. The mobile application works without a connection and queues submissions until it has one. Delivered as a cross-platform mobile app over a Node.js API with automated document generation, territory management and a reporting layer that links inspected vehicles to public listing data.

Industry
Automotive aftermarket — consumable products and services sold into vehicle retail and reconditioning through a distributor network
Solution
A field-service data capture and automated client reporting platform: a cross-platform mobile application over a REST and GraphQL API, with server-side document generation, cloud object storage, transactional email with delivery tracking, and territory and distributor management.
Platforms
Cross-platform · Web & API
Stack
React Native · React · Node.js · Express · MySQL · AWS
Location
Calgary, Canada · delivered remotely
Role
Engineering, with the team behind for mobile and QA

Delivered remotely for a business based in Calgary, Canada. Names withheld by agreement.

Project Overview

Industry: Automotive aftermarket — consumable products and services sold into vehicle retail and reconditioning through a distributor network.

Type of solution: A field-service data capture and automated client reporting platform: a cross-platform mobile application over a REST and GraphQL API, with server-side document generation, cloud object storage, transactional email with delivery tracking, and territory and distributor management.

Business context: The manufacturer does not sell directly. Independent distributors hold defined territories and employ representatives who visit accounts — dealerships, reconditioning centres, auctions, detail operations, fleet and rental businesses — on a recurring schedule. Each visit is supposed to include an inspection of vehicles the programme has been applied to and a count of consumable stock on site. Before the platform, all of that lived in the representative's head, a paper pad, or nowhere at all. The account received no evidence the service had happened, and head office received no data.

General users: Field representatives, distributor administrators, and head-office staff. The visited account's contacts receive reports by email but are not system users.

General purpose: To standardise the field visit, turn every visit into a professional artefact the account actually receives, give the distributor network and head office real operational data, and make the programme's central commercial claim measurable rather than asserted.

The Business Challenge

The field is invisible. A distributor network is a chain of independent businesses. Head office knows what it ships and what it invoices, and almost nothing about what happens between those two events. Visit frequency, account condition, stock positions and coverage gaps were all unmeasured.

A service with no artefact is a service nobody remembers. The programme included a recurring complimentary inspection. Delivered verbally, it left no trace by the time the account reviewed the relationship. It needed to arrive as something the account could open, read and forward.

Connectivity cannot be assumed. Representatives work on open lots, in reconditioning bays and in underground parking. A workflow that depends on a live connection at the moment of submission will fail, and it will fail after the work has been done rather than before.

The submission is heavy. A visit covers multiple vehicles, each with photographs, plus a captured signature. This is not a form post — it is a multi-megabyte document assembled over the better part of an hour, and it has to survive a mobile connection.

The representative should not be doing data entry. Every field they have to type is a field they will eventually stop filling in. Vehicle identification, account identification and previous stock positions all had to be supplied by the system rather than requested from the user.

Distributors are separate businesses. They hold distinct territories and, in commercial terms, are peers rather than colleagues. Visit data, account details and stock positions must be isolated between them while head office retains a view across all of it.

The commercial claim needed evidence. The programme is sold on the proposition that treated inventory moves faster. That is a claim about the market, months after the visit, using data the business does not own — and it cannot be answered with anything the representative types into a phone.

The field fleet upgrades slowly. Representatives across an independent distributor network do not all update an app on the same day. A new release with an expanded workflow cannot break the ones still running the old one.

Our Approach

Make the phone the whole product. The mobile application is not a companion to a web system — it is where the work happens. Everything else exists to receive what it produces. That framing drove the offline model, the payload design and the decision to give the representative as few things to type as possible.

Design for offline first, and make it visible. Drafts autosave to device storage on every change. If a submission fails, it is archived as a file on the device filesystem, the queue is detected when the app next opens, and the representative pushes it with a button. We deliberately avoided silent background sync: a representative who cannot see whether their work has been delivered does not trust the app, and a representative who does not trust the app writes things down on paper as well.

Let the device do the work the user shouldn't. Vehicle identification labels are scanned with the camera and decoded to make, model and year through a public vehicle data service, with manual entry as a fallback. The account is identified from the device's coordinates by matching against previous visits and known accounts nearby, falling back progressively rather than failing to a blank form. Previous stock counts are surfaced next to the current entry so the representative is confirming rather than recalling.

Compose the deliverable server-side and get it out immediately. On receipt, the API composes a branded PDF with the captured photographs, checklist results, signature and visit summary, uploads it to cloud object storage under a content-addressed key, and sends it to the account's contacts through a templated transactional email — all while the database write is happening in parallel rather than after it.

Close the loop on delivery. The email provider's delivery events are received by webhook and joined back to the originating visit, so whether a report was delivered and opened is a fact in the database rather than an assumption.

Store the inspection as data, not as columns. Each vehicle's checklist is persisted as key/value entries rather than a fixed set of fields. This turned out to be the decision that mattered most: it let a much later mobile release ship a significantly expanded inspection workflow against the existing backend, with no migration and no coordinated deployment.

Handle old clients deliberately. Where the newer app changed how a check was represented, the report generator translates the legacy form into the current one — in one place, explicitly marked as removable once the field fleet has caught up.

Separate the read surface from the write surface. A GraphQL layer was added alongside the REST API for reporting consumers, built over the same data, so analytical access could grow without putting the contract the mobile app depends on at risk.

Delegate what isn't the product. Identity, email delivery, object storage, crash monitoring and analytics dashboards are all hosted services. Per-distributor dashboards are served through signed, tenant-filtered embed URLs rather than by building a reporting product.

The Solution

Structured visit capture. A representative starts a visit and the app records device metadata, local timezone and start time automatically. The account is identified from coordinates, shown on a map, and editable if the match is wrong.

Barcode-driven vehicle entry. Vehicle identification labels are scanned with the device camera and decoded to make, model and year, with manual entry and a validity check as the fallback path.

Standardised inspection. Each vehicle is assessed against a consistent multi-point checklist with a condition rating and free-text notes, so results are comparable across representatives, distributors and months.

In-app photography. Two photographs per vehicle are captured in the app and compressed on the device before they ever enter the payload.

Signature and sign-off. The representative writes a visit summary, sets an overall condition rating and signs on screen; the signature is embedded in the generated report.

Demo mode. A prospecting variant of the workflow with pre-filled explanatory narrative, flagged as a demo so it never pollutes operational reporting.

Offline queue with visible state. Drafts persist locally; failed submissions are archived to the device filesystem; the queue is surfaced on app open and replayed on demand.

Automated report generation and delivery. A branded multi-page PDF is composed server-side with photographs, checklist results, signature block and programme explanation, stored in cloud object storage under a content-addressed key, and emailed to the account's contacts with configurable per-distributor blind copies.

Delivery event tracking. Provider events are captured by webhook and linked back to the visit and the specific recipient.

Consumable stock counts. A server-supplied catalogue of product lines and account types, cached on the device, backs an on-site count of stock on hand, quantities delivered and value — with the previous visit's figures shown alongside for comparison.

Territory management. Territories, postcode-to-territory mapping and distributor-to-territory assignment, each with its own effective date range, plus a postcode lookup service for the public web estate.

Distributor administration. Distributor profiles, contact details, microsite metadata and blind-copy configuration, with field-level edit permissions differing between distributor administrators and head office.

Market listing intelligence. Inspected vehicles are linked to public retail listing data so the programme's relationship to time-to-sale can be measured against the local market rather than asserted.

Embedded analytics. Per-distributor dashboards delivered through signed, tenant-filtered embed URLs into a hosted BI service.

In-app training. Instructional videos bundled with the application and linked training documents, so a new representative can be brought up to the standard without a site visit.

Key Features

Offline-first field capture with an explicit queue Drafts autosave continuously, failed submissions archive to the device filesystem, and the representative can see and push the queue rather than trusting an invisible sync.

Barcode scanning with automated vehicle decoding Camera-based scanning of vehicle identification labels, decoded to make, model and year through a public vehicle data service, with a manual fallback path.

Geolocation-based account identification The visited account is resolved from device coordinates through a fallback chain — nearby previous visits ordered by distance, then known accounts nearby, then manual entry — so the representative confirms rather than searches.

Automated branded report generation A multi-page PDF composed server-side with embedded photographs, checklist results, signature and visit summary, stored under a content-addressed key that makes replayed submissions idempotent.

Report delivery with event tracking Templated transactional email to the account's contacts, with provider delivery events joined back to the originating visit and recipient.

Schema-flexible inspection storage Per-vehicle checklist results stored as key/value entries, allowing the mobile workflow to expand without a backend migration or a coordinated release.

Backward compatibility for older field devices A server-side translation of legacy checklist representations into the current form, isolated in one place with a defined removal point.

Consumable stock counting with prior-visit context On-site counts of stock, deliveries and value against a server-supplied catalogue cached on the device, with the previous visit's figures shown alongside.

Territory and distributor management Postcode-to-territory mapping and dated distributor-to-territory assignment, with tenant-scoped visibility across an independent distributor network.

Market listing intelligence Inspected vehicles linked to public retail listing data, making the programme's effect on time-to-sale a measurable question rather than a sales argument.

Technical Architecture

Mobile client. A cross-platform application built around a linear multi-step capture flow: account, vehicles, per-vehicle detail, summary, submit. Device capabilities include camera-based barcode scanning and still capture, native maps with markers, geolocation, on-screen signature capture, device and locale information, filesystem access for the offline queue, key-value storage for drafts and cached catalogue data, and bundled video playback for training. Draft keys are namespaced by a hash of the user identity so shared devices never mix representatives' work.

Authentication. A hosted identity provider handles login through a web-auth flow, issues refresh tokens for offline re-authentication, and enforces email verification before the app will proceed. Group claims travel in the token and drive role behaviour on both client and server.

API layer. A compact Node.js and Express REST API behind an nginx reverse proxy, with token validation performed against the identity provider's published signing keys and explicit audience and issuer checks. Routes are partitioned into authenticated user endpoints, a machine-to-machine surface for the public web estate, and deployment verification endpoints.

Submission pipeline. A visit arrives as a single JSON document under generous body-size limits. The API forks two workstreams: document composition and object-storage upload, and a transactional database write covering the visit, its vehicles and their checklist entries. Both must succeed; either failure rolls the transaction back. Email dispatch follows, and the provider's message identifier is recorded per recipient for later event correlation.

Reporting layer. A GraphQL endpoint mounted on the same application, backed by generated ORM models over the existing schema, serving reporting consumers independently of the REST contract the mobile app relies on.

Data layer. A relational database covering distributors and their users, territories and postcode mappings, accounts, visits, per-visit vehicles and key/value inspection results, stock submissions, email records and delivery events, device configurations, and the market listing intelligence tables.

Infrastructure. Containerised deployment on a managed multi-container platform: application container, nginx reverse proxy, and a log-rotation sidecar shipping structured logs to object storage. TLS terminates at a managed load balancer. A container-registry-backed CI/CD pipeline builds commit-stamped images and deploys them, with a lightweight endpoint for verifying which build is live.

Flow: Mobile app (offline-capable capture) → single JSON submission → token-validated API → parallel PDF composition + transactional write → object storage + relational database → templated email to the account → delivery events by webhook → reporting and analytics surfaces

Technology Stack

Category Technology
Backend runtime Node.js
Backend framework Express
Database MySQL with connection pooling and explicit transactions
ORM / reporting models Sequelize with generated models
Reporting API GraphQL served by Apollo Server on Express
Authentication Hosted identity provider (Auth0) with RS256 JWT validation against published signing keys
Document generation Server-side PDF composition with embedded fonts and imagery
Object storage AWS S3
Email delivery SendGrid, with templated sends and an inbound event webhook
External vehicle data Public vehicle identification decoding service
Logging Structured JSON logging with separate access and error streams, rotation and retention
Hosting AWS Elastic Beanstalk, multi-container Docker with an nginx reverse proxy and log-rotation sidecar
CI/CD Container-registry-backed pipeline with commit-stamped images and automated deployment
Analytics Hosted BI dashboards via signed, tenant-filtered embed URLs
Mobile framework React Native
Mobile navigation React Navigation
Mobile UI library NativeBase
Mobile device features Camera with barcode scanning and still capture, native maps, geolocation, signature capture, device info, localisation, filesystem access, video playback
Mobile storage Device key-value storage for drafts and cached catalogue data; filesystem archive for the offline queue
Mobile monitoring Hosted crash and error monitoring

Technical Challenges & Solutions

Challenge Our Approach
Representatives working where there is no usable connection Offline-first capture with continuous draft autosave, failed submissions archived to the device filesystem, queue detection on app open and explicit user-triggered replay — visible state rather than silent background sync, because a representative who cannot verify delivery keeps a paper copy too.
Multi-megabyte submissions carrying photographs and a signature Images quality- and dimension-capped on the device before they enter the payload, generous body-size limits at the API, and the payload size recorded against each submission so field failures can be correlated with submission weight.
A nested write that must be atomic while a document is being generated The visit, its vehicles and their inspection entries are written inside a single explicit transaction on a dedicated connection, running in parallel with PDF composition and upload; either side failing rolls the whole thing back, and the representative waits for the slower of the two rather than the sum.
Identifying the visited account from coordinates alone A fallback chain: previous visits within a coordinate window ordered by distance, then known accounts within the same window, then a blank form. The representative confirms a pre-filled account rather than searching a directory while standing on a forecourt.
Two app generations submitting different inspection shapes to one API Inspection results stored as key/value entries rather than fixed columns, so an expanded workflow shipped without a migration; plus a single server-side translation of the legacy representation into the current form, explicitly marked for removal once the fleet has upgraded.
Replayed offline submissions creating duplicate documents Generated reports are stored under a content-addressed key derived from the submission payload beneath a per-user prefix, making a replayed submission idempotent at the storage layer rather than requiring deduplication logic.
Proving the report reached the account Provider message identifiers recorded per recipient at send time, and delivery, open and bounce events received by webhook and joined back to the originating visit — so delivery is a queryable fact, not an assumption.
Isolating independent distributors on a shared platform Tenancy derived from the authenticated identity and enforced in the data access layer, combined with group claims that distinguish field representative, distributor administrator and head-office access, with head office retaining a cross-network view.
Diagnosing failures on a device fleet nobody controls Manufacturer, operating system, version, app version and carrier captured with every submission and deduplicated into a device configuration registry, so a failure report can be reproduced against the right configuration without interrogating the representative.

Security & Reliability

Delegated identity. Authentication runs through a hosted identity provider with a web-auth login flow, refresh tokens for offline re-authentication, and an email verification gate the application enforces before allowing use.

Cryptographic token validation. Tokens are validated with RS256 against the provider's published signing keys, with explicit audience and issuer checks and key caching with rate limiting.

Claim-based authorisation. Group claims carried in the token distinguish field representative, distributor administrator and head-office access, with editable field sets differing by role.

Tenant isolation. Visit data, accounts and stock positions are scoped to the authenticated user's distributor, with head office holding the only cross-network view — meaningful on a platform shared by independent businesses in adjacent territories.

Transactional integrity. The nested visit write is wrapped in an explicit transaction with rollback on any failure, including failure of the parallel document generation, so a report can never exist without its underlying data.

Data provenance on every submission. Device configuration, payload size, device-local timestamps and timezone are recorded with each visit, giving a complete provenance trail for any record under question.

Delivery accountability. Report recipients, provider message identifiers and subsequent delivery events are all retained, so what was sent, to whom, and whether it arrived is answerable after the fact.

Structured operational logging. Separate access and error streams in structured JSON with weekly rotation and multi-week retention, shipped off the application instance to object storage by a dedicated sidecar container.

Transport security. TLS terminated at a managed load balancer with centrally managed certificates, and explicit cross-origin policy at the reverse proxy.

Scalability & Performance

A deliberately matched load profile. This platform has low request volume and very high per-request cost — a single visit submission is a large upload, a document composition, an object-storage write, a multi-statement transaction and an email send. The architecture optimises for the expensive request rather than for request throughput.

Parallelised request work. Document composition and the database transaction run concurrently rather than in sequence, so submission latency is bounded by the slower of the two.

Compression at the source. Photographs are quality- and dimension-capped on the device, reducing payload size, upload time and document weight in one step, before the data ever reaches the network.

Catalogue caching on the device. Product and account-type reference data is fetched once and cached locally, with an explicit invalidation path, so the stock-count workflow does not depend on connectivity at all.

Pooled connections with transaction-scoped isolation. A bounded connection pool for general queries, with a dedicated connection checked out for the duration of the nested transactional write and released deterministically.

Stateless application containers. Application instances hold no local state; storage, identity and logs are all externalised, so instances are replaceable and the platform scales horizontally when it needs to.

Log volume off the instance. Structured logs are rotated and shipped to object storage by a sidecar container rather than accumulating on the application host.

Ingestion kept out of the request path. The market listing intelligence data is populated independently and exposed only through read endpoints, so external data collection never affects the field workflow.

Business Outcomes

  • The field visit became structured, comparable data, captured consistently across representatives and distributors instead of living in individual habits and paper notes.
  • Every visit now produces an artefact the account receives, automatically composed and delivered without the representative doing anything beyond completing the visit.
  • Delivery is verifiable, because report recipients and provider delivery events are recorded against the visit rather than assumed.
  • Representatives can work anywhere, with drafts preserved and submissions queued and replayed rather than lost when connectivity fails.
  • Data entry burden was moved from the representative to the system, through barcode-driven vehicle identification, geolocated account matching and prior-visit context on stock counts.
  • Head office gained visibility across the distributor network, with per-distributor dashboards and cross-network reporting over the same operational data.
  • Territory coverage became explicit, through postcode-to-territory mapping and dated distributor assignments.
  • The programme's commercial claim became measurable, by linking inspected vehicles to public retail listing data rather than relying on assertion.
  • The mobile workflow can evolve without backend coordination, because inspection results are stored in a form that does not require a migration each time the checklist changes.

Why it worked

Field-service software fails in a specific and predictable way. It is built by people sitting at a desk with a stable connection, for people standing on a forecourt in the rain with one bar of signal and a customer waiting. The gap between those two situations is where these products die — not in the feature list, but in the moment a representative loses forty minutes of work and quietly goes back to a paper pad, and nobody at head office finds out for six months.

Our team builds for the second situation. We made offline behaviour explicit and visible rather than clever and invisible, because a representative needs to see that their work is safe before they will trust the app with it. We moved every piece of data entry we could onto the device and the server — scanning labels instead of typing them, matching accounts from coordinates instead of searching a list, showing last visit's numbers instead of asking someone to remember them. We designed the submission around the fact that it would be large, slow and occasionally interrupted. And we chose a data model flexible enough that the workflow could keep evolving years later without a coordinated release across an independent distributor network — which is the difference between a platform that grows and one that quietly freezes.

Our teams work across Node.js and API design, React Native and offline-capable mobile architecture, automated document generation and delivery pipelines, cloud infrastructure and containerised deployment, and third-party data integration — with the judgement to know which parts of a field process must be modelled faithfully and which can be taken off the user's hands entirely.

Final Summary

A manufacturer selling through an independent distributor network could see what it shipped and what it invoiced, and nothing in between. The recurring field service it promised its accounts left no trace, its representatives worked from memory and paper, and the central claim behind the product — that treated inventory sells faster — was a sales argument rather than a measurement.

Our team built a platform that starts and ends on a phone. A representative arrives at an account, and the app identifies where they are from the device's coordinates. They scan vehicle identification labels with the camera and the vehicle details arrive decoded. They work through a consistent inspection for each vehicle, photograph it, and sign off on screen — with everything saved continuously to the device, so a lost connection costs nothing. On submission, the platform composes a branded inspection report with the photographs and signature embedded, stores it, emails it to the account, and records whether it was delivered and opened. If the connection was not there, the submission waits in a queue the representative can see and push later.

Behind that sit the parts a distributor network requires: territory and postcode mapping, tenant-isolated data across businesses that are commercial peers, per-distributor analytics dashboards, consumable stock counting with prior-visit context, and a reporting layer linking inspected vehicles to public listing data so the programme's effect on time-to-sale can be measured. One design decision underpins the rest — storing inspection results as flexible data rather than fixed columns — which let the mobile workflow expand substantially years after the backend was written, with no migration and no coordinated rollout across a field fleet nobody controls. In field-service software, that kind of decision is worth more than any feature on the list.

01 — Questions

asked about this kind of project

How do you build a mobile app that works without a connection?

Treat offline as the normal case rather than the error case. Drafts save to device storage on every change, not on navigation. Failed submissions are archived as files on the device rather than held in memory. The queue is surfaced when the app opens, and replay is something the user triggers and can see the result of. The temptation is to hide all of this behind silent background sync, and that is usually a mistake in field work: a user who cannot verify that their work was delivered will keep a parallel paper record, which defeats the entire point of the app.

How do you handle very large mobile submissions containing photographs?

Compress at the source and design the payload for the worst connection you expect. Cap image quality and dimensions on the device before the data enters the payload, set body limits at the API to match the realistic maximum rather than a default, and record the payload size against each submission so that field failures can be correlated with weight rather than guessed at. If the submission is genuinely enormous, chunking is the next step — but on-device compression solves most of it far more cheaply.

How do you keep a mobile workflow evolvable when you cannot force devices to update?

Store variable-shape data as data. If every checklist item is a database column, every workflow change is a migration plus a coordinated release, and in a distributed field fleet that coordination never happens cleanly. Persisting per-item results as key/value entries lets a newer client send an expanded set that older servers accept unchanged. Pair it with a single, clearly marked translation point for legacy representations, and give that shim a defined removal condition so it does not become permanent.

Should a field app identify the location automatically or let the user choose?

Automatically, with a fallback chain and an override. Match against places the user has been before, then against known locations nearby, then fall back to manual entry. The user confirms rather than searches. A directory picker seems safer to build but it is slower in practice, and speed on a forecourt is what determines whether the workflow is used properly or rushed through.

How do you generate and deliver client-facing reports automatically?

Compose server-side, store in object storage, and deliver through a templated transactional email provider. Two details matter more than the generation itself. Use a content-addressed storage key derived from the submission, so a replayed offline submission overwrites rather than duplicates. And capture the provider's delivery events by webhook, joined back to the originating record — otherwise "we sent the report" is the last thing anyone knows about it.

How do you isolate tenants when they are competing businesses?

Enforce it in the data access layer rather than in the interface, scope every query to the authenticated identity's tenant, and make the cross-tenant view an explicit privileged role rather than an absence of filtering. On a platform shared by independent businesses holding adjacent territories, visibility is a commercial matter, not just a technical one — which also means the mechanism that establishes tenancy deserves review in its own right, not just the queries that use it.

Why add GraphQL alongside an existing REST API rather than replacing it?

Because the REST contract is what a deployed mobile fleet depends on, and that fleet cannot be updated on demand. Adding a separate read surface over the same data lets reporting and analytical consumers evolve at their own pace without any risk to the workflow that generates the data in the first place. Replacement is the right call when both sides can move together; here they could not.

What do you build first in a field-service platform?

The capture-to-artefact path, end to end, for one visit — capture, submit, generate, deliver. Everything else is reporting on data you do not have yet. Getting that path reliable under bad conditions is what determines whether the platform is adopted, and adoption is what determines whether any of the reporting is worth building.

03 — Similar project?

describe what is different about yours

Build yours.

Tell me what exists, what you need and the deadline. Fixed price for a defined scope, or hourly from $10 with a written estimate first.

Ahmedabad, India · IST (UTC+5:30) · --:-- IST · Mon–Fri 09:00–18:00 IST · US & EU overlap daily

No newsletter, no CRM. Just a reply.