Case Study · Travel & Tourism

A bilingual tour booking platform, built on top of the operations software that runs it

Alam Al-Munawara sells guided historical tours in Madinah, Saudi Arabia. We built the public Arabic and English website, the six-step booking and payment flow, and the back office their team uses to run guides, vehicles, pricing, content and customer messaging — as one system, not three.

Client
Alam Al-Munawara, Madinah, Saudi Arabia
Sector
Guided tours & travel experiences
Our role
Full-stack design, build and ongoing development
Status
Live and in active development
  • 2 public languages, Arabic RTL and English
  • 45 modules in the admin back office
  • 2 separate portals, admin and tour guide
  • 57 database tables behind it
  • 11 scheduled background jobs
  • 203 automated test files
  • ~93k lines of application PHP

Watch the walkthrough

Nine minutes through the whole platform: the public site in both languages, the booking flow end to end, the operations back office, and the separate portal the guides use.

Try the front end yourself

A working copy of the public site. Browse the tours, switch the whole thing into Arabic, and take a booking as far as the payment step — nothing is charged and no booking is confirmed.

Open the live demo

Opens in a new tab

Ask to see the back office

The administration area and the guide portal hold real bookings, payments and customer records, so they are not open to the public. We will take you through them on a call instead, and you can stop us anywhere you want a closer look.

Book a walkthrough

About 30 minutes, no obligation

The brief

The business had tours, guides, vehicles and a steady stream of pilgrims and visitors who wanted to book them — and no system. Enquiries arrived by phone and WhatsApp, availability lived in someone's head, prices were worked out per enquiry, and every change to the website meant calling a developer.

Two things made it harder than a standard booking site.

The first is language. The audience is roughly half Arabic-speaking and half not, and guides work in Arabic, English, Turkish, Urdu/Hindi and Persian. Arabic could not be a second-class afterthought: it had to be a fully right-to-left site with its own content, its own URLs and its own emails and messages.

The second is that a booking is not just a seat. It reserves a specific guide, on a specific date, in a specific time slot, speaking a specific language, in a vehicle sized for the group — and the price depends on all of it. Two customers reaching the payment screen at the same time must not be sold the same guide.

The public website

Every word, image, price and section on the public site is managed by the client's own team. There is no hard-coded marketing copy. Pages, menus, sliders, blog posts, FAQs, attractions, itineraries and the reusable content blocks that make up each page are all records they can edit, reorder and publish in either language.

How the bilingual side actually works

Arabic and English are separate content, stored side by side on each record and served under separate URL prefixes, so each language is independently indexable and independently editable. When an editor saves English content, a translation job is queued rather than run inline; a scheduled worker then drafts the Arabic through Google Cloud Translation and marks the record's translation state in the admin listing. The team reviews and corrects it before it goes out. Machine translation gets them to a first draft quickly; it never publishes unreviewed.

The front end is Tailwind CSS compiled to a single stylesheet, with hand-written JavaScript for the parts that need it — the availability search, the date picker, the booking wizard, the phone-number input, the gallery. No framework, no hydration cost. The pages render on the server and stay fast.

The booking and payment flow

Six steps: details, date and time, tour options, guide, review, payment. The flow is deliberately linear and deliberately saved at every step, because the people using it are often on hotel wifi or roaming data in a city they do not live in.

  1. Booking step 1: Your details
  2. Booking step 2: Date and time
  3. Booking step 3: Tour options
  4. Booking step 4: Guide
  5. Booking step 5: Review
  6. Booking step 6: Payment

Step 1 of 6 — Your details Name, email, country, mobile and the number of people, then the pickup point — which autocompletes against a places lookup rather than being typed free-hand, so the driver gets an address that exists.

The parts that were worth getting right

Guides stay reserved

Selecting a guide temporarily holds that time slot. This prevents double bookings and releases the slot automatically if checkout is not completed.

Pricing stays consistent

