Both existed only on the live server / untracked locally until now.
Includes the open/closed status fix: the Filiale status badge was
hardcoded as "Geöffnet · schließt um 20:00" regardless of actual time
(caught showing "open" at 3am) -- now computed against the shop's own
Europe/Berlin clock and real weekly hours.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sends a confirmation email (best-effort, fire-and-forget SMTP via mailer.py)
on booking creation, with a manage-booking link embedding the ticket-2 signed
token. Adds /manage/<token>, a stateless cancel/reschedule page that reuses
the existing slot-picker against booking_api's create/cancel/reschedule API,
distinguishing an invalid/expired link from an already-cancelled one. Sender
address uses the client's own domain when configured, falling back to a
mivanchenko.de address otherwise.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds the customer-facing /book/<slug> page: service/slot picker, booking
form, and confirmation screen, built on #16's existing booking JSON API.
Includes iframe auto-fit height reporting (mirroring
deploy/booking/booking_layout.js's eaBookingHeight message), brand-color
theming via a ?color= query param, a honeypot field with a fake-success
response indistinguishable from a real booking, and a clear "just taken"
message on slot-conflict. Caddy per-IP rate limiting is documented in
deploy/booking/RATE_LIMIT.md for manual application (no Caddyfile is
tracked in this repo).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
deploy/smb-demos: compose + runbook for the static demo host
(httpd on the proxy network, routed by Caddy at demos.mivanchenko.de).
Pending a DNS A record before Caddy can issue TLS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>