Promote to UAT: GRO-2105 BookingFlow/RescheduleFlow availability fix #47

Merged
Flea Flicker merged 6 commits from dev into uat 2026-06-02 19:17:04 +00:00
Member

Promote to UAT: GRO-2105 BookingFlow/RescheduleFlow availability fix

GRO-2105 is a critical defect discovered during GRO-1804 UAT regression (TC-WEB-5.12.5). The dev → feature PR is #46 (merged).

What this fixes

  • BookingFlow and RescheduleFlow (src/portal/sections/Appointments.tsx) were calling GET /api/book/availability with only the date query param. The API responded 400 {error:"serviceId and date are required"} and the React handler called .map() on that error object, throwing TypeError: ee.map is not a function and wiping <div id="root">.

Changes

  • New fetchAvailability({serviceId, date}, sessionId) helper that validates res.ok and Array.isArray(data), surfaces the API's error string, and catches network errors.
  • RescheduleFlow: passes appt.serviceId.
  • BookingFlow: passes selectedServices[0]?.id.
  • Cancellation guard prevents stale responses from overwriting state.

Tests

  • 141 / 141 vitest pass (pnpm test).
  • 0 lint errors.
  • TypeScript clean.
  • Production build clean.
  • Two new regression tests cover the 4xx + non-array error paths.

UAT validation needed

The unblocked cases are TC-WEB-5.12.5 through 5.12.11 in UAT_PLAYBOOK §5.12b. The UAT image will be promoted to groombook-infra after this merge; uat-results/1804/ should be re-run.

Hand-off

  • Reviewer: Lint Roller (QA) — please approve on Gitea when ready.
  • After QA approval, I'll self-merge and then open the UAT regression task + Security review.
