fix(GRO-2234): transparent re-mint on 401 for portal Book New submit
CI / Test (pull_request) Failing after 14m28s
CI / Lint & Typecheck (pull_request) Failing after 14m29s
CI / Build & Push Docker Image (pull_request) Has been skipped

A deliberately-paced Book New wizard could outlive the portal impersonation
session, so the final POST /api/portal/waitlist returned 401 and the UI showed
"Failed to book appointment. Please try again."

BookingFlow now retries once on a 401: it re-mints a fresh portal session via
POST /api/portal/session-from-auth (the customer's Better Auth cookie is still
valid) and resubmits the waitlist request with the new
X-Impersonation-Session-Id. Falls through to the existing error if no Better
Auth session is available (staff/dev impersonation paths).

- Appointments.tsx: remintPortalSession() helper; handleConfirmBooking submits
  via submitWaitlist(id) and retries once after a 401 re-mint.
- Test: first waitlist POST 401 -> re-mint -> retry with fresh id -> success;
  asserts exactly one re-mint and the header sequence.
- UAT_PLAYBOOK.md 5.12e: TC-WEB-5.12.25 slow-wizard submit succeeds.

Companion to groombook/api GRO-2234 (bounded sliding expiration).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Flea Flicker
2026-06-08 18:55:00 +00:00
parent 3d0c3c551b
commit 915a310e0a
3 changed files with 131 additions and 14 deletions
+10
View File
@@ -244,6 +244,16 @@ export const { signIn, signOut, useSession, changePassword } = authClient;
| TC-WEB-5.12.22 | Slot buttons show formatted label | Sign in as `uat-customer@groombook.dev`, open `Appointments`, click "Book New", select a pet and service, pick a date with availability | Each time-slot button shows a human-readable label like `10:00 AM` (UTC), never a raw ISO timestamp (e.g. not `2026-06-09T10:00:00.000Z`) |
| TC-WEB-5.12.23 | Confirmation review shows formatted label | Continue the Book New wizard to the Review step | The "Date & Time" summary and the final confirmation both display the formatted slot label (e.g. `10:00 AM`), not a raw ISO string |
| TC-WEB-5.12.24 | Booking submit succeeds (regression) | Complete the Book New wizard and submit the request | Request succeeds with no `500` / `invalid input syntax for type time` error; the booking POST sends `preferredTime` as `HH:MM:SS` (e.g. `10:00:00`); the new appointment appears in the Upcoming list |
| TC-WEB-5.12.25 | Slow-wizard submit succeeds (GRO-2234) | Sign in as `uat-customer@groombook.dev`, open `Appointments`, click "Book New", then deliberately pace the wizard (pet → service → groomer → date/slot → review) so that **>2 minutes** elapse before clicking "Confirm Booking". | Submit returns success — **no** "Failed to book appointment. Please try again." error. In DevTools → Network, if the first `POST /api/portal/waitlist` returns `401`, a `POST /api/portal/session-from-auth` fires immediately after and the booking is retried once with the fresh `X-Impersonation-Session-Id`, then returns 201. The appointment appears in the Upcoming list. |
> **GRO-2234 note:** A deliberately-paced Book New wizard could outlive the
> portal impersonation session, so the final `POST /api/portal/waitlist` returned
> `401 {"error":"Unauthorized"}` ("Failed to book appointment"). The web fix adds
> a transparent one-shot re-mint: on a `401` from the waitlist submit,
> `BookingFlow` calls `POST /api/portal/session-from-auth` (the Better Auth
> cookie is still valid) and retries the submit once with the fresh session id.
> The companion API fix (groombook/api GRO-2234) adds bounded sliding expiration
> so active sessions rarely lapse in the first place.
> **GRO-2211/GRO-2213 note:** The Book New wizard previously rendered the raw
> UTC ISO slot string as the button/confirmation label and submitted that same