A boutique hotel in the commercial heart of old Dhaka was taking every booking by phone or walk-in. I designed and built its direct-booking platform end to end — guest site, hotel operations API, and everything in between.
Guests booked by phone or walked in off the street. The hotel had no direct online channel, no way to show its rooms to the travelers already searching for them, and no system of record for availability beyond the front desk.
A complete direct-booking platform: a guest-facing site that feels as considered as the hospitality it sells, and a backend that runs the hotel's real operations — rooms, availability, bookings, guest verification, and email. Designed and built by one person, both sides.

Instead of assembling a generic hotel template, I defined a small design system and derived every screen from it: a tuxedo palette of pure white and deep charcoal with a single refined gold reserved for the moments that deserve it, Playfair Display headlines over Inter UI text, and sharp geometry — zero border radii anywhere, with depth coming from tonal layering and 1px dividers instead of drop shadows.
The system holds from the cinematic full-bleed hero, under its transparent blurred header, all the way down to the PDF invoices and transactional emails. A guest sees one brand from first visit to inbox.

The suites listing pairs every room with a sticky filter sidebar — date range, guest count, room type, a price-range slider, price sorting, and amenity chips. Every filter is encoded in the URL, so a guest can send "the exact rooms I'm looking at" to a travel partner, and the query executes server-side.
Each room detail page carries a gallery, per-room facts, and a sticky booking widget that knows that room's real availability before the guest ever commits.

Date pickers are where booking UIs usually fall apart: two calendars that don't talk to each other and a guest dropdown off to the side. I built a single component that turns the whole selection into one guided flow — click any field and a popover opens anchored beneath that exact field, with a step rail across the top. Picking check-in auto-advances to check-out, check-out advances to guests, and the popover physically slides under the active field using a virtual-anchor technique over Radix's positioning engine.
That one component powers the home hero, the room-detail widget, the reservation form, and the listing filters. On phones it collapses to a single month, scales its touch targets up, and clamps itself to the viewport.

Availability is layered — confirmed bookings, admin-blocked dates, seasonal price overrides, room status. The API filters each room's bookings at the database level, so calendars never gray out dates a past guest occupied. The client merges those ranges into disabled intervals, prices each night individually, and re-checks availability server-side at the moment of submission — closing the race between two guests eyeing the same dates.
Privacy got the same rigor: managing a booking requires email and booking reference together, matched server-side. Knowing someone's email alone reveals nothing about their stays.

Guests need proof of booking, and hotels need it to look right. Instead of rendering invoices three different ways, the backend owns a single branded PDF generator — charcoal masthead, gold rules, itemized stay, total band — that feeds a public download endpoint, the confirmation email (redesigned as an invoice itself, with the PDF attached), and the Receipt buttons on the success screen and booking-management page.
Change the invoice once, and every surface — web, email body, attachment, download — updates together.

Behind the guest site sits an Express API with a layered architecture — controllers, services, repositories over typed Mongoose models, with Joi validation at every route boundary. JWT auth with role-based permissions guards the staff and admin endpoints; rooms carry per-date availability overrides and seasonal pricing; guest ID uploads flow through a file pipeline to DigitalOcean Spaces with per-category MIME allowlists and size limits.
Errors stay honest the whole way up: the backend's typed error shape carries real messages to the guest — never a bare "HTTP error 400."
The StayPicker guides check-in → check-out → guests in one popover, computing nights live.
A four-step reservation form with national-ID upload for the hotel's guest verification.
Availability is re-verified server-side at submission, closing the two-guests-one-room race.
One branded PDF lands on the success screen, in the confirmation email, and behind every Receipt button.
Hotel The Manha went from walk-ins and phone calls to owning its bookings end to end. If your business is running on a process it has outgrown, I can build the platform that replaces it.