rizalfarhan.dev
Property ManagementLaravelRedisWebhook

Bali Realty PMS

Eliminated booking errors across 80+ villas — $115K/year recovered

$115K

Annual revenue recovered

80+

Villas under management

0

Double-booking incidents

Business Context

Bali Realty Holiday Villas manages a portfolio of 80+ luxury villas across Bali, with inventory distributed across Airbnb, Booking.com, Hostfully, and direct channels. Each double-booking didn't just mean an awkward phone call — it meant refunds, relocation costs, and reputational damage with high-value guests paying $800–2,000/night.

The business was losing an estimated $115,000/year to booking conflicts, manual reconciliation, and staff time spent firefighting calendar mismatches instead of growing revenue.

The Challenge

The existing workflow relied on semi-manual calendar updates and delayed OTA sync. When two channels received bookings for overlapping dates within minutes of each other, the system had no authoritative lock — staff discovered conflicts after confirmation emails went out.

Technical friction points:

  • Concurrent webhook bursts from multiple OTAs during peak booking hours
  • No single source of truth for availability across 80+ property-unit combinations
  • Legacy spreadsheet fallbacks that masked systemic sync failures
  • Manual iCal imports that drifted out of sync within hours

Architecture Decision

Chosen: Laravel monolith with Redis-backed inventory locks, event-driven webhook ingestion, and PostgreSQL as the authoritative availability store.

Rejected: Microservices split per OTA channel — rejected because operational complexity would exceed team capacity, and cross-channel conflicts require atomic cross-property logic in one transaction boundary.

Why Redis + DB locks: Webhook handlers acquire a distributed lock per (property_id, date_range) before mutating inventory. Failed lock acquisition queues a retry with exponential backoff — preventing race conditions without blocking the entire system.

Why not iCal-only sync: iCal is pull-based with inherent latency. Push webhooks from Hostfully and channel managers give sub-minute propagation, which is the difference between zero and five double-bookings per month at this scale.

Key Results

MetricBeforeAfter
Double-booking incidents3–5 per month0
Manual reconciliation time12+ hours/weekAutomated · near-zero
OTA sync latency15–30 minutesUnder 60 seconds
Booking error rate~2.1%0.02%

Lessons

  • Inventory locks must happen at the database transaction level — application-level checks alone fail under concurrent OTA webhooks.
  • Treat every external channel as eventually inconsistent; design for idempotent webhook processing from day one.

Next Project

Portal ExtranetDoubled agent productivity (12→22 bookings/day) with zero double-booking incidents