Skip to main content

MVP.1 - Two-Way Sync + Booking Awareness

Timeline: Weeks 11-16 Status: In Design Business Value: Unified booking visibility across all channels, occupancy awareness


Overview

MVP.1 extends the foundation built in MVP.0 by adding two-way synchronization with Hostaway. This enables TVL to not only push listing data outbound (TVL → Hostaway) but also ingest bookings and availability updates from Hostaway back into TVL. Property managers gain a unified view of all external bookings and can see occupancy at a glance.

This is a read-only booking system — bookings are imported from Hostaway but cannot be created directly in TVL. The availability calendar displays all bookings and blocks, providing complete occupancy visibility.


Core Capabilities

1. Two-Way Channel Sync (Building on MVP.0)

  • Continue outbound sync: TVL → Hostaway (listings, content, availability)
  • NEW: Inbound sync: Hostaway → TVL (bookings, availability blocks)
  • Webhook receivers for real-time booking notifications
  • Polling fallback for missed events (every 15 minutes)
  • Idempotent ingestion with deduplication
  • Sync conflict detection and logging

2. Booking Import & Display

  • Import bookings from Hostaway with full metadata
  • Store booking line items (nights, guests, dates, pricing)
  • Read-only booking list view (filter by Space, date range, status)
  • Booking detail view with guest info, pricing breakdown, status
  • Link imported bookings to Spaces via external listing ID
  • Track booking source (Hostaway, future: Airbnb, VRBO)

3. Availability Calendar (Basic)

  • Unit-level availability calendar display
  • Show bookings as occupied blocks
  • Show manual blocks (maintenance, owner stays)
  • Show imported iCal blocks from external feeds
  • Color-coded status: booked, blocked, available
  • Month/week/list views
  • No booking creation (deferred to V1.0)

4. Inbound Sync Infrastructure

  • Webhook endpoint: /api/webhooks/hostaway
  • Webhook signature verification (HMAC)
  • Event types: booking.created, booking.updated, booking.cancelled
  • Polling job for sync reconciliation
  • Inbound audit log (parallel to outbound_audit from MVP.0)
  • Error handling and retry logic

5. Observability (Extended from MVP.0)

  • Inbound sync metrics (success rate, latency, errors)
  • Webhook delivery tracking
  • Booking ingestion dashboard
  • Sync conflict alerts
  • Audit trail for all imported bookings

Domains Implemented

DomainScopePriorityChange from MVP.0
Identity & TenancyFullCRITICALNo change
Authorization & AccessRBAC onlyCRITICALNo change
SupplyBasic CRUDCRITICALNo change
Channels & DistributionTwo-way syncCRITICALAdded inbound
Availability & CalendarRead-only displayHIGHNEW domain
BookingsExternal onlyHIGHNEW domain
PricingDisplay onlyMEDIUMNEW domain
Analytics & AuditExtended loggingHIGHExpanded

Database Schema (22 Tables)

Inherited from MVP.0 (14 tables)

1-5. Identity & Tenancy (organizations, accounts, users, memberships, sessions) 6-7. Authorization (roles, permissions) 8-10. Supply (spaces, units, unit_snapshots) 11-13. Channels (channel_targets, channel_listings, outbound_audit) 14. Analytics (audit_events)

NEW for MVP.1 (8 tables)

Availability & Calendar (3 tables)

  1. availability_calendars - Authoritative calendar per Space
  2. blocks - Manual/system/imported blocks (maintenance, owner stays, iCal)
  3. holds - Temporary checkout locks (from MVP.0, now used for future bookings)

Bookings (3 tables)

  1. bookings - Imported external bookings
  2. booking_line_items - Nights, guests, pricing breakdown
  3. booking_guests - Guest metadata (name, email, phone)

Inbound Sync (2 tables)

  1. inbound_audit - Log of webhook/poll events
  2. ical_feeds - Inbound iCal feed subscriptions

Functional Requirements

FR-1: Webhook Receiver for Hostaway Events

  • Given: Hostaway sends booking.created webhook
  • When: TVL receives POST to /api/webhooks/hostaway
  • Then: Signature verified (HMAC-SHA256)
  • And: Event payload validated
  • And: Booking ingestion job enqueued
  • And: 200 OK returned immediately
  • And: Event logged to inbound_audit

FR-2: Booking Import from Hostaway

  • Given: Inbound job for booking.created event
  • When: Worker processes job
  • Then: Extract booking metadata (dates, guests, pricing, status)
  • And: Map external listing_id → internal Space
  • And: Create or update booking record
  • And: Create booking_line_items (nightly breakdown)
  • And: Create booking_guests record
  • And: Update availability_calendar with new booking
  • And: Log success/failure to inbound_audit
  • And: Emit internal event: booking.imported

FR-3: Booking Update Handling

  • Given: Inbound job for booking.updated event
  • When: Worker processes job
  • Then: Lookup existing booking by external_booking_id
  • And: Compare version/updated_at timestamps
  • And: Update booking fields if newer
  • And: Update availability if dates changed
  • And: Log change to audit_events
  • And: Emit event: booking.updated

