Delivered remotely for a business based in Milan, Italy. Names withheld by agreement.
Project Overview
Industry: Public-sector regulatory compliance — protection of buried utility infrastructure during excavation work.
Type of solution: A cross-platform mobile application for the general public and field personnel, operating as a front end over a bespoke REST API. The application covers reference content, structured incident reporting, evidence submission and card payment.
Business context: A sector authority operates a formal process for reporting damage to buried infrastructure. The report is long and legally precise, because it opens an enforcement process: it must establish who was excavating, what work was being done with what equipment and method, what was struck, what the consequences were, whether the required pre-excavation checks were carried out, who marked the site, and which provisions are alleged to have been breached. A fee accompanies the submission. Historically all of this happened on a desktop web form after the fact, with the fee handled as a separate transaction.
General users: Utility owners' field representatives, locating and marking technicians, excavation contractors, and members of the public who witness damage. The application is open — there is no account or login — because the person best placed to report is often reporting only once.
General purpose: To move compliance reporting to the point and moment of the incident, enforce completeness one step at a time, survive the interruptions of field work, and collect the associated fee in the same session with a reference that ties the money to the case.
The Business Challenge
The form is long, and it has to stay long. Ten sections and well over a hundred fields is not bloat — each one exists because an enforcement process depends on it. Shortening the form was not an option. Making it survivable on a phone was the requirement.
The reporter is in the field, not at a desk. The moment of best evidence is the moment of the incident. Every hour that passes between the damage and the report costs detail and increases the chance the report is never filed.
Field work interrupts everything. A call comes in, the phone is pocketed, a truck moves. If a partially completed form is lost when the app is backgrounded, the submission will not be completed — and, realistically, will not be restarted.
Connectivity cannot be assumed. Excavation sites are frequently the places with the worst signal. The parts of the form the user is most likely to labour over must not depend on a live connection.
The legal reference is a tree, not a list. The provisions a submitter must identify are nested and numerous. A flat dropdown of them is unusable, and getting the selection wrong undermines the report.
Money and the case record must be linked. The fee and the report are one act to the user but two operations against two systems. If they are not connected by a reference the authority can reconcile, the back office inherits a manual matching problem on every submission.
Evidence needs to travel with the report. Photographs, tickets and locate records are frequently what settles a dispute, and they need to arrive attached to the right record.
Reference content changes on the authority's schedule. Legislation, guidance and FAQs are updated when the authority updates them. Tying that content to app-store release cycles would leave the public reading stale rules.
Our Approach
Break the form into ten steps and make every step short. One section per screen, each with its own validation and its own progress indicator, so the user always knows how much is left. The parent screen renders exactly one step at a time; the steps themselves know nothing about each other. Reordering or revising a section is a local change, not a refactor of the flow.
Make durability the default, not a feature. Rather than holding the whole form in memory in a shared store, each step writes its own slice to device storage as the user advances, and reloads it if the user comes back. The final review step reassembles the complete submission by reading every slice back. The practical consequence is that there is no such thing as losing your progress — the app can be killed at any point and the form is exactly where it was. After a successful submission, every slice is cleared.
Ship the legal taxonomy with the app. The statutory provisions picker is a bundled hierarchical dataset presented through a sectioned multi-select, so the single most legally significant field in the form works with no network at all, and the number of selections is capped to keep submissions meaningful.
Order the submission so nothing is orphaned. The card transaction runs first through a hosted gateway; its transaction identifier becomes the payment reference on the record; the record is then created through the API; and only once the record exists and has an identity is the evidence file uploaded against it. Each step depends on the one before it having succeeded.
Deliver reference content remotely. Legislation, FAQs and curated links are served by the API as content and rendered natively in the app, so the authority updates what the public reads without waiting on a release.
Check the connection before every call, and say so. Rather than letting requests hang and time out, the app tests connectivity first and tells the user plainly. In the field, an immediate honest message is worth more than a spinner.
Keep the codebase current. The application has been carried forward across several React Native generations onto a current release with React 19 and the New Architecture, including patching two unmaintained native modules in place rather than forking them, and pinning transitive dependencies to security-patched minimum versions.
The Solution
Reference library. Legislation and statutory text delivered from the API and rendered natively, with a link out to the full source document; an ordered, expandable FAQ; and a categorised set of curated links with a detail view for each category.
Ten-step incident report. A guided wizard covering the reporting party and an alternate contact; the incident itself with date, time, location and the company involved; the excavator's details; the type of work being carried out; the equipment and method of excavation; the damaged facility, its function, pressure, size and position; the consequences including emergency-service response, evacuation, service interruption and casualty counts; the pre-excavation notification and ticket status; and the locating and marking party with an assessment of the marks.
Hierarchical statutory selection. The provisions alleged to be breached are chosen from a nested tree bundled with the application, with parent and child levels and a cap on selections.
Structured answers, not free text. Work types, excavation methods, equipment, facility types and line functions are all multi-select lists drawn from the authority's own vocabularies, so submissions arrive comparable rather than as prose.
Evidence attachment. An optional supporting document is chosen through the system document picker and uploaded against the created record as a multipart request after submission.
Certification. Before review, the submitter types their full name as an attestation, recorded with the report.
Full review before commitment. The final step renders every section back to the user in a single scrollable summary, section by section, before any payment or submission occurs.
Card payment in session. Card details are captured, the fee acknowledged, and the transaction executed through a hosted card gateway, with the resulting transaction reference carried onto the record.
Standalone fine payment. A separate four-step flow — payer details, amount and reason, billing party with a "same as payer" shortcut, then review and pay — for settling a fee outside the reporting flow, with the same draft persistence and the same confirmation pattern.
Resumable drafts throughout. Both wizards persist and restore per-section state, and clear it on successful completion.
Direct access to the sector information line. The home screen offers a one-tap dial-out to the industry's public information number alongside links to the authority's web resources, over a looping background video.
Key Features
Ten-step guided compliance report A long statutory form decomposed into ten single-purpose screens, each independently validated, with a circular progress indicator on every step.
Per-step draft persistence and resume Each step writes its own state to the device as the user advances and restores it on return. Closing or losing the app mid-form costs nothing; drafts are cleared automatically after a successful submission.
Offline-capable statutory provision picker The nested provision taxonomy is bundled with the application and presented through a hierarchical multi-select, so the most legally consequential field works with no connectivity.
Structured vocabularies throughout Work types, excavation methods, equipment classes, facility types and line functions are selected from the authority's own controlled lists, producing comparable, analysable submissions rather than free text.
Evidence attachment against the created record An optional supporting document is picked from the device and uploaded as a multipart request once the record exists and has an identity.
Payment linked to the case record The gateway's transaction reference is carried onto the submitted record, giving the authority a reconcilable link between the fee and the case.
Full pre-submission review Every captured section is rendered back to the submitter in one summary view before payment or submission, alongside a typed certification of the submitter's name.
Standalone fee payment flow A separate four-step payment wizard with a billing-address shortcut, the same draft persistence, and its own confirmation step.
Remotely managed reference content Legislation, FAQs and curated links are served as content from the API and rendered natively, so the authority updates what the public reads without an app release.
Connectivity-aware networking Every call is preceded by an explicit connectivity check with immediate, plain-language feedback rather than a request left to time out.
Technical Architecture
Application shell. A bottom-tab navigator with a custom tab bar renderer, two of whose tabs wrap their own stack navigators. Monitoring is initialised at the entry point and the root component is wrapped for automatic error capture. A native splash screen is dismissed once the first screen is ready.
Wizard layer. Each multi-step flow is a parent screen holding a single step index and rendering exactly one child step component. Steps advance and retreat through callbacks; they hold their own state and do not communicate with each other directly.
Persistence layer. Device key–value storage holds one serialised slice per wizard section. Steps write on advance and read on mount; the review step reads all slices to assemble the submission payload; a bulk clear runs after a successful submission. A local relational store on the device holds payer details for the payment flow.
Networking layer. A single module exposes typed helpers for each HTTP verb plus JSON and multipart variants, applying common headers, API version and device-type parameters consistently. A companion module maps logical method names to URL fragments, keeping every endpoint definition in one place rather than distributed across screens.
Content layer. Reference screens fetch content on mount and render API-delivered HTML natively, with ordering driven by a sequence field supplied by the API.
Payment layer. Card transactions are executed against a hosted gateway's transaction endpoint, with separate sandbox and production configuration selected through environment files and a build-time switcher script.
Native layer. Standard iOS and Android project shells with the New Architecture and Hermes enabled, a minimal Android permission set, App Transport Security enforced on iOS, a registered custom font family, a bundled background video, and two native modules maintained through in-repository patches rather than forks.
Flow: Mobile app → per-step local persistence → review and assembly → hosted card gateway → REST API record submission with payment reference → multipart evidence upload against the created record → local drafts cleared
Technology Stack
| Category | Technology |
|---|---|
| Mobile framework | React Native (current major release) with React 19, New Architecture, Hermes |
| Navigation | React Navigation 7 — native container, bottom tabs with a custom tab bar, stack navigators |
| Wizard state | Component-local state with per-section persistence to device key–value storage |
| Local database | On-device SQLite |
| Networking | fetch for JSON with a centralised per-verb service layer; blob utility for multipart uploads |
| Connectivity | Network information module with pre-flight checks |
| Forms & inputs | Picker-select, hierarchical sectioned multi-select, date and time pickers, masked view, keyboard-aware scrolling |
| Content rendering | Native HTML rendering of API-delivered content |
| Documents | System document picker for evidence attachments |
| Media | Video playback for the home screen, native splash screen, SVG, vector icons, circular progress |
| Payments | Hosted card payment gateway |
| Configuration | Environment-file based configuration with a build-time environment switcher |
| Monitoring | Sentry, with Metro and Gradle plugin integration |
| Animation & gestures | Reanimated, Worklets, Gesture Handler, Screens, Safe Area Context |
| Localisation | Localisation library with a centralised string catalogue |
| Dependency maintenance | patch-package for unmaintained native modules; explicit transitive dependency pinning |
| Tooling | Yarn 3 with pinned toolchain versions, ESLint, Prettier, Jest |
Technical Challenges & Solutions
| Challenge | Our Approach |
|---|---|
| A ten-section statutory form that cannot be shortened, completed on a phone | Decomposed into ten single-purpose screens, each independently validated, with a progress indicator on every step and a full review before commitment — so the form's length never confronts the user all at once. |
| Field work interrupts form completion constantly | Each step persists its own state to the device as the user advances and restores it on return, with the review step reassembling the whole submission from those slices. Losing progress is structurally impossible rather than defended against. |
| The most legally significant field is a deep nested taxonomy, used where signal is worst | The provision tree is bundled with the application and presented through a hierarchical multi-select, so it works entirely offline, with a selection cap to keep submissions meaningful. |
| A fee and a case record are one act but two systems | Sequenced deliberately: charge, then submit the record carrying the gateway's transaction reference, then attach evidence against the created record — each step conditional on the previous one succeeding, giving the authority a reconcilable link between money and case. |
| Evidence can only be attached once a record exists | Submission is a deliberate two-call sequence: the record is created first and returns its identity, then the file is uploaded against it as multipart — which also means a large attachment can never block or delay record creation. |
| Legislation and guidance change on the authority's schedule, not the release schedule | Reference content is served by the API and rendered natively in the app, so the authority publishes updates directly without an app-store release. |
| Unreliable connectivity producing silent failures | Explicit connectivity checks before each network call with immediate plain-language feedback, rather than allowing requests to hang and time out. |
| Carrying a long-lived codebase onto a current platform | Upgraded across several React Native generations to a current release with React 19 and the New Architecture, with two unmaintained native modules patched in place rather than forked, and transitive dependencies pinned to security-patched minimum versions. |
| Free-text answers producing unusable enforcement data | Work types, excavation methods, equipment, facility types and line functions all drawn from the authority's controlled vocabularies as multi-selects, so submissions arrive structured and comparable. |
Security & Reliability
Transport security. All API communication runs over HTTPS. On iOS, App Transport Security is enforced with arbitrary loads disabled.
Minimal device surface. The Android build requests network access only — no location, no camera, no contacts, no storage permissions beyond what the system document picker mediates. Application-level backup is disabled so form data is not swept into device backups.
No standing credentials on the device. The application has no login and no long-lived user session, so there is no account to compromise on a lost or shared handset.
Draft lifecycle. Working drafts are cleared from the device automatically once a submission or payment completes, so retained data does not outlive the task it supports.
Attestation. The submitter types their full name as a certification before review, recorded with the report — accountability on a submission that initiates an enforcement process.
Payment reference integrity. The gateway's transaction identifier is carried onto the submitted record, so the authority can reconcile a payment against a case rather than matching them manually.
Supply-chain hygiene. Transitive dependencies are explicitly pinned to security-patched minimum versions through package-level overrides — a deliberate measure to stop known-vulnerable indirect dependencies entering the build.
Production monitoring. Crash and error monitoring is initialised at the application entry point and integrated into both the JavaScript bundler and the Android build, so release-build failures surface with usable stack traces.
Sequenced submission. Payment, record creation and evidence upload are ordered, with each stage conditional on the previous one having succeeded, so partial states are contained rather than propagated.
Scalability & Performance
A stateless client. The application holds no server session and performs no background synchronisation. Every instance is independent, and load on the API is proportional to submissions rather than to installed base.
One step mounted at a time. Only the active wizard step is rendered, so a form with well over a hundred fields never constructs a single enormous view hierarchy.
Local writes instead of round-trips. Form progress is persisted to the device, not to the server, so completing a long form generates no network traffic at all until the moment of submission.
The heaviest picker needs no network. The nested statutory taxonomy is bundled with the application rather than fetched, removing both a request and a failure mode from the most-used part of the form.
Content fetched once per screen. Reference content is requested on mount and rendered natively, with ordering supplied by the API rather than computed repeatedly on the client.
Attachment upload decoupled from record creation. The record is created and confirmed before any file transfer begins, so attachment size and upload duration never affect whether the report is filed.
Modern runtime. The application runs on the New Architecture with Hermes, reducing startup time and cross-boundary overhead relative to the legacy runtime.
Cross-platform from one codebase. A single JavaScript codebase serves both platforms, with platform-specific handling confined to keyboard behaviour, layout insets and media playback — so feature work is done once.
Business Outcomes
- Reporting moved to the point of the incident, where the evidence is freshest and the reporter is actually present, rather than to a desk visit that may never happen.
- Submissions arrive complete and structured, because each step validates before the next opens and answers are drawn from controlled vocabularies rather than typed as prose.
- Interruption stopped costing submissions, since progress is persisted after every step and restored automatically.
- The most legally significant field works without connectivity, because the statutory taxonomy travels with the application.
- Fee and case record arrive linked, with the payment reference carried onto the submission so reconciliation is not a manual back-office task.
- Supporting evidence arrives attached to the right record, uploaded against the record after it has been created and identified.
- The authority controls its own published content, updating legislation, guidance and links without waiting on an app release.
- One channel for the whole process — reference material, reporting, evidence and payment — rather than a web form, a separate payment page and a PDF of the rules.
Why it worked
Compliance software fails in a specific and predictable way: it is built to satisfy the form rather than the person filling it in. The result is technically correct and practically unused — the field user gives up, files nothing, and the authority's data quietly gets worse.
Our team builds for the person in the trench. We took a form that could not be shortened and made it survivable: ten short steps, validated one at a time, with progress that persists after every single one so that being interrupted — which is the normal condition of field work, not the exception — costs nothing. We bundled the legal taxonomy into the application because the field where a mistake matters most is the field most likely to be attempted where there is no signal. We sequenced payment, record creation and evidence upload deliberately, so the authority receives money and case linked by a reference rather than inheriting a matching problem. And we kept a long-lived codebase current across several platform generations, patching unmaintained dependencies in place and pinning transitive packages to security-patched versions, so the application remains buildable and shippable years after its first release.
Our teams work across cross-platform mobile development, long multi-step data capture, offline-tolerant design, payment gateway integration, content-driven applications and the unglamorous discipline of platform upgrades — with the judgement to know which parts of a regulated process must be reproduced exactly and which can be made easier without losing anything that matters.
Final Summary
An authority responsible for protecting buried infrastructure needs incidents reported accurately, promptly and completely, because each report opens an enforcement process. The form that does this is necessarily long and legally precise. For years it lived on a desktop web page, which meant it was completed hours after the event by someone reconstructing details from memory — or not completed at all.
Our team delivered a cross-platform mobile application that puts the entire process in the hands of the person who witnessed the damage. The report is decomposed into ten short, individually validated steps with a visible progress indicator; every step persists itself to the device as the user advances, so a phone call, a pocket or a dead battery cannot cost a submission. The statutory provisions the report must cite are shipped inside the application as a hierarchical picker that works with no connectivity. Work types, excavation methods, equipment and facility classifications are chosen from the authority's own vocabularies, so what arrives is comparable data rather than prose. A supporting document can be attached from the device, and the whole submission is rendered back for review and typed certification before anything is committed.
The commercial half is handled in the same session: the fee is taken through a hosted card gateway and the resulting transaction reference is carried onto the record, so money and case arrive linked. Alongside the reporting flow sit a standalone fee payment wizard and a reference library — legislation, FAQs and curated links — delivered as content from the API so the authority can update what the public reads without an app release. Built as a single cross-platform codebase on a current runtime, with connectivity-aware networking, production error monitoring and actively maintained dependencies, it turns a form that people avoided into one they can finish standing in a trench.