Delivered remotely for a business based in Denver, United States. Names withheld by agreement.
Project Overview
Industry: Property and building inspection services — proptech and field-service operations.
Type of solution: A multi-tenant SaaS platform: a REST API with a documented interface, an administrative back office, a company-level web panel, and an offline-capable cross-platform mobile application for field staff.
Business context: An inspection report is a formal document used in property transactions. It has to be professionally worded, appropriately cautious, and consistent between inspectors at the same firm — because buyers, sellers and agents read it, and occasionally it is examined long after the fact. The capture is physical and photographic; the deliverable is narrative and legal in tone. That gap between what an inspector sees and what an inspector has to write is where the working day disappears.
General users: Inspectors in the field, inspection firm owners and administrators managing inspectors and workload, platform administrators maintaining templates and content, and external recipients — clients and agents — who receive reports and correspond about them.
General purpose: To compress the distance between observing a property and delivering a defensible report, without removing the professional's judgement from the loop.
The Business Challenge
Report writing takes as long as inspecting. The site visit is the visible work; the write-up is the invisible half, and it usually happens in the evening. Turnaround suffers, and so does the inspector.
Consistency does not survive scale. Two inspectors describing the same defect produce different reports. As a firm grows, the variation grows with it, and the firm's reputation is carried by whichever report the client happens to read.
The wording carries risk. Inspection narrative has conventions for a reason: it should describe what is visible, avoid speculation about what is hidden, avoid pricing, avoid code and legal claims, and recommend evaluation appropriately. Free-form writing under time pressure is exactly where those conventions slip.
Properties do not have connectivity. Crawl spaces, basements, attics and rural sites. An application that assumes a network loses an inspector's work, and losing an inspector's work once ends the adoption conversation.
Inspections are photograph-heavy. Hundreds of images per job, from phones producing modern formats that servers do not handle natively, uploaded over cellular connections of unpredictable quality.
Every firm inspects slightly differently. Sections, sub-sections, repeated systems, the questions asked of each component, the severity vocabulary — all of it varies by firm, by property type and by jurisdiction. Hardcoding a template produces a product that fits one customer.
The report is not the end of the relationship. Clients reply with questions. Those replies arrive by email and phone, disconnected from the inspection they concern.
AI output cannot simply be trusted into the record. A model can describe a photograph well and still return an answer that does not correspond to a configured option, or a severity value the system does not recognise, or a claim that goes beyond what is visible. A platform that writes model output straight into a professional deliverable is not a product — it is a liability.
Our Approach
Put the AI inside the capture flow, not beside it. The inspector photographs a component, optionally adds a short note about what they observed, and asks for a draft. The model receives the images and the note and responds with structured answers plus a narrative observation, a recommendation, a location and a severity indication. Nothing about the flow requires leaving the section being inspected.
Make the model answer the customer's schema, not a generic one. Sections, sub-sections, repeated sub-systems, fields, option lists, severity vocabularies and colour coding are all administrator-configured data. The request sent for analysis is therefore generated from the live schema at the moment of the request, and the response is validated back against that same schema — free-text answers are matched onto listed options where they genuinely correspond, severity values are normalised to configured options and their colour codes, and anything unresolvable is surfaced rather than silently accepted.
Keep the professional accountable. Every AI-produced value is written into the form marked as a suggestion. The inspector reads it, edits it, and accepts it before it becomes part of the inspection. The platform drafts; the inspector signs.
Centralise the instruction and guardrail layer. The rules governing how findings are written — tone, length, what must not be asserted, how severity is chosen, how output is formatted — are managed in one place rather than scattered through the code, so they can be reviewed and revised as a product decision.
Stream the result. Multi-image analysis takes long enough to feel like a failure on a phone. The platform streams the response as it is produced and renders completed sections of the result progressively, so the inspector sees work happening rather than a spinner.
Record every inference with its inputs. Each analysis stores the field set it was asked about, the image count, the inspector's note, the raw exchange, the parsed result, token consumption and any error. That gives cost visibility, an audit trail, and a way to reproduce and diagnose any result that looks wrong.
Build the mobile application offline-first, seriously. Writes land in local state and on-device storage immediately, enter a durable queue, and drain automatically when connectivity returns — with retry logic designed so a retried save can never create a duplicate record.
Treat media as a pipeline. Compression on the device, format conversion and orientation correction on the server, thumbnail generation, immediate local write with background synchronisation to private cloud storage, and time-limited signed access issued in batches.
Close the loop after delivery. Reports are shared by email or message, and replies from recipients are parsed back into the in-app conversation for that inspection — so a client who never installs the application still stays in one thread.
The Solution
Configurable inspection templates. Inspection types, sections, sub-sections and dynamically created repeated sub-systems, each with its own field set. Fields support option lists, multi-select, severity/condition flags with colour coding, free text and media, with per-field control over ordering, mandatory status and whether the field participates in AI-assisted or manual capture.
Guided inspection creation. A multi-step flow covering contacts, property address and details, scope selection and scheduling, with calendar synchronisation for the booked visit.
On-site capture. Section-by-section progress with completion status, photograph capture with on-device annotation, reusable saved comment library, and a manual mode alongside the AI-assisted mode.
AI-assisted observation drafting. Photographs and an optional inspector note produce structured field answers plus a narrative observation, recommendation, location and severity — validated against the configured schema, presented as suggestions, and streamed as they are generated.
Inference audit log. Every analysis is stored with its inputs, outputs, token consumption and status, with an administrative view over the history.
Offline-first field operation. Local persistence, a durable sync queue, network monitoring, automatic drain on reconnect, and duplicate-safe retry.
Media pipeline. Client-side compression, server-side format conversion and orientation correction, resizing and thumbnails, private cloud storage with batched time-limited signed access, and background synchronisation with per-record status.
Report composition and PDF generation. The inspector chooses which sections and which classes of content to include — property details, inspector narrative, AI-assisted narrative, photographs, and each severity class — and the platform renders a paginated PDF with repeating branded header and footer, controlled page breaks and embedded imagery.
Report delivery and sharing. Delivery by email to one or many recipients or by message, with a signed link for viewing, and a log of what was sent to whom.
Client messaging. Conversations tied to an inspection and its contacts, delivered in real time over websockets, with push notifications and unread tracking — and inbound email replies parsed into the same thread.
Multi-tenant firm management. Firm accounts with their own web panel, inspector seat management and invitations, and subscription state including seats, billing interval and scheduled changes.
Administrative back office. Users, firms, inspections, the full template builder, reference catalogues, content pages, dashboard tiles, branding and integration settings, and a centrally editable catalogue of every user-facing message in the system.
Key Features
Schema-driven AI analysis The analysis request is generated from the administrator-configured field set for the section being inspected, so the model answers the questions this customer actually asks — not a fixed set built into the code.
Validated, coerced model output Responses are checked back against the live schema: free-text answers are resolved onto listed options where they correspond, severity values are normalised to configured options and colour codes, and unresolved values are surfaced rather than silently written.
Suggestion-first, professional-accepted Every AI-produced value is flagged as a suggestion and requires inspector review and acceptance before it enters the record.
Streaming analysis with progressive rendering Results stream as they are produced, and completed structured blocks render as soon as they are available, so long multi-image analysis stays usable on a phone in the field.
Full inference audit and cost visibility Each analysis is persisted with its inputs, its raw and parsed outputs, token consumption and status — for reproducibility, diagnosis and spend visibility.
Per-field AI governance Administrators decide, field by field, whether the model may answer at all, and set separate mandatory rules for AI-assisted and manual capture.
Offline-first capture with duplicate-safe sync On-device persistence and a durable queue keep work safe through app termination and network loss, with retry logic that promotes a possibly-delivered create into an update rather than risking a second record.
Non-destructive template changes Changing which sections an inspection covers preserves the work already captured, rather than regenerating the structure and taking comments and media with it.
Configurable PDF report generation Report scope and content classes are chosen per report, and rendered with repeating branded header and footer, controlled pagination and embedded photography.
Email replies routed into the app Inbound email from report recipients is parsed into the in-app conversation for that inspection, so clients who never install the application remain part of one thread.
Technical Architecture
Mobile client. A cross-platform application built around stack, drawer and tab navigation, with global state in a Redux store and server state managed by a query layer. Capture screens write through to on-device relational storage before anything touches the network. A sync queue manager, driven by a network monitor, drains queued work when connectivity returns. Device capabilities in use include camera and library capture, image cropping, on-device compression, format conversion, annotation with composite export, native sharing and file viewing, and cached image rendering.
API layer. A token-authenticated REST API organised into successive versioned generations rather than replaced in place, so a shipped mobile build continues to work as the server evolves. Controllers are partitioned by audience — mobile API, administrative, firm panel and public web — each behind its own role middleware, with generated OpenAPI documentation across the surface.
AI orchestration layer. A dedicated service builds the analysis request from the live field schema and the centrally managed instruction layer, calls the provider in either batch or streaming mode, parses and validates the response against that schema, coerces answers onto configured options, and records the complete interaction. Streaming is delivered to the client as server-sent events, including detection of completed structured blocks within a partially received payload.
Media layer. Compression on the device, then server-side format conversion, orientation correction, resizing and thumbnail generation, with an immediate local write and a queued background job synchronising to private cloud object storage. Access is granted through time-limited signed URLs issued individually or in batches.
Reporting layer. A composition model describing what a given report includes, rendered through an HTML-to-PDF pipeline with repeating header and footer, page-break control, brand asset resolution and platform-specific layout compensation, plus a signed public link for delivered reports.
Communication layer. Real-time messaging over a hosted websocket service, push notification delivery with a device token registry, transactional email with delivery logging, message delivery for report sharing, and an inbound email parsing endpoint that routes external replies into the correct conversation.
Data layer. A relational database covering inspections and their lifecycle, the configurable template hierarchy, allocated sections and sub-systems, comments and field answers, media, contacts, conversations and messages, notifications, the inference log, delivery and export logs, and multi-tenant firm, plan and subscription records — evolved through a long migration history.
Delivery. An automated pipeline performing branch-based environment selection, deployment, migration and cache management, alongside a feature test suite concentrated on the fragile areas: PDF layout and pagination, comment de-duplication, image orientation, cross-panel authentication and email safety.
Flow: Mobile app (offline-first capture) → local storage + sync queue → Token-authenticated versioned API → AI orchestration and schema validation → hosted vision model → inference log → relational database → media pipeline to private cloud storage → PDF report generation → email/message delivery + real-time messaging and push
Technology Stack
| Category | Technology |
|---|---|
| Backend language | PHP |
| Backend framework | Laravel |
| Database | MySQL / MariaDB with an extensive migration history |
| API authentication | Laravel Sanctum token authentication |
| API documentation | Generated OpenAPI/Swagger specifications |
| AI | Hosted vision-capable large language model (OpenAI), batch and streaming |
| Streaming transport | Server-sent events over a streamed HTTP response |
| Object storage | Google Cloud Storage with service-account signed URLs |
| Real-time messaging | Hosted websocket service (Pusher) |
| Push notifications | Firebase Cloud Messaging |
| Transactional delivery with logging, plus inbound parse webhook | |
| PDF generation | HTML-to-PDF rendering via Laravel Snappy / wkhtmltopdf |
| Image processing | Intervention Image with ImageMagick/GD paths for HEIC/HEIF/AVIF |
| Spreadsheet export | PhpSpreadsheet |
| Calendar | Google Calendar API with OAuth |
| Admin UI | Blade with an AdminLTE-based interface, Vite asset pipeline |
| Monitoring | Sentry error monitoring and a log viewer |
| CI/CD | CircleCI with Capistrano deployment and branch-based environments |
| Testing | PHPUnit feature and unit tests; Pint code style |
| Mobile framework | React Native with React 19 and TypeScript |
| Mobile navigation | React Navigation (native stack, stack, drawer, bottom tabs) |
| Mobile state | Redux Toolkit for application state, TanStack React Query for server state |
| Mobile offline | On-device SQLite and key-value storage, network monitoring, custom sync queue |
| Mobile media | Camera and library capture, cropping, compression, HEIC conversion, annotation with composite export, cached image rendering |
| Mobile real-time | Websocket client with push notification handling |
| Mobile monitoring | Sentry error monitoring |
Technical Challenges & Solutions
| Challenge | Our Approach |
|---|---|
| Model output must populate a schema the customer can change at any time | The analysis request is generated from the live field definitions for the section at request time, and the response is validated back against those same definitions — free-text answers resolved onto listed options where they genuinely correspond, severity normalised to configured options and colour codes, unresolved values surfaced rather than silently accepted. |
| AI output cannot be trusted directly into a professional deliverable | Every AI-produced value is written as a flagged suggestion requiring inspector review and acceptance before it enters the record, with per-field administrative control over whether the model may answer at all. The platform drafts; the professional signs. |
| Multi-image analysis is slow enough to feel broken on a phone | A streaming generation of the analysis API delivers the response as it is produced, with completed structured blocks detected inside the partial payload and rendered progressively, so the inspector sees results forming rather than waiting on a spinner. |
| Inference cost and result reproducibility | Every analysis is persisted with the field set it addressed, the image count, the inspector's note, the raw exchange, the parsed result, token consumption and status — giving spend visibility, an audit trail and the ability to reproduce any questionable result. |
| Inspectors work where there is no connectivity | An offline-first mobile architecture: writes land in local state and on-device relational storage immediately, enter a durable sync queue, and drain automatically on reconnect — surviving app termination and device restart. |
| Retrying a save must never create a duplicate record | The sync queue promotes a retried create into an update, on the assumption that a failed attempt may already have reached the server, so a second record cannot be produced by a network failure. |
| Changing an inspection's section selection was destroying captured work | An earlier delete-and-recreate approach was replaced with a synchronisation service that diffs the desired selection against existing records, preserving matches with their identifiers, comments and media, creating only genuine additions and removing only genuine deselections. |
| Hundreds of photographs per inspection, in formats servers do not handle natively, over cellular connections | A media pipeline with on-device compression, server-side format conversion and orientation correction, resizing and thumbnails, immediate local write with queued background synchronisation to private cloud storage, and time-limited signed access issued in batches rather than per image. |
| Long, photograph-heavy PDF reports rendering reliably | A composition model defining exactly what each report contains, rendered through an HTML-to-PDF pipeline with repeating header and footer, controlled page breaks, embedded thumbnails and platform-specific layout compensation — with the fragile parts covered by targeted feature tests. |
| A shipped mobile app must keep working as the server evolves | The API is extended by successive versioned generations rather than modified in place, so builds already in users' hands continue to function while new capability ships alongside. |
Security & Reliability
Token-based authentication with registration, verification, password recovery and a confirmed email-change flow.
Panel-separated authorisation. The mobile API, the administrative back office and the firm-level web panel are distinct controller trees behind distinct role middleware, with cross-panel authentication behaviour covered by tests.
Tenant scoping. Firm-owned data — inspections, inspectors, media and reports — is scoped so that one firm's records are not reachable from another's session.
Private media with time-limited access. Inspection photography is held in private cloud object storage and served only through signed URLs with a bounded lifetime, never as public objects.
Signed report links. Delivered reports are reachable through signed links rather than guessable addresses.
Human accountability on AI output. Nothing produced by the model becomes part of the record without professional acceptance, and every inference is logged with its inputs and outputs for later review.
Delivery and export auditing. Report exports and shares record who sent what, to whom and by which channel.
Failure visibility rather than silence. Background media synchronisation records per-item status and error, and failed analyses are stored with their error message, so problems appear as data instead of as missing content.
Production monitoring. Error monitoring across both the backend and the mobile application, with log inspection tooling for diagnostics.
Targeted regression testing on the areas most likely to break silently — report pagination and layout, duplicate suppression, image orientation, authentication boundaries and email safety.
Scalability & Performance
Queued background work. Cloud media synchronisation and other slow operations run as queued jobs, so the inspector's upload returns immediately and cloud latency never blocks the field.
Cached schema and settings reads. Section field definitions and platform settings are read on nearly every capture and analysis operation and change rarely, making them natural caching candidates, with explicit invalidation on change.
Batched signed-URL issuance. A section with many photographs resolves its access URLs in a single request rather than one per image.
Compression before transport and before inference. Images are compressed on the device, reducing upload time on cellular connections and reducing the payload sent for analysis.
Streaming rather than blocking. Analysis results are streamed, converting a long wait into progressive feedback without holding a request open behind a loading state.
Local-first reads. Capture screens render from on-device storage rather than waiting on the network, so the application stays responsive regardless of connectivity.
Thumbnails for report embedding, keeping photograph-heavy PDF rendering tractable.
Stateless application tier. Token authentication and externalised media storage keep application instances free of local state.
Delegated real-time infrastructure. Messaging is delivered through a hosted websocket service rather than self-operated socket infrastructure.
Business Outcomes
- Report drafting moved into the site visit rather than the evening after it, because findings are generated at the point of capture instead of reconstructed from photographs later.
- Narrative consistency became a configuration rather than a matter of individual habit, with wording rules managed centrally and applied to every inspector in the firm.
- The professional stayed accountable, because AI output is a reviewable suggestion rather than an automatic entry, which is what makes the capability usable on a document with legal weight.
- Work stopped being lost to connectivity, with offline-first capture and duplicate-safe synchronisation covering the basements, attics and rural sites where inspections actually happen.
- The template became the product, so sections, repeated sub-systems, fields, option lists and severity vocabularies can be configured per customer without code changes — and changing them no longer destroys captured work.
- Report production is a composition step, with scope and content classes chosen per report and the PDF produced automatically with consistent branding.
- Client correspondence stayed attached to the inspection, including replies from recipients who never install the application.
- AI spend and behaviour are visible, with every inference recorded alongside its inputs, outputs and token consumption.
- Firms can operate independently on the platform, with their own panel, their own inspector seats and their own subscription state.
Why it worked
Putting a language model into a professional workflow is easy to demonstrate and hard to ship. The demo works because someone chose the photograph. The product has to work when the schema was edited by an administrator that morning, when the model returns a value that is not in the option list, when the inspector is in a basement with no signal, and when the output ends up in a document a solicitor may read a year later.
Our team builds for that version of the problem. We generated the model's task from the customer's own live schema rather than hardcoding a question set, and validated every answer back against it, because a suggestion that does not fit the form is worse than no suggestion. We kept the professional in the loop by design — suggestions, not entries — because on a deliverable with legal weight, removing human acceptance is not automation, it is exposure. We logged every inference with its inputs so cost, behaviour and mistakes are all inspectable. And we treated offline not as a feature but as the operating condition, with a durable queue and retry semantics that cannot produce a duplicate, because an inspector who loses an afternoon's work once will not open the app again.
Our teams work across Laravel and modern PHP, large versioned API surfaces, AI integration with validation and cost governance, complex media pipelines, automated document generation, real-time messaging, and offline-first cross-platform mobile applications — with the judgement to know which parts of a professional process must stay human.
Final Summary
A property inspector's day has two halves: seeing the building and writing about it. The second half is where the hours go, where consistency between colleagues breaks down, and where the careful conventions of inspection language slip under time pressure.
Our team built a platform that reshapes the second half without removing the professional from it. In the field, the inspector photographs a component and asks for a draft. A vision-capable model receives those images along with any note the inspector adds, and returns structured answers to the exact questions that firm's template asks about that component, plus a narrative observation, a recommendation, a location and a severity indication. Those answers are validated back against the live template — options matched, severity normalised, unresolved values surfaced — and presented as suggestions the inspector reviews, edits and accepts. Results stream in as they are produced, so a multi-image analysis feels like progress rather than a stall, and every inference is stored with its inputs, outputs and token consumption.
Around that sits everything the workflow actually requires: a template system where sections, repeated sub-systems, fields, option lists and severity vocabularies are configuration rather than code, and where changing them preserves work already captured; offline-first capture with a durable sync queue and retry logic that cannot create a duplicate; a media pipeline handling modern phone image formats, compression, orientation, thumbnails and private storage with time-limited access; automated PDF report generation with per-report composition and consistent branding; real-time client messaging that even absorbs email replies from recipients who never install the app; and a multi-tenant layer letting inspection firms run their own panel, inspectors and subscription.
Delivered as an offline-capable cross-platform mobile application over a versioned Laravel API with an administrative back office, it does the thing that matters in a profession where the deliverable carries weight: it makes the writing faster without making it someone else's responsibility.