Promote uat → main (PROD): GRO-2359 OOBE portal-creation routing (web) #79

Open
Flea Flicker wants to merge 1 commits from flea/uat-to-main-gro-2359-web into main
Member

Promote uat → main (PROD): GRO-2359 — OOBE portal-creation routing (web)

Carries the deployed + UAT-validated GRO-2359 P2 web commit
(2069b133, frozen on main base 661bd4f9) to main (PROD).

What's in this PR

Commit Description
2069b133 feat(GRO-2359): route Authentik new-SSO users into OOBE (web)

Diff scope (5 files, 699+/36-)

  • src/App.tsx — new /onboarding deep-link route
  • src/portal/CustomerPortal.tsx — SSO-bridge 404 mounts OOBE inline; deleted-portal path still reaches no-access screen with shared signOut()
  • src/portal/OOBE.tsxnew OOBE component (auth-gated, shared signOut, name prefilled from session, 409/network-error handling)
  • src/__tests__/portal.test.tsx — OOBE render + 201/409 + signOut paths
  • UAT_PLAYBOOK.md — TC-WEB-7.* OOBE acceptance

SDLC gates already passed

  • QA (dev→uat): GRO-2369 APPROVED (web#76 + api#213)
  • Deploy to UAT: GRO-2372 DONE (infra PR #661 self-merged, flux reconciled: web:2026.06.11-a7f2e2e + api:2026.06.11-a629331)
  • UAT regression (Shedward): GRO-2370 PASS — post-deploy security sign-off against the deployed images
  • Security review: GRO-2371 PASS — d5d598f3 comment with full findings + LOW notes

P1 pre-requisite satisfied

  • GRO-2358 merged to main via uat→main PR #74 (661bd4f9) — the no-access screen has a working signOut() (shared lib/auth-client.ts).

No-access screen preserved

  • Per GRO-2359 acceptance criteria: deleted-portal path (?noAccess=deleted-portal) still renders the no-access screen — P2 only removes the new-user path to that screen, not all paths to it.
  • GRO-2358 ensures signOut() works there.

Why a frozen PR, not a live uat→main PR

Per uat-to-main-pr-head-drift-frozen-branch-recut.md (GRO-2244 #185):

  • uat has continued to advance since the GRO-2359 merge (a7f2e2e6 is the GRO-2359 uat tip, then the GRO-2373 dev→uat followed it).
  • A live uat→main PR would replay the fanned-out post-GRO-2359 diff onto main.
  • Frozen branch at 2069b133 (1 commit ahead of main 661bd4f9) keeps the PR to exactly the GRO-2359 files.

cc @cpfarhood — formal Gitea review needed for uat → main per uat-to-main-requires-cto-gitea-review-when-whitelist-fixed.md.

Refs GRO-2359 / GRO-2357 / GRO-2355.

## Promote uat → main (PROD): GRO-2359 — OOBE portal-creation routing (web) Carries the **deployed + UAT-validated** GRO-2359 P2 web commit (`2069b133`, frozen on `main` base `661bd4f9`) to **main** (PROD). ### What's in this PR | Commit | Description | |---|---| | `2069b133` | feat(GRO-2359): route Authentik new-SSO users into OOBE (web) | ### Diff scope (5 files, 699+/36-) - `src/App.tsx` — new `/onboarding` deep-link route - `src/portal/CustomerPortal.tsx` — SSO-bridge 404 mounts OOBE inline; deleted-portal path still reaches no-access screen with shared `signOut()` - `src/portal/OOBE.tsx` — **new** OOBE component (auth-gated, shared signOut, name prefilled from session, 409/network-error handling) - `src/__tests__/portal.test.tsx` — OOBE render + 201/409 + signOut paths - `UAT_PLAYBOOK.md` — TC-WEB-7.* OOBE acceptance ### SDLC gates already passed - **QA (dev→uat)**: [GRO-2369](https://paperclip.farhoodlabs.com/GRO/issues/GRO-2369) APPROVED (web#76 + api#213) - **Deploy to UAT**: [GRO-2372](https://paperclip.farhoodlabs.com/GRO/issues/GRO-2372) DONE (infra PR #661 self-merged, flux reconciled: `web:2026.06.11-a7f2e2e` + `api:2026.06.11-a629331`) - **UAT regression (Shedward)**: [GRO-2370](https://paperclip.farhoodlabs.com/GRO/issues/GRO-2370) PASS — post-deploy security sign-off against the *deployed* images - **Security review**: [GRO-2371](https://paperclip.farhoodlabs.com/GRO/issues/GRO-2371) PASS — `d5d598f3` comment with full findings + LOW notes ### P1 pre-requisite satisfied - [GRO-2358](https://paperclip.farhoodlabs.com/GRO/issues/GRO-2358) merged to main via uat→main PR #74 (`661bd4f9`) — the no-access screen has a working `signOut()` (shared `lib/auth-client.ts`). ### No-access screen preserved - Per GRO-2359 acceptance criteria: deleted-portal path (`?noAccess=deleted-portal`) **still** renders the no-access screen — P2 only removes the *new-user* path to that screen, not all paths to it. - GRO-2358 ensures `signOut()` works there. ### Why a frozen PR, not a live uat→main PR Per `uat-to-main-pr-head-drift-frozen-branch-recut.md` (GRO-2244 #185): - uat has continued to advance since the GRO-2359 merge (`a7f2e2e6` is the GRO-2359 uat tip, then the GRO-2373 dev→uat followed it). - A live uat→main PR would replay the **fanned-out** post-GRO-2359 diff onto main. - Frozen branch at `2069b133` (1 commit ahead of `main` `661bd4f9`) keeps the PR to **exactly** the GRO-2359 files. cc @cpfarhood — formal Gitea review needed for `uat → main` per `uat-to-main-requires-cto-gitea-review-when-whitelist-fixed.md`. Refs GRO-2359 / GRO-2357 / GRO-2355.
Flea Flicker added 1 commit 2026-06-11 21:41:57 +00:00
feat(GRO-2359): route Authentik new-SSO users into OOBE (web)
CI / Test (pull_request) Successful in 19s
CI / Lint & Typecheck (pull_request) Successful in 26s
CI / Build & Push Docker Image (pull_request) Successful in 43s
2069b1332c
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)
Some checks are pending
CI / Test (pull_request) Successful in 19s
CI / Lint & Typecheck (pull_request) Successful in 26s
CI / Build & Push Docker Image (pull_request) Successful in 43s
This pull request doesn't have enough required approvals yet. 0 of 1 approvals granted from users or teams on the allowlist.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin flea/uat-to-main-gro-2359-web:flea/uat-to-main-gro-2359-web
git checkout flea/uat-to-main-gro-2359-web
Sign in to join this conversation.