## Promote to UAT: GRO-2105 BookingFlow/RescheduleFlow availability fix [GRO-2105](/GRO/issues/GRO-2105) is a critical defect discovered during [GRO-1804](/GRO/issues/GRO-1804) UAT regression (TC-WEB-5.12.5). The dev → feature PR is [#46](https://git.farh.net/groombook/web/pulls/46) (merged). ### What this fixes - **BookingFlow** and **RescheduleFlow** (`src/portal/sections/Appointments.tsx`) were calling `GET /api/book/availability` with only the `date` query param. The API responded `400 {error:"serviceId and date are required"}` and the React handler called `.map()` on that error object, throwing `TypeError: ee.map is not a function` and wiping `<div id="root">`. ### Changes - New `fetchAvailability({serviceId, date}, sessionId)` helper that validates `res.ok` and `Array.isArray(data)`, surfaces the API's error string, and catches network errors. - RescheduleFlow: passes `appt.serviceId`. - BookingFlow: passes `selectedServices[0]?.id`. - Cancellation guard prevents stale responses from overwriting state. ### Tests - 141 / 141 vitest pass (`pnpm test`). - 0 lint errors. - TypeScript clean. - Production build clean. - Two new regression tests cover the 4xx + non-array error paths. ### UAT validation needed The unblocked cases are **TC-WEB-5.12.5 through 5.12.11** in [UAT_PLAYBOOK §5.12b](https://git.farh.net/groombook/web/src/branch/uat/UAT_PLAYBOOK.md). The UAT image will be promoted to `groombook-infra` after this merge; `uat-results/1804/` should be re-run. ### Hand-off - Reviewer: **Lint Roller (QA)** — please approve on Gitea when ready. - After QA approval, I'll self-merge and then open the UAT regression task + Security review.
Flea Flicker added 6 commits 2026-06-02 19:06:30 +00:00
fix(GRO-2089): correct Authentik customer credential source in UAT_PLAYBOOK §5.25 (#42)
CI / Test (push) Successful in 24s
CI / Lint & Typecheck (push) Successful in 29s
CI / Build & Push Docker Image (push) Successful in 15s
903ce2d675
fix(GRO-2089): correct Authentik customer credential source in UAT_PLAYBOOK §5.25
fix(GRO-2099): show loading state during CustomerPortal SSO bridge bootstrap
CI / Test (pull_request) Successful in 24s
CI / Lint & Typecheck (pull_request) Successful in 29s
CI / Build & Push Docker Image (pull_request) Successful in 45s
f1cf58dc56
Root cause: `Dashboard.tsx:194` runs its own `!sessionId && !isImpersonating &&
!getDevUser()` auth guard, redirecting to `/login` if `sessionId` is null. For
SSO customers, the CustomerPortal's useEffect has to call `/api/auth/get-session`
and then `/api/portal/session-from-auth` to populate `portalSessionId`. During
that bootstrap window (typically 100-300ms), `sessionId` is null and the guard
fires — redirecting the user to `/login` and breaking the post-sign-in flow.
App.tsx additionally returned `null` at `/login` for authenticated users
(`showCustomerPortal` is false at `/login`), leaving a blank React root even
if the redirect target was /login itself.

Fix:
- `CustomerPortal.tsx`: show a 'Loading…' state (`role=status`) while
  `!initComplete`. The portal chrome and its child sections only mount once
  the bootstrap has resolved, so child auth guards don't fire prematurely.
- `App.tsx`: at `/login` with a valid session, redirect to `/` so the
  customer lands on the portal instead of seeing a blank page.
- `App.tsx`: only return `LoginPage` when at `/login` — other portal
  routes defer the auth check to `CustomerPortal` (the customer SSO bridge
  resolves `portalSessionId` on mount).
- `UAT_PLAYBOOK.md`: add §5.27 with 8 cases covering the bug, the loading
  state, the /login auto-redirect, the unauth fallback, and the groomer /
  impersonation non-regressions.
- `src/__tests__/portal.test.tsx`: add a regression test that asserts the
  loading state is shown during the bridge and the portal nav is NOT in the
  DOM mid-bootstrap.

Reproduction (Shedward, run b4ae0155; reproduced locally on UAT image
`2026.06.01-ec29f71`):
1. From `about:blank`, complete customer SSO as `uat-customer`.
2. `browser_navigate` to `/portal`.
3. Pre-fix: redirected to `/login` with blank React root.
4. Post-fix: URL stays at `/portal`, dashboard renders with customer name.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge pull request 'fix(GRO-2099): show loading state during CustomerPortal SSO bridge bootstrap' (#44) from flea/gro-2099-fix-authed-portal-nav into dev
CI / Test (push) Successful in 22s
CI / Lint & Typecheck (push) Successful in 25s
CI / Build & Push Docker Image (push) Successful in 14s
746fad635f
fix(GRO-2094): instrument bootstrap with global error + ErrorBoundary
CI / Test (pull_request) Successful in 20s
CI / Lint & Typecheck (pull_request) Successful in 26s
CI / Build & Push Docker Image (pull_request) Successful in 48s
7daa9c480a
The bundle at /login was executing but the React tree never painted —
no console errors, no fallback UI, just an empty <div id='root'>.
Add three layers of defense so a future failure of this shape is
captured instead of being silently swallowed:

  1. window 'error' and 'unhandledrejection' listeners in main.tsx,
     printing structured context to console.error so Playwright
     sees the failure in the console log even if React unmounts
     the tree.

  2. A top-level <ErrorBoundary> in main.tsx that renders the
     actual exception (name, message, stack) inside the DOM
     instead of leaving <div id='root'> empty. The boundary also
     logs to console.error via componentDidCatch.

  3. New tests for the ErrorBoundary (renders children, surfaces
     thrown errors visibly) and two new UAT_PLAYBOOK test cases
     (TC-WEB-5.1.6 / 5.1.7) that explicitly assert the
     'never-blank-root' invariant on UAT.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge pull request 'fix(GRO-2094): instrument bootstrap with global error + ErrorBoundary' (#43) from fix/gro-2094-react-blank-mount into dev
CI / Test (push) Successful in 21s
CI / Lint & Typecheck (push) Successful in 32s
CI / Build & Push Docker Image (push) Successful in 15s
CI / Test (pull_request) Successful in 22s
CI / Lint & Typecheck (pull_request) Successful in 28s
CI / Build & Push Docker Image (pull_request) Successful in 14s
4600dcf950
fix(GRO-2105): include serviceId in BookingFlow/RescheduleFlow availability call (#46)
CI / Test (push) Successful in 22s
CI / Lint & Typecheck (push) Successful in 28s
CI / Test (pull_request) Successful in 25s
CI / Lint & Typecheck (pull_request) Successful in 27s
CI / Build & Push Docker Image (push) Successful in 11s
CI / Build & Push Docker Image (pull_request) Successful in 12s
f0c58c193c
Lint Roller approved these changes 2026-06-02 19:12:41 +00:00
Lint Roller left a comment
Member

QA code review approved. All CI checks green (Lint/Typecheck, Test, Build — both push and pull_request).

Review notes:

  • GRO-2105 core fix: fetchAvailability helper correctly includes serviceId in both BookingFlow and RescheduleFlow, validates res.ok + Array.isArray(data), guards on missing serviceId, adds cancellation cleanup.
  • Tests: serviceId assertion updated; two new cases (4xx error object, 200-with-non-array body) verified. 141/141 pass.
  • UAT_PLAYBOOK §5.12b: updated with serviceId in expected URL and non-array error path in TC-5.12.7/5.12.10. GRO-2094 (§5.1.6/5.1.7) and GRO-2099 (§5.27) also covered.
  • .mcp.json: dev tooling config using env-var template, no credential exposure.

Clear to merge.

QA code review approved. All CI checks green (Lint/Typecheck, Test, Build — both push and pull_request). Review notes: - GRO-2105 core fix: `fetchAvailability` helper correctly includes `serviceId` in both BookingFlow and RescheduleFlow, validates `res.ok` + `Array.isArray(data)`, guards on missing serviceId, adds cancellation cleanup. - Tests: serviceId assertion updated; two new cases (4xx error object, 200-with-non-array body) verified. 141/141 pass. - UAT_PLAYBOOK §5.12b: updated with serviceId in expected URL and non-array error path in TC-5.12.7/5.12.10. GRO-2094 (§5.1.6/5.1.7) and GRO-2099 (§5.27) also covered. - .mcp.json: dev tooling config using env-var template, no credential exposure. Clear to merge.
Flea Flicker merged commit 47c29ecbc2 into uat 2026-06-02 19:17:04 +00:00
Sign in to join this conversation.