Mark Lowel Montealto — Full Stack Developer & DevOps Engineer

Mark Lowel
Montealto

Full Stack Developer & DevOps Engineer

Projects

Angular Developer · Sep–Nov 2024 · Outdoor Inspection Services

·

7 min read

Outdoor Inspection System

Angular-powered field inspection dashboard with Google Maps route optimization for OOH ad verification

AngularTypeScriptNode.jsPostgreSQL
Outdoor Inspection System screenshot
Visit live site

Problem

Out-of-home advertising verification depends on human inspectors physically visiting billboard sites, digital screens, and programmatic display panels to confirm campaigns are running correctly. At OIS, field teams were managing dozens of assigned sites per day across sprawling urban areas using a combination of spreadsheets, phone calls, and manual map lookups. Planning an efficient route through ten or more scattered locations took significant time before a single inspection began. Once in the field, inspectors had no structured way to log findings — photos, notes, and timestamps were captured ad hoc and compiled into reports after the fact. Campaign managers at OIS had no live visibility into inspection progress, making it difficult to surface issues to clients like IKEA or Dyson while a campaign was still running.

Solution

I built a web-based field inspection management platform using Angular that centralises the entire inspection workflow into a single, map-driven interface. Inspectors open the dashboard to see all their assigned sites plotted on a Google Map, with the platform calculating an optimised driving route between them. At each site, they complete a structured inspection form — capturing ad condition, display quality, timestamp, and photo evidence — which submits directly to the OIS backend via REST API. Campaign managers get a live view of inspection progress as data flows in from the field, eliminating the end-of-day reporting bottleneck. The platform is fully responsive, designed for use on a smartphone in the field, not just a desktop in an office.

Architecture

The platform is a single-page application built in Angular, consuming a REST API provided by the OIS backend team. The frontend handles three main concerns: authentication, map rendering, and inspection data entry.

On load, the app authenticates the inspector via a JWT-based login flow and fetches their assigned site list for the day. Each site carries geocoordinates that are passed to the Google Maps JavaScript API to render markers on the map canvas. When an inspector requests route optimisation, the app calls the Google Directions API with all site coordinates as waypoints and renders the calculated driving path as a polyline overlay.

Inspection forms are Angular reactive forms with field-level validation — required fields, photo attachment via the device camera, and a GPS timestamp captured at submission time. Submitted reports are sent to the REST API using Angular's HttpClient, with RxJS operators handling retry logic for unreliable mobile connections. The entire layout uses a responsive CSS grid that collapses to a single-column view on mobile, keeping map and form accessible on small screens without horizontal scrolling.

Technologies Used

  • Angular — chosen for OIS's existing frontend ecosystem and its component architecture, which made it straightforward to isolate the map view, the site list, and the inspection form into independently testable units.
  • TypeScript — enforced strict typing across API response shapes and form models, catching integration mismatches at compile time rather than at runtime in the field.
  • Google Maps JavaScript API (Maps + Directions services) — provided geocoding, marker rendering, and route calculation. The Directions API's optimizeWaypoints feature handled multi-stop routing without requiring a custom algorithm.
  • RxJS — used throughout for managing asynchronous data flows, combining live API streams with user interactions in a composable, predictable way.
  • Angular HttpClient — connected the frontend to the OIS backend, with interceptors handling auth token injection on every outgoing request.

Challenges

Rendering many map markers without jank

In dense urban markets, an inspector's daily list could include 30 or more sites across a city. Rendering each site as an individual Google Maps Marker DOM element created noticeable lag when panning and zooming, particularly on mid-range Android devices common among field staff. I solved this by switching from the standard google.maps.Marker to AdvancedMarkerElement with a clustering strategy: sites further than a set zoom threshold are grouped into cluster markers showing a count, expanding into individual pins as the inspector zooms into their current area. This kept the map fluid regardless of site count.

Usable UI in field conditions

