Public booking page + iframe embed #17

Closed
opened 2026-07-23 14:07:57 +02:00 by mivanchenko · 1 comment
Owner

Parent

#14

What to build

The actual public-facing booking page a customer sees, embedded via iframe into a client's landing
page — the first ticket where booking is demoable in a browser rather than only verifiable via
tests.

  • /book/<slug> page: htmx / light JS slot grid, listing the client's active services, then
    available slots (from ticket 2's engine) for the chosen service, then a form to submit
    name/contact and complete the booking.
  • Confirmation screen after a successful booking (shows booking details; the actual email is
    ticket 4's concern, but the on-page confirmation itself is this ticket's).
  • Iframe embed support: a small script posts the rendered content height to the parent frame so
    the embedding landing page can auto-fit the iframe (no inner scrollbar) — mirroring
    deploy/booking/booking_layout.js's approach. Brand color theming via a CSS variable or query
    param, mirroring deploy/booking/frontend.css's --bs-primary pattern.
  • Abuse protection: Caddy-level IP rate limiting on the public routes, plus a honeypot field in the
    booking form (hidden field that must stay empty — filled-in submissions are silently rejected).
  • Clear, human-readable error state when a slot was just taken by someone else (the ticket-2
    concurrency case surfaced in the UI).

Acceptance criteria

  • A customer can open /book/<slug> for a seeded test client, pick a service, pick an
    available slot, submit their details, and see a confirmation screen.
  • The page's rendered height is reported to the parent frame so an embedding iframe can size
    itself without an inner scrollbar.
  • The page accepts a brand color and applies it to the primary UI elements.
  • Submitting the honeypot field populated results in silent rejection (no booking created, no
    obvious "bot detected" tell to a scripted client).
  • Attempting to book a slot that was just taken (simulating the ticket-2 concurrency case)
    shows a clear "that slot was just taken, please pick another" message, not a raw error.
  • Public routes are rate-limited at the Caddy layer per IP.

Blocked by

  • #16 (Availability engine + booking API)
## Parent #14 ## What to build The actual public-facing booking page a customer sees, embedded via iframe into a client's landing page — the first ticket where booking is demoable in a browser rather than only verifiable via tests. - `/book/<slug>` page: htmx / light JS slot grid, listing the client's active services, then available slots (from ticket 2's engine) for the chosen service, then a form to submit name/contact and complete the booking. - Confirmation screen after a successful booking (shows booking details; the actual email is ticket 4's concern, but the on-page confirmation itself is this ticket's). - Iframe embed support: a small script posts the rendered content height to the parent frame so the embedding landing page can auto-fit the iframe (no inner scrollbar) — mirroring `deploy/booking/booking_layout.js`'s approach. Brand color theming via a CSS variable or query param, mirroring `deploy/booking/frontend.css`'s `--bs-primary` pattern. - Abuse protection: Caddy-level IP rate limiting on the public routes, plus a honeypot field in the booking form (hidden field that must stay empty — filled-in submissions are silently rejected). - Clear, human-readable error state when a slot was just taken by someone else (the ticket-2 concurrency case surfaced in the UI). ## Acceptance criteria - [ ] A customer can open `/book/<slug>` for a seeded test client, pick a service, pick an available slot, submit their details, and see a confirmation screen. - [ ] The page's rendered height is reported to the parent frame so an embedding iframe can size itself without an inner scrollbar. - [ ] The page accepts a brand color and applies it to the primary UI elements. - [ ] Submitting the honeypot field populated results in silent rejection (no booking created, no obvious "bot detected" tell to a scripted client). - [ ] Attempting to book a slot that was just taken (simulating the ticket-2 concurrency case) shows a clear "that slot was just taken, please pick another" message, not a raw error. - [ ] Public routes are rate-limited at the Caddy layer per IP. ## Blocked by - #16 (Availability engine + booking API)
mivanchenko added the bookingready-for-agentenhancement labels 2026-07-23 14:07:57 +02:00
mivanchenko added a new dependency 2026-07-23 14:09:18 +02:00
Author
Owner

Shipped in commit b895663 ("Public booking page + iframe embed (#17)"). Closing — this was already implemented, just never closed in the tracker.

Shipped in commit b895663 ("Public booking page + iframe embed (#17)"). Closing — this was already implemented, just never closed in the tracker.
Sign in to join this conversation.