HomeCase studiesA Mobile Field-Service Job Ordering App Built...

Case study · London, United Kingdom

A Mobile Field-Service Job Ordering App Built on a Managed CRM Platform

Industrial field services

A field-services provider already ran its operations on a managed CRM platform. Its customers, however, still ordered work by phone — describing sites by name, and then waiting without visibility for someone to call back with a status. Our team built a customer-facing mobile application directly on top of that existing platform, with no intermediate backend: customers pick the exact work site on a satellite map, schedule the job, and track its status with push notifications. Delivered as a cross-platform React Native app against purpose-built services on the client's own platform.

Industry
Industrial field services
Solution
A cross-platform customer-facing mobile application, built as a client of the customer's existing managed CRM platform rather than against a newly built backend.
Platforms
Android · iOS · Cross-platform
Stack
React Native · React · JavaScript · Firebase · OAuth · Redux
Location
London, United Kingdom · delivered remotely
Role
Engineering, with the team behind for mobile and QA

Delivered remotely for a business based in London, United Kingdom. Names withheld by agreement.

Project Overview

Industry: Industrial field services.

Type of solution: A cross-platform customer-facing mobile application, built as a client of the customer's existing managed CRM platform rather than against a newly built backend.

Business context: The provider's work already lived in a CRM: customer accounts, the companies they belong to, the physical sites where work is performed, and the job records themselves. What was missing was a way for the provider's customers to interact with any of it. Ordering work meant a phone call. Confirming a site meant describing it. Checking status meant calling again. The provider did not want a second system of record, and did not want to pay to build and operate one.

General users: Customer contacts at the provider's client companies. Provider-side administration and job status management remain in the existing platform's own back office.

General purpose: To let a customer raise a service job against a precisely identified work site from a phone, and to give them visibility of that job's status without a phone call — while leaving the provider's existing system of record entirely intact.

The Business Challenge

Ordering work by phone is slow, and it is imprecise. A customer describes a site; a coordinator interprets the description; a crew is dispatched. Every step is an opportunity for the wrong location to end up on the work order.

Sites are numerous, remote and similarly named. A customer company may hold a very large number of registered work locations, many with near-identical names distinguished only by internal codes. A dropdown of names is not a usable interface for that problem, and it is not a reliable one.

Location data in an operational CRM is rarely clean. Coordinates in a system that has grown over years arrive as free text, in inconsistent formats, and are frequently missing altogether. Any map-based interface has to survive that reality rather than assume it away.

Status is invisible once the request is made. After a job is ordered, the customer has no idea whether it is scheduled, underway or finished. The result is repeat calls to the provider asking exactly that.

The provider had no appetite for a second backend. The CRM was already the system of record. Building a parallel API tier would have duplicated the data model, doubled the operational surface, and introduced a synchronisation problem the business did not previously have.

Not every customer should see every job. Access is scoped by which companies a customer contact is authorised against — and that authorisation is a commercial decision made by the provider, not something a user can grant themselves.

Connectivity at the point of use is poor. Work sites are remote by definition. An application that needs a fast round trip for every interaction is an application that does not get used in the field.

Our Approach

Build on the platform, not beside it. We chose to have the mobile client authenticate against and read from the customer's existing managed CRM platform directly, with no backend of our own in between. For a product of this scope that removes an entire tier of build, hosting and operational cost — and, more importantly, it means record visibility is enforced by the platform's own permission model rather than by authorisation code we would have had to write, test and defend independently.

Shape the server responses around the screen, not the data model. Rather than having the app assemble a screen from many generic record queries, we specified a small set of purpose-built services on the platform that return exactly what a given screen needs in a single response. The job-creation screen, for example, bootstraps from one round trip that carries the customer's companies, the sites belonging to each, and the available scheduling options together. On a slow link at a remote site, the difference between one request and six is the difference between an app that is used and one that is not.

Prefetch the site catalogue once, and be honest with the user about it. Site data is large but changes slowly, so the app retrieves it on first run and persists it to the device. Every subsequent site search and map render happens against local state. We made the first-run wait an explicit, explained step rather than an unexplained spinner, because a user who understands why they are waiting waits.

