Projects

Mini & Mighty

A commerce platform for a wholesale coffee business

Year
2026
Source
Private, client work
Client
Mini & Mighty Espresso
Stack
  • TypeScript
  • Next.js
  • Turborepo
  • AWS CDK
  • Lambda
  • DynamoDB
  • SQS
  • Tailwind

The original problem

Mini & Mighty are a wholesale coffee business whose product data lived in several places at once: their online store, their accounting software, and more besides. Every price change or new product meant updating each system by hand, which is slow and surprisingly easy to get wrong across hundreds of SKUs.

The problem was to tackle with simple architecture, clean code and address their core problem now which allowing for extending in the future.

Original architecture

The portal and the services solved the original problem. A single place for the business to easily mass edit and update products, especially with constant supplier price changes.

It worked very well and solved their immediate issue.

Why it quickly grow and what came next

The scope grew. They had a consumer website but wholesale customers had different expectations and pricing, as well as different payment terms.

Their internal process relied on admin to manually create orders in their accountancy systems, manage the orders and ship them off. The admin wasn’t scaleable.

As such a dedicated customer portal was needed for businesses to place orders, see the state of their orders and confirm product pricing whenever they wanted and not via an email or form. The portal provided a professional interface with little friction in placing orders.

However there was plenty to carry over and re-use. It wasn’t mass re-write but a natural extension. In particular most of the architectural even-driven pipeline, which had held up well continued to be used. Just more of it. The running cost hasn’t moved meaningfully despite more microservices performing more dedicated tasks either.

Monorepo and shared code

The original had a shared code problem: Lambdas and the portal needed the same types and utilities, and the arrangement had become a maintenance liability. I rewrite some of this to move to monorepo, utilising Turborepo so that sharing these things was simple and easy.

Introducing a new portal largely meant duplication of components and sometimes logic, as there was a desire to maintain a similar look and feel with a scope gated in functionality.

Given the changes I also took the opportunity to change the entire theme of the portals. It wasn’t as mobile friendly as it initially could have been and with most of their customers preferring to use mobile, this was taken more seriously.

Business portal

The order pipeline

The portal’s needed to be flexible. They couldn’t know about the inner workings of the different product stores, any accountancy systems and other internal systems. The changes within would be cumbersome and time consuming.

As such I took the time to map generic internal data objects to map from multiple different sources. This meant adding a new store would be seemless if it was ever needed. I added a new integration layer lambda and all would work as is.

For a customer placing an order, seeing their orders and seeing what products are on offer its simple. They interact with our custom data objects. Messages are data are sent to queues, which figure out the right destination and offhand to the correct integration layer to import the orders into the correct 3rd party system to update financials and the business information.

Customer portal

Customer data and notifications

Customer records are pulled from the same integration layers the products do. The business portal that internal staff use allows staff to create and manage users on behalf of an organisation and see organisation information like their outstanding balance and other details.

Customer view on the business portal

They recieve an email to confirm their account and setup a password. They can easily see similar information as well (naturally it’s gated to information about their organisation).

New architecture

Although the original architecture is more trim, the new architecture design is very similar in a lot of ways. There is just more of it. Some lambdas have had their functions split into more additional lambdas. The integration layers handle a conversion between our generic objects and data into information those integrations know well - like how a specific accountancy software works and how to map and actually create orders in the right systems for financials, taking payments, reducing stock, etc.

This way we consistantly interact with a generic layer and push that logic into the last remaining steps. It essentially means if a new product store or system is used, we create a new integration layer and most things seemingless work.

What low cost actually buys

Something that doesn’t appear in the architecture but shaped how it was built: when infrastructure costs almost nothing, there’s no pressure to consolidate services to reduce a bill. There’s no temptation to make a Lambda do two things because running two seems wasteful. At this scale, eight Lambdas cost the same as two or three.

Well-architected solutions don’t have to be expensive, and keeping the cost floor low buys the space to architect well without every structural decision being second-guessed against a hosting invoice.

They may outgrow this and it may get rewritten but for now it has enough headroom to allow significant growth. The need for APIs, Kubernetes and Elastic may come one day, or it may not. I’d rather write for the pain points that exist now than the ones that might never come.