The Inn Co.
A full-stack direct booking platform for a boutique hotel — room reservations, Stripe payments, self-serve cancellation, and a complete owner admin dashboard. Built to eliminate OTA commissions and give the owner full control over their bookings.
The Problem
Boutique hotels and inns pay 15–25% commission on every booking made through Booking.com, Expedia, or Airbnb — platforms that own the guest relationship and push the property to the bottom of results whenever a larger hotel bids higher. Dedicated hotel software like Cloudbeds or Little Hotelier runs $150–400/month and is designed for large properties, not independent boutique owners. The goal was a direct booking platform the owner controls outright, with no per-booking commission and no ongoing platform fee.
Try It
Previewing at tablet width. Open the full site ↗ for the desktop experience. Also fully optimized for mobile.
Admin Dashboard
The owner manages every aspect of the property from a protected dashboard. No code, no developer on call — every change reflects on the live site immediately. Live read-only demo below — no login needed.
- Reservations — full booking history with guest name, room, dates, status, and special requests
- Availability calendar — tape-chart style grid showing occupancy by room and day; navigate by month
- Room listings — add, edit, and delete rooms with name, slug, price, and description
- Block dates — mark a room unavailable for Expedia bookings, maintenance, or any external source
- Status management — mark bookings confirmed, completed, cancelled, or no-show from the dashboard
- Message guest — send a direct email to any guest from within the dashboard
- Stripe — paste API keys directly in the UI; webhook URL is displayed with step-by-step instructions
- Resend — API key configured from the dashboard; domain verification guidance included
- Pricing rules — set weekend rate multipliers or seasonal date-range rates; highest multiplier wins when rules overlap
- Tax rate — lodging tax configured once in the dashboard; applied automatically at checkout as a separate line item
- Minimum stay — per-room minimum night requirement enforced at booking before the guest reaches payment
- Setup checklist — guided onboarding for non-technical clients, with plain-English tooltips on every API key field
Desktop
Desktop Pages
Click any screenshot to enlarge.
Home — hero with Book Now CTA, property highlights, and room previews.
Rooms — four suites with pricing, sq ft, capacity, and individual booking flows.
Gallery — property photos managed from the admin.
About — property story and philosophy.
Admin — bookings, revenue, occupancy rate, and per-room availability calendar.
Admin detail — revenue stats and the color-coded per-room availability calendar for July.
Mobile Experience
Guest
Admin
Find Your Reservation
Guests look up any booking with just their email and check-in date — no account required.
Technical Implementation
Booking & Payment Flow
The booking confirmation flow is webhook-driven — Stripe fires a checkout.session.completed event after payment clears, which writes the reservation to Supabase and triggers the confirmation email via Resend. A failed or abandoned payment never creates a booking record. After payment, the success page fetches live booking details using the Stripe session_id from the redirect URL and displays the confirmed room, dates, nights, and total paid — no polling, no waiting. Five email flows run through Resend: booking confirmation, cancellation receipt with refund status, pre-arrival reminder sent 2 days before check-in, post-stay review request sent the day after checkout, and contact form notifications routed to the owner.
Automated Email Scheduling
Pre-arrival reminders and post-stay review requests run on daily cron jobs via cron-job.org (free, no Vercel Pro required). Each job hits a protected endpoint on the server with a shared secret header. The server queries the shared booking API for check-ins or checkouts matching that day's target date, then sends the relevant email through Resend for each matching reservation.
Guest Experience
Each suite has its own SEO-optimized URL (/rooms/coastal-suite, /rooms/garden-room, etc.) served by a single dynamic Express route. Room data, meta tags, the Open Graph image, and the canonical URL are all populated client-side from a JavaScript data map. Guests can look up any reservation at /my-booking using just their email and check-in date — no account required. The booking form pre-selects the room when arriving from a room detail page.
Demo Mode
A read-only demo mode makes the admin dashboard accessible from this portfolio without exposing write endpoints or requiring a login. The page detects a ?demo=true URL param and renders pre-seeded reservation and room data client-side, skipping all API calls for data loading. Every mutating action — status changes, form submissions, adding blocks, deleting rooms, saving API keys — is intercepted before it reaches the server and replaced with a toast notification. No demo session ever touches the database.
Cancellation & Refunds
Each reservation is issued a UUID cancel token at insert time. The confirmation email carries that token in a link — no guest account required, and the URL cannot be guessed or enumerated. When a guest clicks the link, the server checks the check-in date: cancellations made more than 48 hours before check-in receive a full refund processed automatically through the Stripe API. Cancellations within 48 hours fall under the hotel's standard policy — no refund is issued and the booking is marked cancelled in the admin.
Auth & Multi-Tenancy
The admin dashboard is protected by Supabase Auth with a rate-limited login endpoint and JWT validation on every protected route. The architecture is multi-tenant from day one — a single middleware reads an X-Tenant-Slug request header and scopes every database query to that property. When an owner saves a Stripe or Resend key via the dashboard, it syncs to both the tenant's local settings table and the shared platform API so checkout sessions and webhooks both use the client's own keys. Onboarding a second hotel means inserting a row and deploying a new Vercel project — no schema changes, no code forks.
SEO
Schema.org Hotel JSON-LD structured data on the homepage enables Google rich results. GA4 is wired to all public pages. Individual room pages have unique <title>, meta description, Open Graph, and canonical tags set dynamically per room.
The Outcome
A direct booking platform the owner controls outright — capturing bookings at zero commission versus 15–25% on OTA platforms. Guests book, pay, get an immediate confirmation with full details, look up their reservation anytime, and cancel themselves — all without any involvement from the owner. Pre-arrival and post-stay emails run automatically every day.
A non-technical client can connect Stripe and Resend, configure their rooms, set lodging tax, define weekend and seasonal pricing rules, and start taking bookings entirely through the admin dashboard — no developer needed after handoff. The multi-tenant architecture means the same platform can be white-labeled for additional properties.
Designed and built solo in two weeks.