Case Study · Phase 2

Coldstream Distribution — Full-Stack Rebuild on Next.js + Firebase

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.

~85%
Lower Per-Seat Cost
<300ms
List Interactions
100%
Offline-Capable PoDs
The new dispatch board

A modern, real-time replacement

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

Shipment Dashboard

Saturday, 25 April 2026
2026/04/25·Sat

12 shipments in view · 12 total

Overview — click to filter

100%
12
All shipments
17%
2
On delivery
58%
7
Pending dispatch
17%
2
Completed
8%
1
No driver allocated
8%
1
No vehicle allocated
Date
Route
Add Route
Driver
Status
Mate
Round Notes
Vehicle Reg
Actions
25 Apr 2026
101
Select route…
JMJames Miller
IN PROGRESS
Alex B.
Gate code 4521
AB12 CDE
Open
25 Apr 2026
101
Select route…
COChris O'Neil
COMPLETED
EF77 QRS
Open
25 Apr 2026
102
Select route…
SCSarah Chen
IN PROGRESS
XY99 FGH
Open
25 Apr 2026
102
Select route…
AKAnna Kowalski
COMPLETED
GH33 TUV
Open
25 Apr 2026
103
Select route…
OHOmar Hassan
SCHEDULED
Tom D.
LM55 JKL
Open
25 Apr 2026
103
Select route…
?Assign driver
DRAFT
AB12 CDE
Open
25 Apr 2026
104
Select route…
ERElena Rossi
SCHEDULED
PQ88 RST
Open
25 Apr 2026
104
Select route…
JMJames Miller
SCHEDULED
AB12 CDE
Open

Phase 2 dispatch board · Next.js + Firestore · anonymised demo data shown.

16 (1:1 with Dataverse)
Firestore Collections
Document IDs reuse Dataverse GUIDs — sync stays idempotent
3 + 1 Sync
Cloud Functions
Three flow ports + one Dataverse → Firestore live merge
5
Custom Claim Roles
Admin · Dispatcher · Loader · Debriefer · Driver
3 weeks · 0 downtime
Cutover Window
One dispatcher trial · then full team flip

Why we rebuilt it

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.

01

Per-User Licensing Hit a Wall

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.

~85% lower per-seat cost on Firebase + custom auth
02

Gallery Render Hit a Performance Floor

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.

Sub-300ms list interactions in v2
03

No Real Offline Story for Mobile

PowerApps mobile was online-first. Drivers losing signal mid-route either retried at depot or dropped to paper. Compliance hated paper. Drivers hated retrying.

Offline-capable PoD capture in v2
04

Audit Trail Spread Across Three Places

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.

One immutable change-log collection in v2

The Cutover Architecture

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.

Cutover Architecture · Live Sync
Source
Dataverse
16 custom tables · production data · still being written by the PowerApps canvas during the trial period.
Bridge
Cloud Function · syncDataverseToFirestore
Pulls via OData using EntityDefinitions metadata. Merges by Dataverse GUID — re-running is idempotent.
schedule: every 15 min
Destination
Firestore
16 collections. Same GUIDs as document IDs. Read by the new Next.js app via real-time listeners — no polling, no drift.
Surface A
PowerApps Canvas (v1)
Still serving the rest of the dispatcher pool during the trial. Reads/writes Dataverse.
Surface B
Next.js + Firebase (v2)
One dispatcher on trial for three weeks. Reads Firestore live · writes Firestore (and eventually back to Dataverse via reverse-sync at flip).

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.

Key Features

Real-Time Dispatch Board

Firestore listeners drive the UI without polling. A driver mobile update re-renders the dispatcher's board on the listener's tick.

No polling · no drift

Sub-300ms List Interactions

Server-driven date window grows monotonically — picking a wider range never re-fetches what was already loaded.

Down from 1–2s in v1

Offline-Capable Mobile Driver Shell

PoD writes queue locally and flush when reception returns. Banner reads "Saved locally — syncing when online" until Firestore confirms.

100% PoD capture

5-Role Custom Claims

Firebase Auth tokens carry role claims. Server-side rules and client-side routing read the same claim — one source of truth for permissions.

Single auth surface

Cross-Cut Reports Tab

11 tabs over the same Firestore range read — dispatches, deliveries, violations, attendance, VOR, training, debriefs.

Replaced half-day Excel job

FCM + Teams in Parallel

