←

Lancaster Hotels

One website template, twenty-one live sites: every Lancaster hotel, suite and resort from Beirut to Djerba, each with its own admin, its own database and its own domain.

Twenty-one hotels, one codebase.

One website template, twenty-one live sites: every Lancaster hotel, suite and resort from Beirut to Djerba, each with its own admin, its own database and its own domain.

live · multi-site platform · hospitality · five languages

  • 21Sites on one template
  • 5Languages, incl. Arabic RTL
  • 1,000+Commits across the repos
  • Mar → Aug 2026Built in

Lead developer

I designed and built all twenty-one hotel websites: the UI and UX, the front-end and API code, the admin panel and the way each site connects to it, the server and the deploy pipeline. Layth Ayache worked alongside me on property forks, content and media.

  • UI and UX design for the public sites and the admin
  • Front-end, API and admin panel for all twenty-one sites
  • Server, Caddy, systemd and the deploy pipeline
  • Content model, five languages, AI concierge and forms

Who did what

  • Tayseer

    All twenty-one hotel websites: web development, UI and UX design, the admin panel and its connection to every site, architecture and infrastructure

  • Layth Ayache

    Property forks, content seeding, photo scraping from the legacy sites, admin population

Structure, design and layout

Before the first site shipped, one plan had to work for every hotel: a page structure every property shares, a design system that carries a luxury brand without looking the same twice, and a layout every page is built from.

Site map, every property

Stay
  • Home
  • Rooms & suites
  • Room detail
  • Offers
  • Offer detail
Experience
  • Dining
  • Dining venue
  • Events
  • Event venue
  • Wellbeing
  • Wellbeing detail
  • Facilities
  • Gallery
Hotel
  • About
  • Contact
  • Booking
Chain hub only
  • Our hotels
  • Locations
  • Lancaster Loyalty
  • Media hub
  • Article
  • Careers
  • Development
Legal
  • Privacy policy
  • Cookies policy
  • Not found

Design system

  • Navy#173A63
  • Lancaster red#C41E3A
  • Ink#1A1A2E
  • Paper#FAF9F7
  • Surface#FFFFFF
  • Muted#6B7280
Headings
Aire Bold Pro, a high-contrast serif, with Cormorant Garamond as fallback
Body and UI
Gotham, with Montserrat as fallback; GE Hili for Arabic
Scale
Six sizes from 0.7rem labels to a fluid display at clamp(2.6rem, 6vw, 5rem)
Radii
2, 4 and 8px, plus pills for buttons: sharp, hotel-brochure corners
Containers
1280px wide, 880px narrow, 720px for reading

Page layout

HEADERHERO SLIDESHOWSUB-NAVOVERVIEWCARD GRIDNEWSLETTERFOOTER
Header
Hamburger and search on the left, the hotel's own logo centred, language, log in and Reserve on the right. Transparent over the hero, solid once scrolled.
Sub-nav
The hotel name plus Overview, Accommodation, Offers, Dining, Events, Wellbeing, Facilities and Contact, pinned under the hero on every page.
Hero
Full-bleed slideshow from the admin's hero slides, the page title in serif at the bottom left, arrows and dots.
Sections
Seven reusable blocks: overview, rooms, card grid, facilities, wellbeing, contact and newsletter, composed per page.
Listings and details
One listing layout and one detail layout shared by rooms, dining, events, offers and wellbeing, so every content type looks and behaves the same.
Footer and overlays
A full-screen navigation, a search overlay, the cookie bar and the AI concierge bubble, identical across the chain.

How it was built

  1. 01

    One template, cloned per hotel

    lancaster-acra is the canonical template. Each property is a clone with its own repo, its own GitHub variables for the hotel name, description and booking URL, and its own branch rules. Changes to the template are pulled into the forks.

  2. 02

    Admin and content model

    A React admin inside the same Vite app, with a generic content editor over ten tables: rooms, dining venues, event venues, facilities, gallery images, hero slides, news articles, offers, page content and wellbeing sections. Rich text through TipTap, sanitised with DOMPurify, ordered with dnd-kit.

  3. 03

    Five languages

    English, French, Arabic, Chinese and Vietnamese through i18next, with the admin's Translations page editing the locale files per site and Arabic rendering right to left.

  4. 04

    The AI concierge

    A chat route on each site that answers as the hotel's front desk, grounded in that hotel's rooms and venues, limited to the Lancaster group, with per-site custom instructions edited in the admin. Rate-limited per visitor.

  5. 05

    Forms

    Contact, careers and newsletter forms verified with reCAPTCHA, rate-limited, stored as submissions in the admin and emailed to the hotel.

  6. 06

    Branding per site

    Logo, share image, phone numbers, emails, social links, header and footer, SEO fields and page visibility, all in a site-settings table read by the public site at load.

  7. 07

    Media

    A single public-read bucket with one folder per hotel. The API signs uploads from the admin; the hero slider and galleries read the public URLs directly.

  8. 08

    Security

    Helmet, CORS allow-lists per site, three rate limiters for public, forms and chat, session auth for the admin, and no secrets in any repo: real values live on the server and in GitHub secrets.

