Skip to content
All work

Case studyShipped

Cupcino

Client
Datamole
Role
Full-stack engineer
Timeline
2022

The portal behind a fleet of connected coffee machines. I started the repository, designed the data model and migrated the legacy database.

Context

Cupcino operates connected coffee machines. Every machine reports what it does, and every cup it makes is a row in a database somewhere. The business question is simple to ask and annoying to answer: how is the fleet doing, by machine, by customer, by key account?

The answers lived in a legacy system nobody wanted to extend. Datamole took on the replacement, and I was the engineer who started it.

My role

I was the first person on the repository and I built the foundation the product was then grown on, over roughly two months, before handing it to a larger team that shipped on it for another year and a half.

That handover is the point. The job was not to finish a product, it was to make a product finishable by other people.

The data model

Everything else depends on getting this right, so it came first.

The domain is a chain: a key account contains customers, a customer has machines, a machine has modules, and a module produces dispenses. Around that sit users, per-account and per-customer permissions, machine installations, module installations, module states and device password history.

I designed and migrated those entities against the real legacy data, which is where the modelling stops being theoretical. Some identifiers are generated by us, others arrive imported from the machines and cannot be renumbered. Timestamps that lived as strings had to become dates. user is a reserved word in SQL. Each of those is a small fact that decides a schema, and each of them cost an iteration of the initial migration.

The backend

A NestJS service with TypeORM over PostgreSQL: configuration validated at boot, a Dockerised database for local development, a migration workflow the rest of the team could use without asking me, generated Swagger docs, and authentication built on Passport with JWTs and refresh tokens, hashed credentials and role-based permissions that follow the key account and customer hierarchy.

The frontend foundation

A Vite and React application with the theme, the reset, the application shell (side navigation, top bar, global search, sign-out), the routing table with every planned page stubbed out, the first shared components, Formik forms, and route guards driven by role, so that permissions were part of the architecture from the first screen rather than retrofitted later.

Stubbing out the whole route table before the pages exist is a small trick worth keeping: it turns “what are we building” from a document into something the team can click through.

Migrating the legacy data

The old system ran on SQL Server, with its own naming and its own idea of users, groups and group dependencies. I wrote a standalone Node script that reads it and writes the new PostgreSQL model: key accounts and customers, machines and their installations, password history, users and their permissions, modules and module states, and the dispense history behind all the statistics.

It is not glamorous code. It is the code that decides whether a replacement system launches with history or launches empty, and it ran long enough that I gave it a logger and a timer so the person running it could tell progress from a hang.

Outcome

A running foundation, handed over: schema, migrations, auth, API conventions, application shell and a populated database. Six engineers built the product on top of it over the following eighteen months, which is the most useful thing I can say about the decisions in it.

Next project

All work

IPEX B2B Portal

IPEX a.s. · 2019 – 2020