The three Power Automate flows became Firestore-triggered Cloud Functions firing FCM push and Teams Adaptive Card via Promise.all.

Both channels · one trigger
The mobile story

Driver run-sheet that survives a dead-spot

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.

1
Captured at the customer door
PoD signature, photo, and driver-confirmed status committed via the in-browser Firestore SDK.
2
Offline = persistent queue
Firestore SDK queues the write to IndexedDB locally. UI shows the row as "Saved locally" with an amber sync indicator.
3
Flush on reconnection
The Firestore SDK retries the queued writes automatically when the network returns — Cloud Function triggers fire as if the write had been live.
4
Conflict resolution
Last-write-wins on driver-owned fields (status, PoD blob). Dispatcher-owned fields (driver assignment, vehicle) never collide because drivers can’t write them.
09:42
Offline
Route 103 · Tuesday
Today’s run
5 of 8 stops complete
2 PoDs saved locally — syncing when online
Greenfields Wholesale
Beckton DC, IG11
Riverside Foodservice
Stratford E15
queued
Harborough Bistros
Walthamstow E17
queued
4
Coastline Catering
Romford RM7
5
Highline Hotels
Ilford IG1

Measurable Business Impact

After cutover from PowerApps to Next.js + Firebase

~85%
Lower Per-Seat Cost
Premium PowerApps licensing replaced with Firebase + custom auth
<300ms
List Interactions
Down from 1–2s gallery refresh in the canvas build
100%
PoD Capture
Even with signal loss · queued writes flush automatically
1
Reports Tab
Replacing half-day Monday Excel reconciliation

Annualised cost picture

£24K–£40K
Licensing Saved
Premium PowerApps · per-seat
£10K–£16K
Disputed PoD Avoidance
Drivers no longer drop to paper
£15K–£22K
Manager Time Reclaimed
Reporting tab replaces Excel

Indicative ranges based on industry benchmarks for a mid-sized UK chilled-distribution operator. Actual savings vary with fleet size and historical license commitment.

Modern Web Stack

Next.js 14 · App Router

Server components for the static reporting shell, client components for the dispatch board. One framework, one mental model.

Firestore

Real-time listeners drive the dispatch board without polling. Document IDs reuse Dataverse GUIDs so the live sync is idempotent.

Cloud Functions Gen 2

Three Power Automate flows ported as Firestore-triggered functions. Teams Adaptive Card + FCM push in parallel via Promise.all.

Firebase Auth + Custom Claims

One auth surface, five roles. Server-side rules and client-side routing read the same claim — no second source of truth for permissions.

React Query

Background refetch with 6h stale time for dispatches. Page-back navigations feel instant; filter changes don't thrash Firestore.

Tailwind + Lucide

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.
OM
Operations Manager
Coldstream · UK Chilled Distribution

Implementation Timeline

Weeks 1–2

Schema Mirror in Firestore

Designed 16 Firestore collections to match the existing Dataverse schema 1:1. Document IDs reuse Dataverse GUIDs so the upcoming sync stays idempotent.

Weeks 3–4

Cloud Functions for the Three Flows

Ported Customer Deliveries, Collection Notification, and Loading Violation flows. Each fires Teams Adaptive Card and FCM push via Promise.all from a Firestore trigger.

Weeks 5–6

Auth + Role Layer

Firebase Auth with custom claims for the five roles. Server-side rules and client-side routing both read the claim — single source of truth.

Weeks 7–8

Live Dataverse Sync

syncDataverseToFirestore Cloud Function deployed on a 15-minute schedule. Pulled production data into the new app while the canvas app kept writing.

Weeks 9–11

Single-Dispatcher Trial

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.

Week 12

Full Cutover

Flipped the dispatcher pool over to v2 across two days. PowerApps left running read-only as a fallback for one week before being archived.

Outgrowing your low-code build?

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.

PowerApps-UAE logo

PowerApps-UAE

Your trusted partner for Microsoft Power Platform development in the UAE. We transform business processes through innovative low-code solutions.

Quick Links

Our Services

  • Canvas Apps Development
  • Model-Driven Apps
  • Power Automate Integration
  • AI CoPilot Enablement
  • SharePoint Integration
  • Custom Connectors

Contact Us

Office
Dubai, United Arab Emirates
Follow Us
© 2026 PowerApps-UAE. All rights reserved.
Microsoft, Power Apps, Power Platform are trademarks of Microsoft Corporation.