Skip to content

Guest portal

A mobile-first guest-facing site at my.stayonthesnow.com. Each booking has its own private URL of the form /p/{token} where the token is a 32-byte opaque string baked into every guest email.

Why a portal

Before P12, guest interactions lived in scattered emails with bare ?b={bookingId} links pointing at individual form endpoints. That broke the moment a guest wanted to revisit something later (links got buried in their inbox), and the ?b= query-string ID was both guessable and unauthenticated.

The portal:

  • Gives each booking ONE link that opens a hub of every action they might need (forms, lock-box code, add-ons, property info)
  • Replaces the guessable booking ID with a 256-bit opaque token
  • Sets a 2-year cookie so returning visitors land back in the portal without needing to dig out the email again — useful for future re-book nudges

What pages exist

PathPurposeModule
/Cookie-root: redirect to portal if signed in, else “look in your email” pageP12.M2
/p/{token}Landing / overview card (property, dates, status, action buttons)P12.M2
/p/{token}/pre-checkinExisting pre-check-in form, token-verifiedP12.M3
/p/{token}/check-inExisting check-in form, token-verifiedP12.M3
/p/{token}/check-outExisting check-out form, token-verifiedP12.M3
/p/{token}/arrivalLock-box code + arrival instructions (gated to arrival day) — see Arrival screenP12.M4
/p/{token}/addonsAdd-on status summary + late-checkout picker entry — see Add-ons screenP12.M5 (small)
/p/{token}/info + 3 sub-pagesWiFi, parking, amenities, walk-throughs, rules — see Property info pagesP12.M8
/signoutClear cookie, show goodbye pageP12.M2

Design system

  • Mobile-first single column, max width 520px
  • Deep mountain-blue primary (#1e3a5f), warm amber CTAs (#d97706)
  • System font stack — zero web-font load delay on slow trailhead Wi-Fi
  • All HTML rendered by the worker; CSS inlined per response (no external assets, no FOUC)
  • Shared shell helper lives in src/lib/portal-shell.ts — every portal page calls renderPortalShell({ title, body, hero? })

Source

  • Routes: src/routes/portal.ts
  • Shell: src/lib/portal-shell.ts
  • Tokens: src/lib/guest-token.ts + migrations/0035_guest_tokens.sql
  • Tests: test/routes/portal.test.ts, test/lib/guest-token.test.ts

See Token model and Cookie session for the auth details.