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 system | Status |
|---|---|
| ChargeAutomation guest portal | Fully replaced by our /forms/pre-checkin (Phase 5) |
| 27 Booking Automation auto-actions | Ported to worker workflows / cron / route handlers |
| 3 BA VRBO payment auto-actions | Stay in BA — payment infra not migrated |
| 2 BA auto-actions | Intentionally skipped (Mailchimp + no-op) |
| Pipedream cleaner flow | Replaced 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:
- Cohost notification (TP front desk)
- Channel-specific setup (Airbnb confirm, Booking.com paid flag)
- Cleaner heads-up
- Pre-arrival messages (T-14, T-5, T-3, T-1, T-0)
- M4c early-checkin availability check (-2 days)
- Arrival flag color change (T-1 evening)
- Arrival-day Bill email (T+0 morning)
- Still-dirty check (T+0 3pm)
- Departure-day Bill email
- Check-in form chase (T+1 day)
- T-2 cleaner reminder
- Checkout-eve guest message
- Time-commit cleaner request
- M4d late-checkout availability check (D-3)
- 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
| Where | What |
|---|---|
D1: bookings | Cached Beds24 booking rows |
D1: cleanings | Per-booking cleaning state (touchpoint ack timestamps) |
D1: pre_checkin_submissions | Guest form submissions + payment intent IDs |
D1: mailgun_events | Webhook events from Mailgun (delivery/open/click/bounce) |
D1: twilio_events | Status callbacks from Twilio outbound SMS |
D1: outbound_log | Cross-channel send log (source of truth for delivery watchdog) |
D1: beds24_messages | Thread messages we sent for verification reconciliation |
D1: feature_flags | Shadow-mode toggles for each workflow chunk |
D1: alert_log | Dedup log for repeat-alert suppression |
D1: property_config | Per-property settings (cleaners, codes, arrival messages, addon pricing) |
D1: shadow_predictions | What the workflow PLANNED to do — for shadow reconcile |
D1: workflow_instances | Workflow instance ID lookup by booking ID |
D1: migration_log | Audit trail of webhook hits, workflow triggers, errors |
KV: BEDS24_KV | Beds24 access token cache + per-booking self-write debounce flags |
KV: DROPBOX_KV | Dropbox access token cache |
| Beds24 infoItems | Durable 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.