Make the map the primary way to choose a site. Site selection happens on a satellite map with every eligible location pinned, alongside name search for users who already know what they want. Choosing a work location by looking at it removes the single most expensive error in the process.

Assume the location data is dirty. Coordinate parsing tolerates multiple delimiter formats, discards values that are not numeric, and where a chosen site has no usable coordinates at all the interface says so plainly instead of failing silently or crashing the map.

Replace status chasing with push. Job status changes are pushed to the device and deep-link straight into the relevant job, in all three application states — running, backgrounded, and launched cold from the notification tray.

Represent the approval gate as a first-class state. Because access is granted by the provider, a newly registered user is not an error condition and not an empty screen. They get a screen that explains what has been requested and what happens next.

The Solution

Platform-backed sign-in. Users authenticate against the client's existing platform, so there is no separate user directory to maintain and no second set of credentials to manage.

Self-service registration with a controlled access gate. A customer contact can register themselves, then search for and select the companies they work with and submit a link request. Job access opens only once the provider approves it — and the app explains that state rather than presenting a broken experience.

Company type-ahead search. Companies are found by typing, with matches returned from the platform and selections shown as removable chips, so multi-company customers can request all their relationships in one action.

One-call screen bootstrap. The job-creation screen loads its companies, sites and scheduling options in a single request, keeping the most latency-sensitive screen in the app to one round trip.

Prefetched, locally persisted site catalogue. The user's full site list is retrieved once and stored on the device, so search and map rendering are instant and do not depend on connectivity.

Map-based site selection. A full-screen satellite map with every eligible site pinned, plus an overlaid name search that filters as the user types. The site is chosen by looking at it.

Job scheduling. A date picker constrained to future dates, a time window chosen from provider-supplied options, the company and site, and a free-text description — assembled and submitted as one job request.

Job list with live status. All jobs visible to the user, showing site, company, scheduled time, status and a description preview, with pull-to-refresh.

Job detail with site map. A read-only view of every field on the job alongside a lightweight map pinned to the work location, so the user can confirm at a glance that the right site was booked.

Push notifications with deep linking. Status changes arrive as notifications and open directly on the relevant job, whether the app was running, backgrounded or closed.

Profile and session management. User details and photo drawn from the platform's own user record, with sign-out clearing session state and de-registering the device from push delivery.

State restoration. Application and navigation state persist across launches, so the app returns the user to where they left off.

Key Features

Direct managed-platform integration with no intermediate backend The client authenticates and operates against the customer's existing CRM platform, inheriting its identity model and record-level permissions instead of reimplementing them in a new tier.

Screen-shaped aggregate services Purpose-built endpoints on the platform return complete screen payloads in one response, keeping the most latency-sensitive interactions to a single round trip on poor connections.

Prefetched, device-persisted site catalogue The full site list is retrieved once on first run and held locally, making subsequent search and map rendering independent of network conditions.

Map-first work-site selection Satellite-map selection with pinned sites and overlaid name search, addressing the costliest error in the manual process — dispatching to the wrong location.

Resilient handling of imperfect location data Multi-format coordinate parsing with graceful degradation, and clear user-facing messaging where a site carries no usable coordinates, rather than a silent failure or a broken map.

Approval-gated onboarding as an explicit state Self-service registration and company linking, with the pending-approval period presented as an explained, deliberate step in the flow.

Multi-company type-ahead linking Chip-based company search and selection, so customers working across several client companies request all their access at once.

Push-based status updates with deep linking Job status changes delivered to the device and routed straight to the relevant record from any application state, replacing status-chasing phone calls.

Persisted application and navigation state The app rehydrates its full state on launch, returning users to their previous position rather than to a cold start.

Technical Architecture

Mobile client. A cross-platform React Native application with a stack navigator wrapping a two-tab structure — jobs and account — with navigation state held in the application store and persisted, so the app restores to its previous position. Screens are backed by a predictable unidirectional state layer with asynchronous middleware handling all platform communication.

