Smart dispenser fleet analytics

Helping Aquablu turn data from 1,500+ connected dispensers into sales and service signals

Aquablu is a Dutch retail company that sells smart water dispensers and flavored water refills poured through them. The machines stay under service contracts long after installation, and Aquablu supplies filters and spare parts that keep them pouring as a part of their maintenance service. Selling a dispenser opens an account rather than closing a deal, and that post-sale business is where the margin comes from.

The early dispensers were simple enough to look after. However, starting in November 2025, when more flavors came in, they brought more parts, each needing attention on its own schedule. Fall behind, and it's not just a missed service visit, people drink what comes out of these machines, so when something goes wrong, it's Aquablu's name on the front of it.

Staying on top of that across a whole fleet needed a system. So, Aquablu has built AURA, a cloud-based fleet management platform for predictive maintenance, to do that job. That's where the DigitalSuits team came in.

Client

Country

Netherlands

Industry

Retail, Manufacturing

Partnership period

December 2024 – May 2025

Team

Fractional CTO, Project manager

Technologies

Shopify, Shopify Plus, Liquid, HTML, JavaScript, Remix, Node.js, AWS, Vue 3, Vite, Pinia, Tailwind CSS, Laravel, PHP, MySQL, MongoDB

The challenge

The hard part starts after installation

AURA had been running for almost 4 years when we joined, built back when a REFILL was essentially a water filter. The product moved on underneath it. Machines now pour six flavors, and each cartridge starts its own expiry countdown the moment it's opened. Aquablu's revenue was shifting further into post-sales at the same time: consumables, service contracts, and lately pay-per-drink subscriptions.

All of this depended on Aquablu knowing what was happening inside each machine. The team had already decided to rebuild AURA to keep up. Here's what the rebuild had to solve:

A legacy stack that couldn't open up

The dashboard ran on an outdated front-end framework and a long-outdated Laravel backend, tightly coupled, so every new feature meant working through both. Resellers had access, but there was no proper way to manage B2B clients and resellers, and end clients couldn't see the machines in their own offices.

Fixed schedules missed each machine’s maintenance needs

Some service tasks came due every week, others, every six months or once a year. Filters followed usage: a machine in a busy office could reach its rated liter limit long before one in a quieter space. The contract also determined who did the work (Aquablu, the reseller, or the client). A fixed calendar couldn't simply tell the team which machine needed attention or who was responsible. The business needed a custom notification system.

Machines that don't always report back

Each dispenser uses a SIM card from KPN, a Dutch mobile provider, to send JSON data to AURA. But coverage is patchy in parts of Europe, especially Germany, and machines regularly go offline.

In one case, a firmware update used the entire monthly data allowance and left a batch of dispensers offline for seven days. Their internal counters kept running, but the devices had too little memory to retain much of that week’s data. Missing readings mean missed signals: a reorder sales never hears about, or a critical error the service team finds out about too late.

Every drink poured is a database

Every time a dispenser poured a drink, it sent a record to AURA. With more than 1,500 machines in busy offices, those records added up fast. Checking a machine’s current status required only a few records. But a monthly client report or a year's worth of consumption statistics meant reading through millions of records. The database struggled with that volume, and a monthly report took about a day to generate.

Having already worked with DigitalSuits on its Shopify B2B storefront and the ERP, CRM, and logistics integrations behind it, Aquablu turned to us again. This time, we joined as an extension of their team: a dedicated team of full-stack and data engineers working within the AURA engineering team on the platform's data.

The solution

Making the data fast enough, complete enough, and clear enough to act on

Getting data off the devices and through KPN is handled on Aquablu's side. Our work starts when an event reaches AURA's database. From there, we store it, process it, and turn it into what each audience needs to see: device status, service tasks, alerts, and reports. Where it made sense, we also advised on technical decisions along the way.

Rebuilding AURA as a standalone app

The dashboard came out of the Laravel application and now runs as its own Vue 3 single-page app against the API. A UI change ships without a backend release.

That rebuild also made AURA fit to hand to an outside audience. We added B2B client and reseller management, synced Aquablu's B2B clients from Shopify into the platform, and opened access to end clients for the first time. Their view is deliberately narrow (their own machines, usage, levels, and what's due), without the fleet-wide and commercial views that stay with Aquablu and its resellers.

From raw events to calculated values

MySQL is the primary store: devices, companies, clients, locations, raw messages, snapshots, per-drink records, errors, service tasks, and the computed levels and due days. That's what a device page reads.

MongoDB holds four aggregate collections (daily, weekly, monthly, yearly) rebuilt each night from the MySQL records. Charts and long-range usage read those. No raw events go into Mongo.

Alongside that, we brought the Laravel backend up from a long-outdated version, optimized the queries and codebase behind reporting, and moved the monthly client report from a link on a public page to a PDF attached to an email. Generation went from about a day to 10 minutes. Dependencies are now audited as routine, because nobody raises a ticket for a package that quietly became vulnerable six months after you shipped.

Mongo was in the stack before we arrived and isn't what we'd pick for this today. Replacing it would mean rebuilding those four collections and reconciling years of figures. The client would pay for that work but would gain no new capabilities. We kept it and built the aggregation layer around it.

Knowing when service is due and which errors need attention

Every task carries its own timestamp off the device: nozzle cleaning, flavor-line flush, service visits, each flavor and filter change. Invalid timestamps are ignored and backfilled from the previous snapshot or the installation date.

Nozzle cleaning comes around roughly weekly and sits with the client. The flavor-line flush runs about quarterly, and the six-month clean sits with the partner. Filters run to their own intervals, and take whichever comes first: the rated lifespan or usage running them out. Tasks show as action due, then overdue once the grace period passes. Since responsibility is split by contract, that record is the shared reference for all three parties.

Errors arrive as bitmasks and get decoded per product and severity. Most are for the dashboard. A handful email the company directly, capped at one per machine per day, and they're the ones that stop a machine working: CO₂ pressure high, float-sensor timeout, a solenoid down, an unexpected carbonation pump start. A locked machine shows from its last snapshot even if nothing has arrived since.

Inaccurate readings stopped before they reach a bill

Firmware sits outside the web platform, so the protection has to live in the data layer.

  • Impossible readings are caught on the way in. Volumes over 10,000 ml and prices over 1,000 are written as zero, because the hardware was sending figures that couldn't be real. Broken clocks are rejected rather than stored as service dates.
  • Silent machines are declared. A machine that hasn't reported in 12 hours goes into a daily email and Slack digest flagging that window as incomplete, so a gap surfaces instead of quietly becoming a bill.
  • Due dates keep moving regardless. A nightly job recalculates levels and service dates for machines that haven't reported in 24 hours, working from the last known snapshot.

With pay-per-drink billing running, this is what stops a connectivity problem from turning into a wrong invoice.

Monitor a growing fleet without growing the team that watches it

We connect your devices to the systems your business already runs on, so usage data drives decisions without someone checking manually.

The result

Reports in hours instead of days, across the fleet of 1,500+ connected machines

AURA is Aquablu's platform and Aquablu's achievement. Our part has been the engineering underneath it: it collects the data, checks it, and holds up when three different audiences query it at once.

What that looks like in numbers:

1,500+ connected units

REFILL machines tracked through AURA across Aquablu's direct clients and reseller network


~1 day → 10 minutes

Monthly report generation after the Laravel upgrade and database optimization


3 access levels, one platform

Aquablu, resellers, and end clients – end-client access added by DigitalSuits, where previously there was none


Monitor a growing fleet without growing the team that watches it

We connect your devices to the systems your business already runs on, so usage data drives decisions without manual checks.