Shipment Dashboard
Saturday, 25 April 202612 shipments in view · 12 total
Overview — click to filter
Same client. Same data. Two surfaces — through a zero-downtime cutover. When PowerApps hit four hard walls, we rebuilt the dispatch platform on a modern web stack and walked the team over without ever asking them to wait for the migration.
Same data model as the canvas app — same 16 collections, same role model, same Operations Manager — on a sub-300ms web stack with offline-capable mobile.
app.coldstream-dist.co.uk/dispatch
12 shipments in view · 12 total
Overview — click to filter
Phase 2 dispatch board · Next.js + Firestore · anonymised demo data shown.
The PowerApps platform ran the dispatch floor for nine months. It did its job. But four hard walls turned up at the same time — and each had a metric attached to it.
PowerApps premium connectors and per-app plans scaled linearly with headcount. As the dispatcher pool grew and drivers came on, monthly per-seat cost was becoming the largest line item in the operations stack.
With 100+ rows and any LookUp() inside a row template, dispatch galleries lagged 1–2 seconds on every filter change. Power Fx pre-filtering helped — the canvas runtime was the ceiling.
PowerApps mobile was online-first. Drivers losing signal mid-route either retried at depot or dropped to paper. Compliance hated paper. Drivers hated retrying.
In v1, "who changed what when" lived partly in native createdon, partly in flow run history, partly in custom text columns. Compliance couldn't pull a single report without a developer.
The most important risk-reduction move on the project: a Cloud Function that pulled from Dataverse on a schedule and merged into Firestore using the same GUIDs. Both surfaces read the same record-of-truth — the cutover became reversible.
The cutover became boring. One dispatcher trialled v2 for three weeks while the rest of the team stayed on v1. No big-bang flip. No data freeze. No rollback panic.
Firestore listeners drive the UI without polling. A driver mobile update re-renders the dispatcher's board on the listener's tick.
Server-driven date window grows monotonically — picking a wider range never re-fetches what was already loaded.
PoD writes queue locally and flush when reception returns. Banner reads "Saved locally — syncing when online" until Firestore confirms.
Firebase Auth tokens carry role claims. Server-side rules and client-side routing read the same claim — one source of truth for permissions.
11 tabs over the same Firestore range read — dispatches, deliveries, violations, attendance, VOR, training, debriefs.
The three Power Automate flows became Firestore-triggered Cloud Functions firing FCM push and Teams Adaptive Card via Promise.all.
Drivers regularly work in steel-roofed warehouses and rural lanes with no signal. The mobile shell treats offline as a normal state, not an error — queued writes flush when connectivity returns.
After cutover from PowerApps to Next.js + Firebase
Indicative ranges based on industry benchmarks for a mid-sized UK chilled-distribution operator. Actual savings vary with fleet size and historical license commitment.
Server components for the static reporting shell, client components for the dispatch board. One framework, one mental model.
Real-time listeners drive the dispatch board without polling. Document IDs reuse Dataverse GUIDs so the live sync is idempotent.
Three Power Automate flows ported as Firestore-triggered functions. Teams Adaptive Card + FCM push in parallel via Promise.all.
One auth surface, five roles. Server-side rules and client-side routing read the same claim — no second source of truth for permissions.
Background refetch with 6h stale time for dispatches. Page-back navigations feel instant; filter changes don't thrash Firestore.
Utility-first styling with a design-token sidebar. No Figma archive to drift from production — design lives in code.
The cutover was the part I worried about most — and it turned out to be a non-event. We trialled v2 with one dispatcher for three weeks while everyone else stayed on the canvas app. When we flipped the rest of the team over, both surfaces had been seeing the same data the whole time.
Designed 16 Firestore collections to match the existing Dataverse schema 1:1. Document IDs reuse Dataverse GUIDs so the upcoming sync stays idempotent.
Ported Customer Deliveries, Collection Notification, and Loading Violation flows. Each fires Teams Adaptive Card and FCM push via Promise.all from a Firestore trigger.
Firebase Auth with custom claims for the five roles. Server-side rules and client-side routing both read the claim — single source of truth.
syncDataverseToFirestore Cloud Function deployed on a 15-minute schedule. Pulled production data into the new app while the canvas app kept writing.
One dispatcher used the new Next.js app exclusively for three weeks. Logged friction, edge cases, and offline behaviour. Rest of the team stayed on PowerApps.
Flipped the dispatcher pool over to v2 across two days. PowerApps left running read-only as a fallback for one week before being archived.
We rebuild PowerApps and other low-code platforms on Next.js + Firebase, with a live data bridge that keeps your team productive through the migration. No big-bang cutovers.