Superhero Hotel Booking
Rebuilding Superhero Hotel's two booking flows, the 4-Week Stay and the nightly Day-by-Day, around one rule: never let the interface lie about price, scarcity, or time.
TL;DR
- Role
- Senior Product Designer, sole designer end to end, research through implementation
- Team
- Christian Peters (founder, product direction), Michalis Vasileiadis (backend engineering), Liz (front desk, operational ground truth)
- Timeline
- June 26 to July 10, 2026, about two working weeks across three calendar weeks
- Stack
- Next.js App Router, TypeScript strict, Tailwind v4, shadcn/ui, react-day-picker, Stripe PaymentElement, Playwright for the E2E suites
- Outcome
- Both booking flows redesigned and delivered as review-ready pull requests, with 31 passing end-to-end scenarios at handoff. The founder reviewed the proposed best-window pricing experience in two live sessions and approved it: it replaces fabricated scarcity with transparent, inventory-informed price comparisons. The backend pricing algorithm behind it is on hold pending a roadmap decision. The audit also surfaced three production bugs. No live business impact has been measured.
The problem
Superhero Hotel sells a fixed 28-day stay to startup founders visiting San Francisco's Frontier Tower. The founder's brief named four problems. Pick a start date near the edge of the calendar and your checkout month never rendered, so guests committed to a stay whose end they had never seen. The picker itself was a free date-range control strapped onto a fixed-length product. He wanted the flow to propose optimal start dates instead of accepting arbitrary ones. And arbitrary dates were expensive in a way nobody was tracking.
“You don't see it if across different months… you can't even see the end date… the two-month window is not a good thing.”
One guest leaves July 28, the next arrives August 10: 13 nights nobody can sell. Across a hotel's worth of rooms, that is the difference between a packed calendar and a leaking one.
Walking both live flows on video, my audit across the 4-Week Stay and the nightly widget turned up more than the brief named. The ones it didn't name were about trust: the flow showed “Only 2 rooms left” counters that were random numbers, capped at 3 by design, and payment was full and non-refundable, disclosed late. A conversation with the front desk added two more that no screen could show. My read: founders were at least as likely to abandon at trust as at calendar mechanics.
Named in the brief
4- The calendar hides the checkout. The two-month picker never advances, so a later-month start puts the checkout in a third month that never renders. On mobile, only one month shows at all.
- A free date-range picker strapped onto a fixed 28-day product, implying you can pick any two dates.
- The flow accepts arbitrary start dates instead of proposing the optimal ones.
- Arbitrary starts strand inventory: one guest leaves on the 28th, the next arrives on the 10th, and 13 nights go unsold.
Surfaced in my audit
+5- Fabricated scarcity. “Only N rooms left” was a random 1 to 3 that re-rolled on every refresh; git blame proved it was capped on purpose.
- Full, non-refundable payment, disclosed late, right at the moment of commit.
- The nightly widget priced before tax and duplicated the entire guest form.
- That same widget dead-ended on sold-out dates instead of offering an alternative.
- A rate-tier inversion in the live prices: six nights totalled less than five, $766 against $1,200.
Front-desk interview
+2- The live flow only took a second guest through the Double, but the hotel's direct policy lets partners share the Suite's king bed: one founder per one-bed room, two if partners, two at most in the Double. That policy lived only at the desk, and it differs from the OTAs' two per single and four per double.
- Found in my audit, confirmed at the desk: bank transfer left the room unheld while the transfer settled, so any promise to hold the guest's dates would have been false. Liz confirmed there's no hold procedure.
My role
Sole designer, end to end: the research, both flows, the founder feedback and review sessions, an interview with front-desk operations, and the handoff to backend engineering. Every design decision and every QA catch was mine, including the pricing inconsistency below, the step-overload call, and the copy that had to be rewritten. Claude helped synthesize the competitor research. I verified everything I delivered by breaking the flows in the browser at five viewports and tabbing through every step.
Two working weeks from brief to handoff, June 26 to July 10, 2026.
Discovery
Start from the live flow, not the brief
Instead of designing against the founder's four problems, I started from evidence: I walked the live flow on video and mobile screenshots, read the git history, and probed the production APIs read-only. Of everything that surfaced, the most interesting finding looked like a bug and wasn't. The scarcity counter was fabricated deliberately: the founder's own commit capped it at a random 1 to 3 because raw inventory (“36 rooms left”) weakened the signal. That finding set the shape of the whole project: the business goals were real, the mechanisms were the problem. It also gave me the question I carried into every other source: where else is the interface promising something nobody behind it can back?
Who's booking
One primary user, defined in the PRD (product requirements doc) and held to: the founder relocating to Frontier Tower for a working stint. They think in months and rough windows, not check-in/check-out dates, so “which month” comes before “which dates.” They're committing thousands sight-unseen, which is why non-refundable prepay next to fake scarcity reads as risk, not urgency. And their flexibility on start dates was an assumption I flagged for validation rather than a fact, so exact-date entry stayed first-class instead of being designed away. The tourist on a short, specific-date stay was explicitly deprioritized to the nightly track.
Empathy map: The Founder
PRIMARY PERSONA · LONG-STAY, STRATEGIC · RELOCATING TO OR VISITING FRONTIER TOWER FOR A WORKING STINT
- Founder / operator / builder
- Often referral-driven
- Time-poor, certainty-seeking
- Some date flexibility, to validate
Says
- “I'm coming to SF around August for about a month.”
- “Just need somewhere to live and work, sort it for me.”
- “Is this the real price, or does it balloon at checkout?”
- “I'll be here for the cohort / demo day.”
Thinks
- I think in months and rough windows, not check-in/out.
- Decide the month first; exact dates can come later.
- I have some flexibility, but my lease / flight may not.
- Don't make me hunt for a bargain; just be fair.
Does
- Arrives via referral; trusts the network.
- Compares a few options fast, then commits.
- Books a working stint near Frontier Tower.
- Picks the guided ‘best’ option if it's clearly fair.
Feels
- Time-poor, wants certainty over endless optionality.
- Wary of dynamic pricing and hidden fees.
- Trust-sensitive: committing thousands sight-unseen.
- Reassured by transparency and a real confirmation.
Pains
- Calendar defaults to a near-over, mostly-booked month.
- Range picker implies ‘pick any two dates’ for a fixed stay.
- Teaser price, then about 30% reveal-shock at checkout.
- ‘Confirmed’ that isn't; refund / cancellation anxiety.
- Fake ‘only N rooms left’ erodes trust on refresh.
Gains
- Pick a month, see a few optimal 28-day slots, done.
- Best-priced slot framed as a carrot, transparently.
- All-in (tax-incl) pricing kept in the new slot list, already shown; don't regress.
What the front desk knew
The audit showed me what the interface said. It couldn't tell me whether the hotel could keep its word, and the person who knows that is the one behind the counter. So I sat with Liz at the front desk for an open-ended conversation (we spoke in Taglish). Rather than limit it to the problems the brief already named, I asked how bookings actually work on the hotel's side and where the guest-facing flow might part ways with operations. Two findings directly shaped the redesign.
Occupancy is governed by hotel policy, not OTA conventions. On direct bookings a one-bed room takes one founder, or two guests if they're partners; the Double's two beds take two guests at most. Relationship only matters when two people share a bed. The OTAs (online travel agencies) sell the same rooms at two per single and four per double. The direct flows now enforce her two-guests-per-room cap, not the OTA's, and it drives the room step's capacity math (below). The partner rule is guidance in the copy rather than a hard block, with the formal rule left to the terms and check-in. My first draft of the guest copy framed the second guest around “partners and married couples.” I rewrote it for the customer the hotel actually serves, founders, around the beds instead of the relationship: “Bringing your partner? You'll share the Suite's king bed. Traveling with a co-founder or friend? The Double has two separate beds.”
No room is held while a bank transfer settles. I'd found it in the live Stripe states, and Liz confirmed there's no hold procedure at the desk, so any “we're holding your dates” promise would have been false. That turned a copy problem into a product decision (below): I took it to the founder, and he switched bank transfer off. “We should just deactivate it.” The occupancy policy wasn't visible from any screen, and the hold gap only became certain once the desk confirmed it; both became constraints the redesigned flows had to respect.
What the research showed
Liz told me what the hotel could promise. The research had to answer the question the fake counter left open: if not fabricated scarcity, what can the founder's urgency stand on? Two research waves ran before any pricing UI got designed: published UX and pricing evidence first, then a competitor teardown with review mining. The findings converged. The providers and pricing practices I reviewed pointed toward transparent price differences and genuine savings, not fabricated inventory counters. Blueground's pricing presentation gave a reference for framing price differences as savings rather than penalties. And the reviews I analyzed surfaced recurring concerns around cancellations, refunds, and unexpected fees, which I recorded as competitive trust considerations, not as validated problems among Superhero Hotel's own guests.
When gap pricing came up, I pushed for rigor over instinct: research other providers first. The revenue-management tools (PriceLabs, Beyond, Wheelhouse, OwnerRez) treat orphan gaps with discounts of 20 to 35% and prevent them with stay restrictions; none of them surcharges the booking that creates the gap.
Across the four revenue-management tools reviewed: orphan gaps get 20–35% discounts and prevention via stay restrictions. None surcharges the gap-creating booking, so the penalty framing we almost shipped would have been an outlier.
The same research named the endgame pattern (price-per-date calendars, the Google Flights model) as the next iteration once live pricing flows, and fed the backend brief: score both edges of the 28-day block, the arrival gap and the trailing fragment.
I also studied Airbnb's flexible-dates system from recordings: the continuous-scroll calendar that solves our hidden-checkout bug, all-in pricing, and a “free cancellation” selling point this non-refundable product can't match, a competitive gap worth knowing rather than hiding. A read-only scrape of the live nightly rates across six rooms and six stay lengths surfaced a price inversion (6 nights cheaper than 5 in total) that went straight to the founder.
Synthesis
Different problems, one design challenge
The findings came from different sources and had different causes: a calendar defect, a deliberate business decision, a pricing inconsistency, an operational limit. What connected them was the challenge they added up to: help guests make informed booking decisions without the interface misrepresenting the hotel's inventory, pricing, or operations.
I translated these findings into three principles, and every decision below answers to at least one:
- Keep the goal, challenge the mechanism. Urgency, inventory use, and full prepayment were real business needs. The design question was how to pursue them without misleading scarcity or late disclosure.
- Show the whole commitment before the commit. The dates, the all-in price, and the cancellation terms are on screen before the Pay button, never after it.
- Promise only what the system and the operation can support. Room capacity, availability, and payment states reflect the hotel's actual rules and technical capabilities.
Where each finding landed
Source · what it caught · what it became
- Live auditA fabricated “only N rooms left” counter, and non-refundable terms disclosed at the moment of commitA proposed best-window pricing experience, and the cancellation policy moved above Pay
- Founder's briefA checkout month that never rendered, and a free range picker on a fixed 28-day productOne continuous calendar, the full stay and checkout always in view
- PersonaFounders think in months, and their date flexibility is an assumption, not a factMonth-first entry, with the exact-date tab kept first-class
- Front deskOccupancy set by house policy, not the OTAs, and no room held while a bank transfer settlesA capacity-gated room step, and bank transfer cut rather than overpromised
- IndustryNone of the tools reviewed surcharges the booking that creates a gap; the operators who price it frame it as a savingThe founder's penalty model flipped to “best price for them”
- Rate scrapeSix nights totalling less than five, $766 against $1,200Escalated to the founder, and the real tier break written next to short stays
The 4-Week Stay
Urgency without lying
The proposed replacement makes urgency a property of the offer instead of a counter: the flow presents a handful of real, gap-free “best windows” each month at the lowest price, and windows that strand empty nights cost visibly more, with the reason written next to the price (“Starts 4 nights later than the best window, so it's priced a little higher”). Scarcity became “the good windows are genuinely few,” which has the advantage of being true.
The founder had originally asked for a penalty framing: prices increase as you drift from optimal. Competitor research supported flipping it. Blueground frames the same economics as “save money by booking a move-in closer to an apartment's availability date,” pricing the operator's need as the guest's discount so both sides win the same transaction. I presented that flip as his call to make, with the evidence, rather than just shipping my preference. It became the model he approved:
“High occupancy for us, best price for them.”
To be precise about status: the experience is designed, built in the interface, and approved. The algorithm that scores windows against live inventory is the backend piece still pending, so the window prices in these screens show the interaction, not production pricing.

The audit's other trust finding closed in the same spirit. Full prepay at booking stayed, that was the founder's deliberate call, but its terms stopped arriving late: both flows now put his exact cancellation policy in its own inset before the Pay button, so the non-refundable commitment is read before the commit, not discovered at it.

Guide only where the constraint is real
Curated windows make sense in busy months. But in a wide-open month, “3 best windows” is fake curation: every start date is equally optimal. The founder spotted it in review and sketched the answer: when everything is open, just show the calendar.
“For September there is no such thing like an ideal start date.”
My first build gave open months their own embedded calendar. Then I asked the question that killed it: with an exact-date calendar one tab away, isn't this redundant? It was. The delivered version makes wide-open month chips navigational: tap “October · Wide open” and you land on the one calendar, scrolled to October, with a banner explaining that every start date gets the best price. One calendar in the whole flow. Which months flip between curated and open is specified as a per-month backend decision, so the interface is built to adapt as occupancy grows without a redesign.
That one calendar is also where the brief's first problem dies. It scrolls continuously (the Airbnb pattern from the research) instead of paging two fixed months, the full 28 days shade across month boundaries, and check-in and checkout stay pinned in the summary below it. Nobody commits to an end date they have never seen.
The date decides the price, never the tab
Testing my own flow, I picked July 9 in the flexible tab: $1,900, best price. Then I picked the same July 9 on the exact-date tab: $1,980, standard rate. Same stay, two prices, depending on which button you had clicked. Nobody had specified this case, and it would have shipped.
The fix became a rule with a name: the date decides the price, never the tab. In the interface, an exact-date pick that matches an optimal window now shows that window's price; a suboptimal pick shows its uplift and offers a one-tap “Best-price start” upgrade. The rule then outgrew the frontend: it went into the backend handoff as a contract requirement that every number a guest sees, taxes included, comes from the pricing API.

The Day-by-Day
Two flows that behave like twins
The hotel's nightly track (1 to 27 nights) ran through an embedded third-party widget: prices shown before taxes, duplicated guest forms, and dead-ends on sold-out dates. I brought it in-house as the 4-week flow's sibling: same steps, same validation behavior, so a guest who learns one flow has learned both.
The parity ran both directions. When I judged the 28-day flow's first step overwhelming (dates, guests, and rooms stacked on one screen), the fix came from the nightly flow's structure: room selection became its own step. When the nightly flow got press-to-validate (an always-enabled button that marks every missing field and focuses the first one), the 28-day flow got it the same day. I had originally deferred inline validation to keep the prototype moving; an audit I ran against the flow ten days later named that deferral its weakest point, and I reversed it the same day.

The widget's failure points, handled
The old widget's dead-ends became moments the new flow designs for:
- Sold out is caught at selection, not after you've committed to a room. A “We're full for these dates” card offers two one-tap alternative windows of the same length, with WhatsApp and email as the human fallback.
- 28 nights or more steps aside. The nightly path hides and a routing card hands you to the 4-Week Stay flow, carrying the check-in date you already picked.
- All six room categories render as full cards, price-sorted, and the cheapest room that fits your party wears a Recommended badge. Groups get per-category room steppers with a live capacity tally (“2 rooms · sleeps 4 · Room for 4 of 7 guests”), and Continue stays gated until everyone fits. The capacity per room is the house policy from the front desk, not the OTA's.
- Two-tier pricing became an honest hint. I scraped the live rates across six rooms and six stay lengths to model the real tier break, then wrote it next to short stays: “Stays of 6 nights or more get a lower nightly rate.”
- A declined card is a designed state. A destructive banner, the form preserved, a retry that works, tested against Stripe's decline test card.

Explored and killed
Built, then killed by taste
- An Airbnb-style two-mode picker with ±3 days flexibility chips. Built, then cut: the flexibility math complicated the packing model for marginal benefit. The simpler month-first flow survived contact with the founder twice.
- Collapsible room rows. I proposed showing only the recommended room expanded. It passed every automated test, and I still killed it after seeing it: burying rooms behind a tap made the page tidier at the cost of trust. All six rooms render as full cards.
The invisible work
None of this shows up in a screenshot. It shows up when you tab through the flow, refresh mid-booking, or book from the wrong timezone. It is most of what separates a prototype from something you would trust with a card.
Hotel-time everywhere
“Today” is computed in San Francisco time regardless of the visitor's timezone. A founder booking from Manila at 2am sees the same calendar the front desk sees. A subtle server-side variant of the same bug (a long-running process freezing “today” at boot) got the same treatment.
Copy that never overpromises
Every “we're holding your dates” line came out of the flow (why). With no honest version of bank transfer left, I brought it to the founder and he switched the option off rather than ship a promise the backend couldn't keep.
Focus that follows intent
Tap a wide-open chip and focus lands on the banner that explains where you are. Step changes focus the new heading, and the photo lightbox traps Tab. None of it shows up until you put the mouse down and Tab through the flow.
State that survives
Refresh mid-booking and your draft restores. Browser Back steps backward through the flow instead of ejecting you. “Edit booking” from the payment step returns you to the start with nothing retyped. The exception is card details, which the flow never writes to storage.
Where it stands
Both flows were delivered as pull requests and in review at handoff, with the pricing algorithm assigned to backend engineering against my spec. What stands behind them:
- The founder reviewed the flow in two live sessions and approved it in the second (“That looks all good”); both of his change requests from the first (current-month availability, windows visible on load) were built the same day.
- I briefed backend engineering against my handoff spec, and the pricing algorithm was assigned to be built against the contract it defines; that build is on hold pending a roadmap decision, so there are no live results yet.
- The cancellation policy is in the founder's own wording, kept at his request. My part was where it sits and when the guest reads it, not what it says.
31 automated end-to-end scenarios across the two flows, green at handoff, covering the full booking paths, validation, focus management, and a 320 to 1920px responsive sweep.
Accessibility addressed throughout both flows: measured text contrast, 44px touch targets, keyboard focus management, and a reduced-motion alternative on every animation.
- Research along the way surfaced three live production bugs (the hidden-checkout calendar, a schema.org price rendering “$undefined/night” to Google, and a rate-tier inversion where 6 nights cost less than 5), all documented for the team.
In hindsight
What this project taught me
Make data access a condition of the brief. We asked for funnel analytics in week one and designed three weeks without them; every “where do founders actually drop?” debate ran on judgment instead of evidence. Judgment held up, but I'd rather have known. Delivery and impact are separate milestones, so the baseline comes first next time: with the pricing build on hold, the honest next step is instrumenting step drop-off, the share of bookings that land in best windows, and gap nights per month before anything ships, so the redesign gets judged instead of believed.
Bring operations in at discovery, not at QA. One conversation at the front desk changed two product decisions that no amount of screen auditing would have caught. The interface is only the visible part of the service; its promises get kept, or broken, behind the counter.
Two habits this project hardened. Check history before overriding: three things that looked like obvious bugs (the fake counter, the penalty pricing, the full prepay) were the founder's deliberate decisions, and the git log proved it. I brought each counter-proposal back with evidence and kept the decision where it belonged, with the business owner; all three ended in agreement. And hold the brief steady under dramatic findings: when competitor research surfaced a reframe (“the real risk is post-booking trust”), I tested it against the brief, confirmed the founder's direction was sound, and filed the reframe as a watch-out instead of a pivot.
Credits. Christian Peters (founder): product direction, pricing model, two rounds of live review. Michalis Vasileiadis: backend engineering, assigned the pricing algorithm. Liz (front desk): operational ground truth on occupancy policy and payment reality.
Next project
2026 · Web
