Skip to content
All work

Case study · Hotel management system for Villa Lanka

Ayura

A multi-tenant property management system for two hotels in Sri Lanka. It replaced an Excel-based workflow and runs the full booking lifecycle, from inquiry to invoice. I designed, built and operate it end-to-end.

Sole developer: architecture, backend, frontend, operations
Role
First version 2023 Rebuild live since April 2026
Timeline
Java 21, Spring Boot 3.5, Angular 20, PostgreSQL, Docker, GitLab CI
Stack
In daily use at both hotels
Status
Ayura booking dialog for a two-room Ayurveda cure booking, showing the finalized invoice: package and transfer lines with net amount, levies and gross, then totals for service charge, tourism levy (TDL), VAT and a grand total of 4,860 euros
Demo data

The problem

Both hotels managed bookings, availability, agency commissions and invoices in Excel. Prices depend on the season, the room occupancy and the travel agency a guest books through, and every booking needs several documents. Keeping all of that consistent by hand was slow and error-prone.

From v1 to a rebuild

The first version went into use in 2023. To handle two hotels, seasonal prices, agency contracts and local tax rules properly, I rebuilt Ayura from scratch in 2025 and 2026, with multi-tenancy, a clear domain model, automated tests and a deployment pipeline built in from the start. The new version has been live since April 2026.

What I built

  • Booking lifecycle

    Requested, confirmed, cancelled. Bookings are editable only while requested and never deleted, so the history stays intact. Rooms can be changed mid-stay with automatic repricing.

  • Pricing engine

    Package prices per night by season and occupancy, plus supplements, room-type surcharges, discounts and deposits.

  • Travel-agency contracts

    Net-rate and commission models per agency, applied automatically to the right booking lines.

  • Documents

    Offers, confirmations, bills and accounting bills as PDFs, in German or English depending on the guest, with unique numbering per hotel and year.

  • Tax & accounting rules

    Configurable per hotel, including Sri Lankan VAT, tourism levy and service charge.

  • Review sync

    A nightly Google Places sync with an admin curation step feeds selected reviews to the hotel website.

Architecture

Architecture of Ayura The Angular 20 staff client calls the Spring Boot API over REST with JWT. The API is a Java 21 modular monolith with a booking module, a reviews module, and pricing, documents and accounting. It stores data in PostgreSQL through JPA, one schema with rows per hotel. A nightly sync pulls guest reviews from the Google Places API, and a public feed serves them to the Nuxt website villalankaflair.com. GitLab CI with a self-hosted runner runs the full test suite, builds multi-arch Docker images and deploys the API pinned to the commit SHA. REST + JWTJPAnightly syncpublic feeddeployAngular 20 clientGoogle Places APISpring Boot APIPostgreSQLvillalankaflair.comGitLab CI · self-hosted runnerstaff UIguest reviewsJava 21 · modular monolithone schema, rows per hotelNuxt, public websitefull test suite → multi-arch Docker images → deploy pinned to the commit SHAbooking modulereviews modulepricing · documents · accounting
A modular monolith: booking is its own vertical slice, and other features reach it only through narrow read ports.

Engineering decisions

  • Tenant isolation in every query

    Each request resolves the current hotel first and only uses hotel-scoped queries. Dedicated integration tests check that one hotel can never see another hotel's data.

  • Modular monolith with ports

    Booking is a vertical slice. Dashboard, calendar and documents read it through narrow ports instead of sharing its repositories.

  • One pipeline for every change

    Creating and editing a booking run through the same steps: validation, seasonal pricing, agency contracts, taxes, discounts, commission. All invariants live in one place.

  • Money and time done right

    All amounts use BigDecimal with explicit rounding. Time comes from an injected clock, so date logic is tested deterministically.

  • Safe document numbering

    Invoice numbers are generated under a database lock per hotel, document type and year, so parallel confirmations never collide.

  • Delivery by commit

    Every release is pinned to a commit SHA on the server. Rolling back means switching the tag, no rebuild needed.

Results

Excel retired
Both hotels run their daily booking work in Ayura.
Consistent numbers
Prices, commissions, taxes and accounting splits are calculated the same way every time.
Documents on confirm
Confirming a booking generates the confirmation, bill and accounting bill automatically.

What's next

The staff client is being rebuilt in Angular 20 with a new design system and a stricter TypeScript setup. After that comes a full architecture review, and the question of whether Ayura can serve other Ayurveda hotels as a SaaS product.

  • Ayura room plan: a 14-day timeline with one row per room, bookings drawn as bars labelled with guest names and travel agencies, colored by booking status
    Demo data
  • Ayura travel agency form with its contract settings: commission pricing model, 15 percent, applied to packages and supplements
    Demo data
  • German booking confirmation PDF generated by Ayura: stay dates, two rooms and a price overview with the cure package split into high- and low-season lines per room
    Demo data · German confirmation
  • The same booking confirmation generated in English
    Demo data · English confirmation