Customer appointment confirmation and cancellation #98
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
No-shows are the #1 revenue killer for groomers. Customers receive email reminders (24h and 2h before appointments) but have no way to confirm or cancel through the portal or email. The groomer has no signal until the client doesn't show up — by then the slot is wasted and can't be filled.
Priority: P1 — from product backlog (#84), agreed build order: auth (✅ done) → search (#97) → confirmation
Proposed Solution
Customers can confirm or cancel upcoming appointments via two channels:
Staff see confirmation status on the admin calendar, giving them advance warning of cancellations and confidence that confirmed clients will show.
Database Changes
Add to the appointments table (or appointment_groups if that's the booking unit):
confirmationStatus— enum:pending|confirmed|cancelled(default:pending)confirmedAt— timestamp, nullablecancelledAt— timestamp, nullableconfirmationToken— text, nullable, unique — for tokenized email links (no auth required)API Endpoints
POST/api/appointments/:id/confirmPOST/api/appointments/:id/cancelGET/api/confirm/:tokenGET/api/cancel/:tokenEmail Changes
Update existing reminder email templates to include:
/api/confirm/:token(redirects to a confirmation success page)/api/cancel/:token(redirects to a cancellation confirmation page)Frontend — Customer Portal
Frontend — Staff Calendar/Admin
Token Generation
crypto.randomUUID()orcrypto.randomBytes(32).toString('hex'))Acceptance Criteria
Out of Scope for This Issue
Dependencies
Priority
P1 — Directly reduces no-shows, the groomer's biggest revenue problem. Builds on existing email reminder and customer portal infrastructure. Third feature in the agreed build order.
cc @cpfarhood
CTO Technical Review
Well-specified. Architecture aligns with our existing patterns. A few technical notes:
Database:
appointmentstable (notappointment_groups— groups are a booking-time convenience, confirmations are per-appointment).0012_appointment_confirmation.sql. Add the enum, columns, and a unique index onconfirmationToken.confirmationTokenshould be nullable — only populated when a reminder email is sent.Token security:
crypto.randomBytes(32).toString('hex')for tokens — UUIDs are predictable in some implementations./api/confirm/:token,/api/cancel/:token) should be GET requests that return an HTML page (or redirect to the portal with a success message), not JSON API responses. These are clicked from emails by humans.API routes:
POST /api/appointments/:id/confirmand/cancel) go in the existing appointments router with customer auth middleware.routes/confirmation.ts— they're unauthenticated and have different middleware needs.Email integration:
Frontend:
Sequencing: This comes after #97 (search). Scrubs should complete GRO-134 (search) first.
CTO Architecture Review
Reviewed the codebase and wrote the implementation plan. Key decisions:
Separate
confirmationStatusfrom existingstatus: The appointments table already has astatusfield (scheduled/confirmed/in_progress/completed/cancelled/no_show) for the operational lifecycle. Customer confirmation is a separate concern — addingconfirmation_status(pending/confirmed/cancelled),confirmed_at,cancelled_at, andconfirmation_tokencolumns.Tokenized endpoints under
/api/book/: The public booking routes already bypass auth middleware. AddingGET /api/book/confirm/:tokenandGET /api/book/cancel/:tokenhere avoids new auth carve-outs.Token strategy:
crypto.randomBytes(32).toString('hex'), generated on appointment creation and when sending reminders (backfill). Single-use for cancellation, idempotent for confirmation. Expires when appointmentstartTimepasses.Staff calendar: Confirmation status shown as a separate visual layer on appointment cards (green checkmark for confirmed, de-emphasized for customer-cancelled), independent of the existing status color coding.
Portal endpoints:
POST /api/appointments/:id/confirmandPOST /api/appointments/:id/cancelbehind auth for staff/impersonation use.Implementation delegated to engineering. PR incoming.