Problem
ChargedUp ran Europe's largest phone-charging network — kiosks in pubs, bars and clubs across the UK. When COVID-19 closed hospitality overnight in March 2020, the entire revenue model evaporated. The company had two assets venues still cared about: relationships with thousands of operators, and an engineering team that could ship fast.
The pivot brief was contactless ordering: customers scan a QR code at their table, browse the menu, pay, and the order routes to the bar. Venues needed it live before reopening. Brand sponsors — Redbull, Jägermeister and others — needed it co-branded. We had weeks, not months.
Process
I led engineering across six full-stack applications: the customer-facing order app, the venue dashboard, an admin console, the menu builder, a sponsor campaign tool, and the backend.
Three decisions shaped the timeline:
- React Native for the customer app, React for everything else. One codebase across iOS web app, Android web app and a venue-side native install. We deliberately shipped the customer experience as a PWA loaded from the QR scan to skip app-store friction.
- Single serverless backend on AWS, infra-as-code from day one. Lambda + API Gateway + DynamoDB with Terraform modules so we could spin up a new venue's environment in minutes. Cognito for venue-side auth.
- Tight feedback loops with venue operators. I ran weekly demos with operators of the first 5 venues and routed their feedback directly into refinements — not a backlog.
I also handled enterprise client liaison: building bespoke configurations for Redbull and Jägermeister activations, where the order app would carry the sponsor's branding and unlock specific drink offers.
Outcome
We shipped six apps to production in under two months. The QR-order experience went live in 100+ venues across the first wave of reopenings. Two enterprise sponsorship campaigns ran on the platform. The pivot kept ChargedUp solvent through the lockdown and gave the company a second product line that survived after charging kiosks returned.
For engineersTechnical Deep DiveExpand
Architecture
[QR scan] → /v/<venue-id>?t=<table-id>
↓
Static React PWA on CloudFront
↓
API Gateway + Lambda
↓
DynamoDB (single-table design)
↓
EventBridge → SQS → Bar printer worker
A single DynamoDB table stored venues, menus, tables, orders and sessions. Access patterns:
PK = VENUE#<id>for venue config and menu (SKdiscriminated byMENU#,TABLE#,ITEM#)PK = ORDER#<orderId>with a GSI onVENUE#<id>#OPENfor the venue dashboard's live order queue- TTL on session records to auto-expire abandoned baskets
Why serverless
The traffic profile fit Lambda perfectly: low baseline, bursty around opening hours and Friday/Saturday nights. Cold-start cost was near-zero because most of the customer flow was cached at CloudFront — the menu only hit the API on first scan, and order writes were async anyway.
Sponsor campaign isolation
Brand campaigns (Redbull, Jägermeister) needed to feel like first-party experiences without forking the codebase. We modelled campaigns as a CAMPAIGN#<id> partition keyed against a venue, with theme tokens (colours, logo, hero copy) loaded into the React app at boot. A single feature flag toggled the campaign overlay on a venue's QR codes.
Trade-offs
- No native app. The PWA route was contentious — venues wanted "an app" — but app-store review timelines would have killed the launch window. We compensated with an "Add to Home Screen" prompt after the first order.
- Terraform vs CDK. Picked Terraform because the team already knew it. With hindsight CDK would have given us better TypeScript-typed infra alongside the rest of the codebase.
Lessons
Speed of iteration with operators mattered more than test coverage in the first two weeks. We added integration tests as the schema stabilised, not before.
