Passport hold collision
Why both booking sites rejected the same customer
I traced a booking rejection to another site's passport hold, then explored what could change.
Senior Software Engineer / UK
I build reliable, event-driven systems with TypeScript, Node.js and AWS.
Currently building a ferry booking platform.
See projects ↘Professional work
Payments, content systems and automation at a ferry booking company, CGHero and Prezzybox.
Why both booking sites rejected the same customer
I traced a booking rejection to another site's passport hold, then explored what could change.
from scope reset to launch, ahead of the timetable release
Read the four-day delivery story ↗
Launch deposits for future sailings.
Led a 3-person engineering project, reporting to the Head of Engineering and CEO.
Customers chose deposits from release day, most of all in release week.
More sailings on screen, more customers to the cart.

deployment window
Move a 2,000+ page SEO estate to micro-frontends and shorten deployments.
Owned the architecture and implementation of the SEO-content migration to micro-frontends, from design through launch.
Migrated 2,000+ pages, cut deployment time from 2 hours to 5 minutes and limited the blast radius of changes.
slowest operator search calls
One large operator's system was unavailable on 17 of 21 days in April 2026. Customers waited for searches, got empty results and became stuck in the cart.
Made the existing circuit breaker faster and visible, set timeouts from real response data and served the last good answer from a cache.
Slowest 5% of operator search calls cut from 7.4s to 3.2s. Answers in 0.14 seconds with the breaker open, and customers kept booking from cached sailings.
~13 seconds
Estimated from a Sanity update to the BFF's data store. Method below.
I designed the Sanity CMS ingestion integration within the ferry booking platform's event-driven architecture. It turns CMS webhooks into domain events, with each backend-for-frontend (BFF) keeping the data its micro-frontend needs.
About 13 seconds, estimated by adding per-stage median timings from a typical hour, from the Sanity update to the BFF's data store.
Publishing and consumer updates happen when content changes. Page requests read from the BFF's own data store.
Sanity sends create, update and delete webhooks to an API Gateway REST endpoint. The ESG callback Lambda stores received webhook events in DynamoDB for replayability.
The DynamoDB stream invokes a separate trigger Lambda, which fetches the full document from Sanity and publishes domain events to EventBridge, then Kinesis.
Each BFF listener filters for the events it needs and keeps the relevant data in its own DynamoDB store.
The BFF API is exposed through API Gateway. Qwik renders on AWS Lambda, with client JavaScript where needed.
Each backend-for-frontend subscribes to relevant events and keeps its own data for the micro-frontend it serves.
Each BFF builds its own view from the shared event stream.
ESG webhook storage is separate from each BFF's read model.
permission-check latency
Permission checks took more than a second for power users.
Implemented role-based access control using SpiceDB, based on Google's Zanzibar model.
Reduced permission-check latency from more than 1 second to less than 100 milliseconds.
additional revenue reported in Nov–Dec 2021
Make relevant recommendations while customers were already adding something to their basket.
I researched how other retailers handled cross-selling, then integrated a third-party recommendations service into the add-to-cart confirmation and basket.
In November and December 2021, the recommendation lists were reported to have driven over 2,000 additional unit sales and roughly £25,000 in additional revenue.
Automated artwork for an exclusive personalised product.
I built a script that turned customer names into personalised Celebrations artwork, placing each letter in the right chocolate-brand font and producing PSD files for printing.
When I discovered the Bounty font had no Q, I worked with Mars's marketing team to resolve it.
Automating the artwork made the exclusive product practical at a volume manual production couldn't support.
Prezzybox / Operations & automation
A daily SEO check that didn't need someone to remember to run it.
30–60 min estimated time saved per day
I containerised a daily Screaming Frog crawl of prezzybox.com. Reports went to S3, where a put event triggered a Lambda function to parse the results and send a summary and report attachment to Slack.
It replaced a repetitive manual check, with an estimated half-hour to an hour saved each day, and surfaced SEO issues such as accidental no-index changes.
Starting in April 2021, I worked on a progressive AngularJS-to-Vue migration. A small team needed to keep shipping, so we moved product pages, categories, the homepage and search in stages rather than replacing the whole storefront at once.
We deferred checkout ahead of Christmas rather than rush a high-risk change into peak trading.
Away from work
I studied pharmacy, found my way into SEO, and started writing tools for the marketing team. That became a move into software engineering.
Experience
Jan 2024 - Present
Event-driven systems, deposit payments and micro-frontends.
Also: resilient integrations, Grafana dashboards and A/B testing. Search result selection improved by +2.55pp UK / +4.87pp FR.
Aug 2022 - Jan 2024
Access control, real-time messaging, Laravel 10 and multi-item quoting. WebSocket messaging increased messages sent by 30%.
Aug 2017 - Aug 2022
Progressive AngularJS-to-Vue migration, personalised-product automation, recommendation modules and daily SEO-audit tooling.
Toolkit
I currently use Qwik on the frontend, with previous work in Vue and Nuxt.
Aston University · Diploma of Higher Education in Pharmacy