The Engineering Challenge

This project started as a way to keep my automation skills sharp against a real, live system rather than a tutorial app, using the operational challenges of a small hospitality business I'm involved with as the test subject. That business has to keep several systems in tandem: a channel manager tracking availability across booking platforms and a website, a booking form guests use directly, and a WhatsApp line where enquiries arrive alongside phone calls.

The engineering risk in that setup is double bookings and silent coordination failures: two systems disagreeing about availability, a slow or missed response losing a booking, or a workflow that's technically correct but too brittle for people to use efficiently under real conditions.

The Solution

I designed and built a small set of connected systems: a booking flow with live availability checks, a Playwright + TypeScript automation suite running in CI to catch regressions and double-bookings before guests do, and a WhatsApp bot that responds to enquiries and checks availability on a regular automated schedule. Each piece is tested on its own, and as part of the larger system.

Guest-facing pages and the booking flow are deployed as static pages and serverless functions on Vercel. A channel manager holds the availability data; the booking form checks against it in real time before allowing a submission. A separate Node.js and Express service, deployed on Railway, runs the WhatsApp bot via the Twilio API, independent of the main site's deploy cycle. GitHub Actions ties it together with scheduled test runs against the live, deployed environment.

The Playwright suite covers the booking flow end to end: form validation, availability checks, and channel manager API responses, plus synthetic monitoring that runs continuously against the live site. A core focus is double-booking detection across multiple room types: the suite checks for date overlaps room by room, on a schedule, and raises an alert the moment two reservations claim the same night. The WhatsApp bot runs on its own automated schedule too, checking availability and auto-responding to enquiries with current rates and booking information, so a message at 2am still gets an answer.

Technical Decisions

The most instructive bug in the project was a timezone drift issue in the double-booking detector. The original overlap check used JavaScript's new Date() to compare a checkout date against a checkin date. new Date() parses a bare date string as midnight UTC, but the property operates several hours ahead of UTC, so a checkout and a checkin on the same calendar day appeared to overlap by several hours. The result was a run of false-positive double-booking alerts that only surfaced in cross-timezone CI runs, not in local testing.

The fix was to stop comparing Date objects and start comparing calendar dates as plain YYYY-MM-DD strings — timezone-agnostic by construction.

Before — timezone-sensitive Date comparison

// new Date() parses a bare string as midnight UTC.
// A checkout/checkin on the same calendar day can
// appear to overlap once the property's UTC offset
// is applied.
function datesOverlap(checkOut, checkIn) {
  return new Date(checkOut) >= new Date(checkIn);
}

After — timezone-agnostic string comparison

// Compare calendar dates as YYYY-MM-DD strings.
// No Date object, no UTC offset, no false positives.
function datesOverlap(checkOut, checkIn) {
  const toDateString = (d) => new Date(d).toISOString().slice(0, 10);
  return toDateString(checkOut) >= toDateString(checkIn);
}

It's a small fix, but a reminder that a lot of production bugs come from a mismatch between what a data type represents and what you assume it represents. That's as true of a payout calculation as it is of a checkout date.

A second deliberate decision was soft-assertion overlap checking: rather than stopping at the first conflict found, the suite collects every date overlap across every room type in a single run before reporting. In this domain the cost of missing one instance is a guest turned away or double-booked, so a single-failure assertion pattern wasn't good enough.

Measurable Outcome

The booking flow now runs under continuous, automated verification instead of manual checking, and the specific timezone-drift bug that caused false-positive double-booking alerts has not recurred since the fix shipped. Guest enquiries get an immediate, accurate response regardless of time of day, handled by the WhatsApp bot rather than a person watching a phone.

The broader lesson generalizes past this one project: most production failures in a multi-system workflow live in the handoffs between systems, not inside any single one of them, and a monitoring suite only earns trust by staying quiet and accurate over a long stretch of time.

Read the related engineering write-up →