Skip to content

System overview

The stayonthesnow-pms worker orchestrates the lifecycle of every booking at Bill Titler’s three Steamboat Springs short-term rentals (Chateaux Chamonix #223, Steamboat Sheraton #702, Torian Plum #501). It runs on Cloudflare Workers + Workflows backed by D1 and KV, and talks to Beds24 (reservations + thread messaging), Mailgun (email), Twilio (SMS), Stripe (payments), and Dropbox (selfie storage).

What it replaces

Old systemStatus
ChargeAutomation guest portalFully replaced by our /forms/pre-checkin (Phase 5)
27 Booking Automation auto-actionsPorted to worker workflows / cron / route handlers
3 BA VRBO payment auto-actionsStay in BA — payment infra not migrated
2 BA auto-actionsIntentionally skipped (Mailchimp + no-op)
Pipedream cleaner flowReplaced by per-booking cleaning workflow (M4)

See the BA AA migration map for the complete 35-AA inventory.

High-level architecture

┌────────────────────────┐
Beds24 ────────────┤ Workers (this PMS) ├──────── Mailgun
webhooks │ │
│ • per-booking ├──────── Twilio
Cron (06Z, 15min, │ Workflow │
14Z, 21Z) ────┤ • routes: ├──────── Stripe
│ /forms/... │
Guest browser ─────┤ /clean-ack ├──────── Beds24 API
│ /admin/... │ (token, bookings,
│ /webhook/... │ infoItems, messages)
│ • D1 (state) │
│ • KV (tokens, ├──────── Dropbox
│ self-write │ (selfie uploads)
│ debounce) │
└────────────────────────┘

The two workflow types

DailyFlagSyncWorkflow (daily 06:00Z) — sweeps Beds24 bookings, ensures each has a BookingFlagWorkflow instance. The cold-start mechanism. See Daily flag-sync cron.

BookingFlagWorkflow (one per booking) — owns that booking’s full lifecycle. Currently runs roughly this sequence:

  1. Cohost notification (TP front desk)
  2. Channel-specific setup (Airbnb confirm, Booking.com paid flag)
  3. Cleaner heads-up
  4. Pre-arrival messages (T-14, T-5, T-3, T-1, T-0)
  5. M4c early-checkin availability check (-2 days)
  6. Arrival flag color change (T-1 evening)
  7. Arrival-day Bill email (T+0 morning)
  8. Still-dirty check (T+0 3pm)
  9. Departure-day Bill email
  10. Check-in form chase (T+1 day)
  11. T-2 cleaner reminder
  12. Checkout-eve guest message
  13. Time-commit cleaner request
  14. M4d late-checkout availability check (D-3)
  15. Departure flag color change

Each phase is idempotent and uses step.sleepUntil to wait until its target moment. Workflows can be respawned without duplicate sends — each phase reads state (info codes, cleanings table, mailgun events) before acting.

See End-to-end flow for the timeline view.

Where state lives

WhereWhat
D1: bookingsCached Beds24 booking rows
D1: cleaningsPer-booking cleaning state (touchpoint ack timestamps)
D1: pre_checkin_submissionsGuest form submissions + payment intent IDs
D1: mailgun_eventsWebhook events from Mailgun (delivery/open/click/bounce)
D1: twilio_eventsStatus callbacks from Twilio outbound SMS
D1: outbound_logCross-channel send log (source of truth for delivery watchdog)
D1: beds24_messagesThread messages we sent for verification reconciliation
D1: feature_flagsShadow-mode toggles for each workflow chunk
D1: alert_logDedup log for repeat-alert suppression
D1: property_configPer-property settings (cleaners, codes, arrival messages, addon pricing)
D1: shadow_predictionsWhat the workflow PLANNED to do — for shadow reconcile
D1: workflow_instancesWorkflow instance ID lookup by booking ID
D1: migration_logAudit trail of webhook hits, workflow triggers, errors
KV: BEDS24_KVBeds24 access token cache + per-booking self-write debounce flags
KV: DROPBOX_KVDropbox access token cache
Beds24 infoItemsDurable per-booking flags (CA_PRE_CHECKIN_COMPL, CHECKIN, COHOST_NOTIFIED, etc.)

Feature flag philosophy

Every meaningful BA migration is gated by a feature_flags row with shadow_mode (0 = real, 1 = predictions only). This lets Bill flip a chunk live AFTER disabling the corresponding BA auto-actions.

See Feature flags for the current list.