One shared calculation handles margins, tax, discounts and rounding. The same total appears on tour cards, during checkout and in confirmation emails.

Payments stay secure

Moyasar's hosted form handles card details directly. The server verifies payments, refunds and signed webhooks without storing sensitive card data.

Rewards stay controlled

Discount rules are checked during checkout and can be limited by tour or customer. Referral commission is tracked automatically for completed bookings.

The back office

This is the half of the project a visitor never sees and the client uses every day. Forty-five modules covering tours, categories, attractions, time slots, languages, vehicles, guides and their availability, bookings, payments, refunds, discount codes, referrals, reviews, contact requests, pages, menus, sliders, blog, FAQs, email and WhatsApp templates, site settings, admin users and permissions, audit logs and traffic. Tour guides get a separate portal of their own.

Screenshots come from the development instance, which runs on seeded sample data. The figures shown are not the client's trading numbers, and the customer name, email, phone and pickup address in the booking screenshots have been replaced with placeholders.

One module, end to end

Forty-five modules is a number that means nothing until you see one of them. Tours is the largest, and it is worth showing in full because it is where the bilingual content model, the pricing inputs and the media handling all meet.

One module is designated the canonical pattern and every other module follows it. That is why the forms, listings, filters, bulk actions, validation messages and empty states are consistent across all forty-five — and why adding the next one is a known quantity rather than a fresh invention.

A separate portal for the guides

Guides are not admin users with fewer checkboxes. They get their own application behind the same sign-in screen, with its own navigation, its own dashboard and its own data boundary — a guide can only ever see the bookings assigned to them and the availability they own.

This matters operationally more than it looks. Guides maintain their own calendar, so the business stops being the bottleneck for "is Nabil free on the 12th". They start and end tours from their own screen, which is what populates the tracking panel on the admin booking and what triggers the automatic stop if a tour is never closed out. And because they never touch the admin area, nobody has to decide which of forty-five modules a guide should be trusted with.

Engineering decisions worth explaining

Reliable notifications across channels

Email and opt-in WhatsApp messages cover confirmations, cancellations, refunds, reviews and referral commissions in both languages. Idempotent retries recheck consent, stop after three attempts and sync Meta approval status without duplicating a successful send.

Scheduled work with clear rules

Eleven background jobs release abandoned holds, close overdue tracking, process translations, refresh template status and handle routine cleanup. Each one documents its batch size, retry policy, failure mode and production schedule, with the dry-run task explicitly excluded.

Permissions and accountability

Module-level permissions limit what each administrator can access, while login attempts are rate-limited and recorded. Every data change includes the responsible account in an audit log, making actions easy to trace.

Private, first-party analytics

Traffic data stays in the application's own database, with visitor countries resolved later in scheduled batches. The client gets useful reporting without adding a third-party tracking script or exporting customer behaviour.

Consistent, readable code

One admin module defines the pattern for every other module, keeping new work predictable and familiar. Written standards cover formatting, validation, CSRF protection, escaping, transactions and uploads; editable source is never minified.

Tests focused on real risk

Two hundred and three test files cover authentication, CSRF, booking and hold rules, discounts, uploads and admin forms. Browser tests also protect shared interface behaviour that can break across several screens at once.

Built with

Platform

  • PHP 8.4
  • CodeIgniter 3
  • MySQL
  • Apache
  • Composer

Front end

  • Tailwind CSS
  • Vanilla JavaScript
  • HTMX
  • Server-rendered templates
  • Full RTL support

Integrations

  • Moyasar payments
  • WhatsApp Cloud API
  • Google Cloud Translation
  • reCAPTCHA Enterprise
  • Google Places
  • Mailgun
  • IPInfo
  • CKEditor & CKFinder

Related services: Custom Web Applications, Business Websites, Technical Support & Maintenance.

Have something like this in mind?

Booking, scheduling, payments, multilingual content, an operations back office — tell us what you are trying to build and we will tell you honestly whether we are the right fit.

Live demo

Open in a new tab