Integration layer. A thin service module owning HTTP concerns, endpoint composition and token handling. Every outbound call carries a bearer token obtained from the platform's own authorisation service. Where a token has expired mid-session, the layer re-establishes the session and replays the original request so the user is not interrupted during a task.

Server-side services. Rather than generic record CRUD, the platform exposes a small set of operations written specifically for this application: fetch the jobs a user may see, bootstrap the job-creation screen, retrieve a company's sites, create a job, register a customer, and search and link companies. Each returns a payload shaped for the screen that consumes it.

Data and authorisation tier. Entirely the client's existing managed CRM platform. It remains the single system of record for customers, companies, sites, jobs and job status, and its own permission model — not application code — determines which records a given user can see.

Mapping layer. A native map component rendering satellite imagery with pinned site markers, using an interactive full-screen map for selection and a lightweight non-interactive map for read-only confirmation views.

Notification layer. A managed push service, with the device registered against the platform's own mobile device registry at sign-in and de-registered at sign-out, and three distinct client-side handling paths covering foreground, background and cold-start delivery.

Local persistence. Device storage holding the prefetched site catalogue and the rehydrated application state, so the app is usable and fast on first paint and resilient to poor connectivity.

Flow: Mobile app → Platform authorisation service (bearer token) → Screen-shaped services on the managed CRM platform → Platform data and permission model → Push notifications back to the device

Technology Stack

Category Technology
Mobile framework React Native (cross-platform iOS and Android)
UI language JavaScript / React
State management Redux with thunk middleware for asynchronous operations
State persistence Store rehydration from device storage
Navigation Stack and tab navigators, with navigation state held in the application store
HTTP Promise-based HTTP client with bearer-token authorisation
Backend platform The client's existing managed CRM / low-code cloud platform
Server-side services Purpose-built REST operations authored on that platform
Authentication OAuth 2.0 bearer tokens issued by the platform's authorisation service
Authorisation The platform's native record-level permission model
Mapping Native map components with satellite imagery, interactive and lite-mode rendering
Push notifications Firebase Cloud Messaging, with devices registered in the platform's own device registry
Local storage Device key-value storage for the site catalogue and session state
Input components Date picker, chip-based type-ahead selector, pickers and modal composition

Technical Challenges & Solutions

Challenge Our Approach
A CRM object graph requiring many chained requests to render one mobile screen Purpose-built aggregate services authored on the platform that return complete, screen-shaped payloads. The job-creation screen loads its companies, sites and scheduling options in a single round trip rather than six.
Site catalogues too large to query on every interaction, over connections that are poor by definition A one-time prefetch on first run, persisted to device storage, with all subsequent search and map rendering served from local state. The wait is presented to the user as an explained step rather than an unexplained delay.
Location coordinates stored as inconsistent free text, and frequently absent Defensive parsing that accepts multiple delimiter formats and discards non-numeric values, combined with explicit user-facing messaging where a chosen site has no usable coordinates — so bad data produces a clear message, not a broken map.
Rendering large numbers of map markers without degrading the interface A bounded marker set on the interactive selection map, and a non-interactive lightweight map on read-only confirmation views where interactivity adds nothing.
Platform session tokens expiring in the middle of a user's task Transparent session re-establishment in the integration layer with replay of the original request, so expiry is invisible to the user rather than an interruption that loses their work.
Notifications needing to open the right record from any application state Three explicit handling paths — application running, application backgrounded, application launched cold from the notification tray — each resolving the notification payload to the correct record before navigating.
Access granted by the provider, not by the user, leaving new registrants in limbo The pending-approval period modelled as a first-class application state with its own screen and explanation, rather than as an empty list or an error.
Choosing the correct work site from many similarly named locations Site selection on a satellite map with pinned locations, alongside name search — so the choice is made visually, where near-identical names are unambiguous.

Security & Reliability

Platform-issued authentication. Users authenticate against the client's own managed platform. There is no separate credential store to maintain, and account lifecycle — creation, suspension, removal — is governed centrally by the platform rather than by the application.

