The post-auth handler in CustomerPortal previously rendered the
"Portal access not configured" card when the SSO bridge returned 404
(no client row for the user's email). That trapped first-time SSO
users on a dead-end screen with no path to portal creation.
This change routes the 404 to a new OOBE component (src/portal/OOBE.tsx)
that drives portal creation:
* Mounts inline inside CustomerPortal so the post-auth flow stays
inside the portal render tree (no App-level router needed).
* Also reachable as a direct deep-link via the new /onboarding route
in App.tsx (for grooming admins or recovery flows).
* Submits to a new POST /api/portal/clients-from-auth endpoint in
groombook-api (companion commit) that creates a fresh client row
bound to the Better Auth email. 409 means the email already has a
portal record — the OOBE shows a portal-selection message.
* Uses the canonical shared signOut() from lib/auth-client (GRO-2358
invariant) for the Sign out button.
* Full window.location.href reload on submit success to reset the
bridge's cached state and land the user in their portal.
The no-access card itself is preserved for the deep-link deleted-portal
case (a customer whose portal was disabled/deleted), signalled via
?noAccess=deleted-portal on a portal sub-route. The OOBE handles the
first-time-creation case; the no-access card handles the "had a portal
but lost it" case.
Test coverage:
* "routes to /onboarding when session-from-auth returns 404 (GRO-2359)"
— proves the post-auth 404 mounts the OOBE inline, not the legacy
no-access card.
* 6 new OOBE tests: render from direct link, name prefill, form
submission, 409 portal-selection, required-name validation, shared
signOut(), redirect on no-session.
* P1 no-access tests reworked to use ?noAccess=deleted-portal so the
GRO-2358 signOut invariant is still verified on the only surviving
path to the no-access card.
UAT_PLAYBOOK §5.25.5–6e rewritten to cover the OOBE flow (form submit,
409, deep-link mount, deleted-portal no-access card).
Paired with the api PR on feature/2357-p2-portal-clients-from-auth.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
(cherry picked from commit 250c7a5ac9)
Merge PR #50: fix(GRO-2180) portal Appointments ISO startTime (dev → uat)
QA-approved (gb_lint); PR CI green after transient runner re-run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
promote: dev → uat (GRO-1173 buffer rules + GRO-1470 pet save persistence) (#14)
Merged-By: The Dogfather (CTO)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
| TC-WEB-5.16.4 | My Pets tab row — horizontal scroll, no visible scrollbar | Sign in as customer → My Pets. Set viewport to 390px. If 3+ pets are seeded, the pet-selector row overflows. | Pet selector row scrolls horizontally; native scrollbar is **not** visible (`scrollbar-width: none` / `scrollbar-hide` applied). |
| TC-WEB-5.16.5 | My Pets section tab row — no visible scrollbar | On the same My Pets view, observe the tabs row (Basic Info / Medical / Grooming / History). | Tabs row scrolls horizontally when needed; native scrollbar is not visible. |
| TC-WEB-5.16.6 | Billing/Payments tab row — no wrap, no visible scrollbar | Sign in as customer → Billing/Payments at 390px. | Tab row (Invoices / Payment Methods / Packages) does **not** wrap to a second line; scrolls horizontally if needed; native scrollbar not visible. |
| TC-WEB-5.16.7 | Desktop — no visual regression | Open My Pets and Billing/Payments at ≥1024px. | No layout change; tab rows display identically to before the fix. |
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.