FR-4: Booking Cancellation

  • Given: Inbound job for booking.cancelled event
  • When: Worker processes job
  • Then: Lookup existing booking
  • And: Set status = 'cancelled', cancelled_at = now()
  • And: Free availability on calendar
  • And: Log cancellation to audit_events
  • And: Emit event: booking.cancelled

FR-5: Polling Reconciliation Job

  • Given: Scheduled job runs every 15 minutes
  • When: Job executes
  • Then: Fetch recent bookings from Hostaway API (last 24 hours)
  • And: Compare with local bookings by external_booking_id
  • And: Enqueue jobs for any missing/outdated bookings
  • And: Log reconciliation results to inbound_audit
  • And: Alert on sync lag > 1 hour

FR-6: Availability Calendar Display

  • Given: User with Space access
  • When: User views Space calendar
  • Then: Render month/week view
  • And: Show bookings as solid blocks (color: blue)
  • And: Show manual blocks (color: gray)
  • And: Show holds if active (color: yellow, dotted)
  • And: Show available dates (color: white/green)
  • And: Display booking details on hover/click
  • And: Filter by date range

FR-7: Booking List View

  • Given: User with Viewer+ role
  • When: User navigates to Bookings page
  • Then: Display table of all bookings
  • And: Columns: Space, Guest, Check-in, Check-out, Nights, Status, Source
  • And: Filter by: Space, date range, status, source channel
  • And: Sort by: check-in date (default), created_at, status
  • And: Paginate (50 per page)

FR-8: Booking Detail View

  • Given: User clicks on a booking
  • When: Detail modal/page loads
  • Then: Display full booking metadata:
    • Space name and photo
    • Guest name, email, phone
    • Check-in/check-out dates
    • Nights, guests (adults/children)
    • Total price, breakdown (nightly, fees, taxes)
    • Status, source channel
    • External booking ID (Hostaway reference)
    • Created/updated timestamps
  • And: Show sync status (last synced, any errors)
  • And: Link to Space and channel_listing

FR-9: iCal Feed Import (External Calendars)

  • Given: User adds external iCal feed URL (e.g., from Airbnb)
  • When: Import job runs (hourly)
  • Then: Fetch feed via HTTP GET
  • And: Parse iCal events (VEVENT blocks)
  • And: Create/update blocks for each event
  • And: Set source = 'external', external_ical_uid
  • And: Deduplicate by (calendar_id, external_ical_uid)
  • And: Use If-None-Match (ETag) to skip unchanged feeds
  • And: Log import to inbound_audit

FR-10: Idempotent Booking Ingestion

  • Given: Duplicate webhook for same booking
  • When: Ingestion job processes duplicate event
  • Then: Lookup by external_booking_id
  • And: Compare external_updated_at timestamp
  • And: Skip if local record is newer or equal
  • And: Log skipped duplicate to inbound_audit
  • And: Return success (no error)

Non-Functional Requirements

NFR-1: Performance

  • Webhook response time: <200ms (ack only, async processing)
  • Booking ingestion latency: <30 seconds (webhook to visible)
  • Polling reconciliation: <2 minutes per sync cycle
  • Calendar load time: <500ms for 90-day view

NFR-2: Reliability

  • Webhook delivery: at-least-once processing via job queue
  • Idempotency: safe to replay events (dedupe by external_id + timestamp)
  • Polling fallback: catches missed webhooks within 15 minutes
  • Zero data loss: all events logged to inbound_audit

NFR-3: Data Consistency

  • Bookings always linked to correct Space (via external listing_id)
  • Availability conflicts detected and logged (booking overlaps)
  • Sync conflicts resolved: external source wins (Hostaway is source of truth)
  • Audit trail: every booking create/update/cancel logged

NFR-4: Security

  • Webhook signatures verified (HMAC-SHA256 with shared secret)
  • API tokens stored in Secrets Manager
  • Rate limiting: 100 req/min per channel target
  • Webhook endpoint: HTTPS only, no public exposure without auth

NFR-5: Scalability

  • Support 50+ properties with 200+ annual bookings each
  • Handle 1000+ webhook events/day
  • Process 500+ imported iCal events/hour
  • Prepare for 1000+ properties in MVP.2

Technical Architecture

Stack (Inherited from MVP.0)

  • Backend: Node.js 20+ with TypeScript
  • Framework: Express.js
  • Database: PostgreSQL 15+
  • Queue: BullMQ + Redis
  • Auth: Google OIDC (Passport.js)
  • Secrets: AWS Secrets Manager or GCP Secret Manager
  • Deployment: Docker + Kubernetes

NEW Components for MVP.1

ComponentTechnologyPurpose
Webhook receiverExpress route + middlewareAccept Hostaway events
Signature verifiercrypto (Node.js)HMAC-SHA256 validation
Inbound job processorBullMQ workerProcess booking events
Polling reconciliationCron job (node-cron)Catch missed events
iCal parserical.jsParse external feeds
Calendar UIReact + date-fnsDisplay availability
Booking UIReact tableList and detail views

