
Replaced a paper-and-spreadsheet quotation flow with a mobile-first app rolled out nationwide
The client had sales teams across the country handling business-to-business and high-value retail quotations. The shape of the brief is one anyone who has digitized a sales process will recognise:
The mandate was different from the rescues: this one was greenfield, but with a hard integration constraint. SAP was the system of record and was not going to move. Anything new had to plug into it without becoming another fragile bridge.
| Constraint | Reality |
|---|---|
| Team size | 3 engineers, with me as architect and tech lead |
| Form factor | Mobile-first — sales staff work on phones in stores and on the road |
| Source of truth | SAP for catalog, pricing, customers, and quotation persistence |
| Connectivity | Sales sites with variable network quality — the app had to degrade gracefully |
| Rollout | Nationwide, across multiple sales teams with different habits |
| Adjacent systems | The same SAP integration patterns I'd built for the e-commerce rescue could be reused |
The non-negotiable: the salesperson on the floor must always be able to produce a credible quote, even on a flaky connection.
The temptation in 2025 was to reach for a fashionable stack. The right answer for a small team and a nationwide deadline was the one we could ship.
| Option | Trade-off | Chose |
|---|---|---|
| A bespoke SPA + custom admin | Months of UI work before the back-office could see anything | |
| Laravel + Filament for the back-office; a thin mobile-first PWA for the salesperson surface | Filament gives a production-grade admin in days; Laravel handles the SAP integration cleanly; the team already knew the stack |
Boring on purpose. The novelty budget went into the SAP integration, not the framework choice.
Same reasoning as earlier PWA work, applied at higher stakes.
| Option | Trade-off | Chose |
|---|---|---|
| Native iOS + Android | App-store gauntlet on every release; longer build cycles; device fragmentation | |
| Mobile-first PWA, installable from a link | Same codebase as the back-office; instant updates; deploys decoupled from app stores |
For a tool used by employees rather than customers, a PWA was the obvious right answer — fewer moving parts, faster iteration, no rollout choreography.
SAP was the system of record. It wasn't, however, fast or always available. If the app called SAP synchronously on every action, the salesperson on the floor would feel every SAP hiccup.
| Option | Trade-off | Chose |
|---|---|---|
| Call SAP synchronously for every read and write | Simplest mental model; the salesperson lives at SAP's mercy | |
| Project SAP catalog and pricing into the app's own store; queue writes back to SAP | More moving parts; the salesperson always sees a usable catalog and the system tolerates SAP outages |
This is the pattern I carried over from the e-commerce rescue: a single integration module with a typed interface, observable, retry-aware, and replaceable. The app reads from a local projection and writes through the module — SAP is the contract, not the runtime.
Sales sites don't have a uniform network story. Treating offline as an exception meant it would never be tested; treating it as a default meant it just worked.
| Option | Trade-off | Chose |
|---|---|---|
| Assume the network and add offline later | Offline becomes a perpetually-postponed Phase 2 | |
| Cache the catalog locally, queue quotes, sync when online | Up-front design cost; the app behaves the same in the warehouse and on a highway |
The business outcome of this decision was simple: a salesperson on a bad connection still closes the quote.
Filament made the admin surface cheap to build. That meant we could spend the saved time on the SAP integration and the mobile experience — not on yet another bespoke admin.
| Option | Trade-off | Chose |
|---|---|---|
| Build a custom admin from scratch | Fully bespoke, fully ours, fully unfinished | |
| Lean on Filament for the back-office and put the engineering time into integration and mobile UX | The interesting work goes where the leverage is |
By rollout:
This was the build where the integration-module pattern proved generalizable: write the SAP boundary once, reuse it across products.
Same brief today, same constraints, same SAP. The architecture instincts wouldn't change; the platform underneath would.
The shape of the work is the same as the rescues — a boring framework, a single integration boundary, an offline-first surface, and observability from day one — but the platform underneath does most of the heavy lifting.
If you have a SAP-coupled process that still depends on manual coordination, I'd be glad to compare notes on what a small focused build could look like. Reach out here.
Stabilizing an inherited e-commerce platform on NestJS + Strapi
A recovery-shaped engagement on an inherited NestJS + Strapi storefront: stabilize the runtime, contain the SAP integration behind a single boundary, containerize the deploy path, and keep Strapi to editorial content. This is the recovery half of a paired engagement; the rebuild that followed is its own story.
Shipping a high-scale PWA from an inherited e-commerce project
How a stalled Node.js + Angular e-commerce project was diagnosed, recovered, and shipped end-to-end as a PWA and mobile apps for a high-volume customer base — with a Docker registry and CI/CD pipeline that made continuous delivery possible for the team that came after.