A dashboard that looks clean on a desktop monitor can be nearly unusable outdoors — bright sunlight washes out low-contrast text, small tap targets frustrate gloved or cold hands, and inspectors rarely have a free hand to navigate complex menus. I prioritised large touch targets (minimum 48×48 px), high-contrast colours legible in direct sunlight, and a single-action-per-screen flow for the inspection form. I also implemented optimistic UI updates: the form shows success immediately while the API call completes in the background, so a slow mobile connection does not stall the inspector at the site.

Implementation

The map component is an Angular standalone component wrapping the Google Maps JavaScript API. On initialisation it imports the Maps and Marker libraries via @googlemaps/js-api-loader, avoiding a blocking script tag in the HTML. Site coordinates from the API response are mapped to AdvancedMarkerElement instances and clustered using @googlemaps/markerclusterer.

Route optimisation is triggered by a toolbar button. I collect all unvisited site coordinates as Directions API waypoints, set optimizeWaypoints: true, and render the returned overview_polyline as a google.maps.Polyline. The ordered waypoint list from the response re-sorts the site list panel so it matches the driving sequence.

const result = await directionsService.route({
  origin: inspectorLocation,
  destination: sites[sites.length - 1].coords,
  waypoints: sites.slice(0, -1).map(s => ({
    location: s.coords,
    stopover: true,
  })),
  optimizeWaypoints: true,
  travelMode: google.maps.TravelMode.DRIVING,
});
const ordered = result.routes[0].waypoint_order.map(i => sites[i]);

The inspection form is a reactive FormGroup with validators for required fields, a file input for camera photos (converted to base64 for the API payload), and a hidden timestamp field populated on form initialisation. On submit, HttpClient.post() is wrapped in an RxJS retry(2) pipe — giving intermittent connections two automatic retries before surfacing an error state.

Screenshots

Outdoor Inspection System — map dashboard showing assigned inspection sites as markers across a city

Outdoor Inspection System — mobile inspection form for submitting site condition, photo evidence, and notes

Results

Centralising the inspection workflow into a single platform removed the manual coordination overhead that previously started and ended every field shift. Inspectors began each day with a pre-optimised route rather than planning their own, which reduced drive time between sites and allowed more inspections to be completed per shift. Structured form submissions meant inspection data arrived at the OIS platform in a consistent, queryable format — replacing the mixed-quality notes and photos that had previously required manual compilation into client reports.

Campaign managers at OIS gained real-time visibility into which sites had been inspected and which were pending, allowing them to proactively flag delivery issues to clients during a live campaign rather than in a post-campaign summary. For a platform that has verified over $1 billion in media investment for brands like IKEA, Dyson, and Disney, faster and more reliable field data directly strengthens client trust.

Lessons Learned

The biggest shift in thinking this project required was designing for the environment, not the device. A responsive layout is necessary but not sufficient for field workers — I had to consider physical conditions (sunlight, one hand occupied, outdoor noise) that never come up when building office-facing dashboards. Testing on an actual Android phone outdoors, rather than just resizing a browser window, surfaced issues that no emulator would have caught.

I also learned to be more deliberate about handling unreliable connectivity early in the design process. Bolting on retry logic and optimistic updates after the fact is harder than designing for intermittent connectivity from the start. On future field-facing projects I would define the offline/retry strategy before writing a single API call.

FAQ

How long did this project take?

The engagement ran from September to November 2024 — approximately three months. That covered requirements gathering with the OIS team, design and build, and iterative refinement based on feedback from actual field inspectors during a pilot period.

What was your role on the project?

I was the Angular developer responsible for the frontend application end-to-end: architecture decisions, component development, Google Maps integration, API integration, and mobile responsiveness. The REST API and backend were handled by the OIS engineering team.

Is the source code publicly available?

The codebase is proprietary to Outdoor Inspection Services and is not publicly available. The live platform is accessible to OIS clients and their field teams at oisooh.com.

What was the hardest technical problem you solved?

Getting the map to perform well on mid-range mobile hardware with 30+ sites was the most challenging part. Switching from standard Marker objects to AdvancedMarkerElement with clustering made a significant difference, but it required understanding the Google Maps rendering lifecycle more deeply than a typical integration would demand.