Key Design Decisions

DecisionChoiceRationale
Sync directionTwo-way (outbound + inbound)Enable booking visibility
Booking creationExternal only (no direct bookings)Defer to V1.0; reduce MVP scope
Webhook vs pollingBoth (webhook primary, polling backup)Reliability + real-time updates
Conflict resolutionExternal source winsHostaway is source of truth for MVP
Calendar granularityUnit-level (Space = 1 Unit in MVP)Simplify; multi-unit in V1.0
Availability storageDedicated calendar + blocks tablesClean separation from bookings
iCal handlingImport as blocks, not bookingsExternal events lack booking metadata
IdempotencyDedupe by external_id + timestampPrevent duplicate ingestion

Success Metrics

MetricTargetMeasurement
Bookings imported100% of Hostaway bookingsCompare Hostaway API vs TVL DB
Webhook success rate99%+inbound_audit success %
Sync latency<1 min (webhook), <15 min (polling)Time from external event to visible
Calendar accuracy100% match with HostawayManual spot checks
Zero booking loss100%All external bookings ingested
Availability conflicts<1% false positivesConflict alert rate
User adoption10+ properties using calendarActive Space count

Out of Scope (Deferred)

Deferred to MVP.2

  • Multi-channel inbound (Airbnb, VRBO)
  • Advanced conflict resolution (automated)
  • Channel-specific pricing display
  • Booking modification (dates, guests)

Deferred to V1.0

  • Direct booking creation in TVL
  • Payment processing
  • Guest communication (messages)
  • Owner financial reports (revenue splits)
  • Dynamic pricing rules
  • Multi-unit bookings

Deferred to V2.0+

  • Event/experience bookings
  • Booking recommendations (AI)
  • Guest portal
  • Task automation (cleaning, maintenance)

Dependencies

External Dependencies

  • Hostaway Webhooks API (docs.hostaway.com/webhooks)
  • Hostaway REST API v1 (for polling reconciliation)
  • iCal format (RFC 5545) for external feeds
  • Google OIDC (from MVP.0)
  • Secrets Manager (from MVP.0)

Internal Dependencies

  • MVP.0 infrastructure (Auth, Multi-tenancy, Supply, Channels)
  • channel_targets table (Hostaway connection config)
  • channel_listings table (external listing_id mapping)
  • spaces table (booking destination)

Risks & Mitigation

RiskImpactProbabilityMitigation
Webhook delivery failuresHIGHMEDIUMPolling fallback every 15 min
External listing_id mismatchHIGHMEDIUMValidation on import; manual override UI
Booking conflicts (double-booking)HIGHLOWDetect and alert; manual resolution
Hostaway API rate limitsMEDIUMMEDIUMRespect 429 responses; exponential backoff
Webhook signature spoofingHIGHLOWHMAC verification; rotate secrets
iCal feed downtimeMEDIUMMEDIUMRetry on 5xx; alert on 24hr failure
Data inconsistency (stale bookings)MEDIUMMEDIUMPolling reconciliation; audit logs

Acceptance Criteria

  • Webhook endpoint accepts Hostaway events
  • Webhook signatures verified (reject invalid)
  • Booking.created event imports booking to TVL
  • Booking.updated event updates existing booking
  • Booking.cancelled event marks booking as cancelled
  • Polling job reconciles bookings every 15 minutes
  • All imported bookings visible in Booking List
  • Booking Detail shows full metadata
  • Availability calendar displays bookings as blocks
  • Calendar shows manual blocks (maintenance)
  • iCal feed import creates blocks from external events
  • Duplicate webhooks deduplicated (idempotent)
  • All events logged to inbound_audit
  • Sync conflicts detected and logged
  • 50+ properties with bookings imported successfully
  • Zero data loss (100% booking ingestion)

Delivery Plan

Week 11: Inbound Infrastructure

  • Database schema (8 new tables)
  • Migrations
  • Webhook endpoint with signature verification
  • Inbound audit logging

Week 12: Booking Import

  • Booking ingestion worker
  • booking.created, booking.updated, booking.cancelled handlers
  • External listing_id → Space mapping
  • booking_line_items and booking_guests creation

Week 13: Polling & Reconciliation

  • Polling job (every 15 minutes)
  • Reconciliation logic (compare external vs local)
  • Conflict detection and alerting
  • iCal feed import (basic)

Week 14: Availability Calendar

  • availability_calendars and blocks tables
  • Calendar API (get availability by date range)
  • Calendar UI (month/week views)
  • Color-coded blocks (booked, blocked, available)

Week 15: Booking UI

  • Booking List view (table with filters)
  • Booking Detail view (modal/page)
  • Sync status indicators
  • Testing with real Hostaway data

Week 16: Testing & Hardening

  • Integration tests (webhook → ingestion → display)
  • Load testing (1000+ webhooks/day)
  • Security review (signature verification)
  • Bug fixes and polish
  • Staging validation
  • Production deployment