Authorisation delegated to the system of record. This is the most important reliability property of the architecture. Which jobs and which sites a user can see is determined by the managed platform's own record-level permission model, not by conditional logic in the mobile client. Access control lives in one place, is administered by the people who already administer it, and cannot be circumvented by a modified client.

Commercially controlled access grants. A customer contact cannot self-grant access to a company's records. Linking is a request, approved by the provider through its existing back office, and unapproved users have no visibility of job data.

Bearer-token session handling. Every request to the platform carries a token, with session renewal handled in a single integration layer rather than duplicated across screens, and session state cleared and the device de-registered from push delivery at sign-out.

Single system of record. Because no parallel datastore was introduced, there is no synchronisation to drift and no possibility of the application and the business disagreeing about the state of a job. The CRM is authoritative, always.

Graceful degradation on imperfect data. Missing or malformed location data produces an explicit user message and a usable screen rather than a crash — important in an operational dataset that will never be perfectly clean.

Platform-inherited operational reliability. Availability, backup, disaster recovery and patching of the data tier are the responsibility of the managed platform vendor, under the client's existing agreement, rather than an operational burden added by this project.

Scalability & Performance

No backend tier to scale. The architecture deliberately introduces no server infrastructure of its own. Capacity, availability and scaling of the data and service tier are absorbed by the client's existing managed platform under an agreement it already held.

One round trip on the critical screen. Aggregate services collapse what would be several dependent requests into one, which matters disproportionately on high-latency mobile connections at remote locations.

Local-first site search. After the initial prefetch, site search and filtering run entirely against device-resident state, so the interaction is instant and unaffected by connectivity.

Bounded map rendering. Marker sets on the interactive map are capped, and read-only maps use a lightweight non-interactive mode, keeping map screens responsive on lower-end devices.

Push rather than polling. Job status reaches the device by notification rather than by repeated client requests, which keeps both battery consumption and platform request volume low.

Efficient list rendering. Job and site lists use virtualised rendering, so list length does not translate into memory or scroll cost.

Fast restoration. Persisted application state means the app renders meaningful content on launch without waiting for the network.

Business Outcomes

  • Work is ordered from a phone rather than over one, removing the coordinator from the middle of every routine service request.
  • The work site is selected visually and unambiguously, addressing the most expensive failure in the manual process — a crew arriving at the wrong location.
  • Customers can see job status without calling, replacing status-chasing enquiries with a list they can check themselves and notifications they receive automatically.
  • The provider gained a customer-facing channel without gaining a second system, because the existing CRM remained the single system of record throughout.
  • Access remains a commercial decision, with the provider approving which customers see which companies' work through its existing back-office process.
  • No new backend infrastructure was introduced, so the project added no hosting, scaling or operational responsibility to the business.
  • The application is usable where the work happens, with the site catalogue held locally so poor connectivity at remote locations does not prevent a job being raised.

Why it worked

The instinct on a project like this is to build a backend. There is already a system of record, it is already the source of truth for every entity the mobile app needs, and it already enforces exactly the access rules the business wants — and yet the default reflex is to put a new API tier in front of it, duplicate the model, and inherit a synchronisation problem that did not previously exist.

We took the other path deliberately. The mobile client talks to the client's existing managed platform directly, and the only server-side work we specified was a small set of services shaped around the screens that consume them. That decision is what kept the project small, and it is the reason record visibility is enforced by the platform's permission model rather than by authorisation code somebody has to maintain and prove correct. It is also the reason the business ended up with one system of record instead of two.

The engineering judgement that mattered after that was mostly about the field. Operational location data is never clean, so the map had to survive missing and malformed coordinates and say something useful when it found them. Connectivity at remote sites is poor, so the site catalogue is fetched once and lives on the device, and the most important screen loads in a single request. And the approval gate that governs access is a real commercial step, so it is a screen with an explanation rather than an empty list.

Our team builds cross-platform mobile applications on top of managed platforms, low-code backends and existing enterprise systems — including the parts that are unglamorous: session lifecycle against a platform we do not control, offline-tolerant catalogues, geospatial data that arrives in whatever shape years of operational use has left it in, and notification handling that works from a cold start and not just when someone is watching.

Final Summary