Stack

Front end
Vite + React single-page app, Framer Motion, react-helmet-async for per-page SEO, served as static files.
API
Express on Node 20, one systemd unit per hotel on its own port.
Data
One Postgres database per hotel on a shared instance, each with its own user.
Media
Google Cloud Storage, one bucket, one prefix per hotel.
Edge
Caddy on the VM with one virtual host per hotel and the chain hub as the catch-all. Custom domains such as lancasterplaza.com point at the same box.
Deploy
Push to main runs a GitHub Action that builds the SPA, copies it over SSH, and runs the deploy script for that hotel's slug, with a health check at /api/health.
Earlier iteration
Accra first shipped on Vercel with Supabase before the move to the single VM that now runs all twenty-one.

The final product

Eight of the twenty-one live sites, captured from the servers today.

Also on the template: Lancaster Accra, Tamar, Lancaster Suites and Lancaster Hotel in Raouche, Re-Ndama in Libreville, Michelangelo, Al Salam Resort, and six Djerba properties: Djerba, Narjis, Suites Al Manara, Dhalia, Zahra and Yasmin.

What every site does

The same pages and the same admin on every property, filled with that hotel’s own content.

  1. Rooms and suites
    01

    Rooms and suites

    Every room is a database row: bed type, capacity, amenities, gallery and a book-now link that opens the hotel's booking engine. Listings and detail pages share one layout component.

  2. Dining, events and wellbeing
    02

    Dining, events and wellbeing

    Restaurants and bars, meeting and event venues, and spa and wellbeing sections each follow the same listing-and-detail pattern, so adding a venue is one admin form.

  3. Gallery and hero
    03

    Gallery and hero

    Hero slides and gallery images live in one Google Cloud Storage bucket with a prefix per hotel, uploaded straight from the admin, reordered by drag and drop.

  4. The chain hub
    04

    The chain hub

    The group site lists every property, carries the loyalty programme, the media hub with articles, careers with an application form, and the development page for new hotels.

  5. The admin
    05

    The admin

    Each site has its own Lancaster CMS at /admin: dashboard, analytics, a page editor for the hero and every banner, content tables for rooms, dining, events, wellbeing, offers, gallery and news, submissions, supplier offers, a media library, the chatbot's instructions, branding and settings, and translations in all five languages.

How it was built

  1. 01

    One template, cloned per hotel

    lancaster-acra is the canonical template. Each property is a clone with its own repo, its own GitHub variables for the hotel name, description and booking URL, and its own branch rules. Changes to the template are pulled into the forks.

  2. 02

    Admin and content model

    A React admin inside the same Vite app, with a generic content editor over ten tables: rooms, dining venues, event venues, facilities, gallery images, hero slides, news articles, offers, page content and wellbeing sections. Rich text through TipTap, sanitised with DOMPurify, ordered with dnd-kit.

  3. 03

    Five languages

    English, French, Arabic, Chinese and Vietnamese through i18next, with the admin's Translations page editing the locale files per site and Arabic rendering right to left.

  4. 04

    The AI concierge

    A chat route on each site that answers as the hotel's front desk, grounded in that hotel's rooms and venues, limited to the Lancaster group, with per-site custom instructions edited in the admin. Rate-limited per visitor.

  5. 05

    Forms

    Contact, careers and newsletter forms verified with reCAPTCHA, rate-limited, stored as submissions in the admin and emailed to the hotel.

  6. 06

    Branding per site

    Logo, share image, phone numbers, emails, social links, header and footer, SEO fields and page visibility, all in a site-settings table read by the public site at load.

  7. 07

    Media

    A single public-read bucket with one folder per hotel. The API signs uploads from the admin; the hero slider and galleries read the public URLs directly.

  8. 08

    Security

    Helmet, CORS allow-lists per site, three rate limiters for public, forms and chat, session auth for the admin, and no secrets in any repo: real values live on the server and in GitHub secrets.

Stack

Front end
Vite + React single-page app, Framer Motion, react-helmet-async for per-page SEO, served as static files.
API
Express on Node 20, one systemd unit per hotel on its own port.
Data
One Postgres database per hotel on a shared instance, each with its own user.
Media
Google Cloud Storage, one bucket, one prefix per hotel.
Edge
Caddy on the VM with one virtual host per hotel and the chain hub as the catch-all. Custom domains such as lancasterplaza.com point at the same box.
Deploy
Push to main runs a GitHub Action that builds the SPA, copies it over SSH, and runs the deploy script for that hotel's slug, with a health check at /api/health.
Earlier iteration
Accra first shipped on Vercel with Supabase before the move to the single VM that now runs all twenty-one.