A field-services provider ran its business on a managed CRM platform, and its customers ran their side of the relationship on the telephone. Ordering work meant describing a site to a coordinator and hoping the right one made it onto the work order. Checking status meant calling to ask.

Our team built the customer-facing half as a cross-platform mobile application sitting directly on the platform the business already had. No second backend, no duplicated data model, no synchronisation problem — the CRM stayed the single system of record, and its own permission model, not application code, decides what each user can see. The only server-side work was a handful of services shaped around the screens that consume them, so the job-creation screen bootstraps in one request instead of six.

For the customer, the change is concrete. The work site is chosen by looking at it on a satellite map rather than describing it down a phone line. The full site catalogue is fetched once and lives on the device, so search is instant even where the signal is not. Jobs are scheduled with a date, a time window and a description, and their status arrives as a notification that opens straight to the record. And because access is granted by the provider rather than claimed by the user, the approval step is an explained state in the app rather than an empty screen.

It is a small application by design. The interesting decision was what not to build.

01 — Questions

asked about this kind of project

Can you build a mobile app on our existing CRM without building a new backend?

Usually, yes — and often you should. If the CRM is already the system of record and already enforces the access rules you want, adding an API tier in front of it duplicates the data model and creates a synchronisation problem you did not previously have. The mobile client can authenticate against the platform and call services published on it directly. The work then shifts to designing those services well, which is a much smaller job than building and operating a backend.

What is the catch with going directly to a managed platform?

Three things. You are bound by the platform's authentication model, its API rate limits and its response shapes, so you design within those constraints rather than around them. You have less room to optimise a slow query, because the query planner is not yours. And versioning is harder — the client and the platform services have to move together. For a focused application on a platform the business already runs, those trade-offs are usually worth the tier you avoid building.

Why shape API responses around screens instead of around data?

Because mobile latency is dominated by round trips, not payload size. A screen that needs six dependent requests to render is slow on a good connection and unusable on a bad one. An endpoint that returns everything one screen needs in a single response is less "pure" as an API design, but it is the difference between an app people use in the field and one they abandon. Purpose-built read operations are the right pattern for a mobile client with a known, finite set of screens.

How do you handle location data that is incomplete or inconsistently formatted?

You assume it is broken and design for that. Operational datasets accumulate coordinates entered by different people, in different formats, over years, with many records simply missing them. Parse permissively across the formats you actually see, discard what cannot be interpreted rather than passing it to the map, and — most importantly — tell the user plainly when the record they selected has no usable location. Silent failure on a map is worse than no map, because the user cannot tell the difference between "no data" and "wrong data".

How should a mobile app work where connectivity is poor?

Identify the data that is large, changes slowly and is needed constantly — a site or asset catalogue is the classic case — and fetch it once, persist it on the device, and serve every subsequent interaction locally. Keep the network on the critical path only for the things that genuinely must be current. And be transparent about the initial download: an explained wait with a reason is tolerated, an unexplained spinner is not.

How do you handle push notifications reliably across platforms?

Treat the three application states as three separate problems, because they are. A notification arriving while the app is in the foreground, one that resumes a backgrounded app, and one that launches the app cold from the tray each follow a different code path, and each has to resolve the notification payload to a record and navigate there. Register the device at sign-in and de-register it at sign-out, so notifications do not follow a user to a device they no longer use.

How is access controlled when the backend is a platform you do not own?

That is the strongest argument for this architecture. Record-level permissions are enforced by the platform, not by the mobile client, so a modified or decompiled client cannot see records its user is not entitled to. Where access is a commercial decision — which customers may see which companies' work — that grant belongs in the provider's existing back-office process, with the app representing the pending state honestly rather than pretending access exists.

Is this approach suitable for a first version, or only for small products?

It is at its best for a focused first version on a platform the business already runs, where speed to a working product matters more than architectural independence. It scales further than people expect, because the platform absorbs the capacity question entirely. The point at which you outgrow it is usually the point at which you need logic the platform cannot express, integrations it cannot reach, or performance its query model cannot deliver — and at that point you introduce a service tier deliberately, for a reason, rather than by default at the start.

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.