Resolve conflicts with PR #132 (UAT_PLAYBOOK doc updates GRO-2000) and
PR #137 (profile-summary error handling GRO-2014) which landed on dev
after this PR was opened.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts:
# UAT_PLAYBOOK.md
When a customer (e.g. uat-customer@groombook.dev) signs in via Better Auth
and calls GET /api/pets/{ownPetId}/profile-summary with their portal
session header, the staff RBAC middleware auto-provisions a 'groomer'
staff row for them (rbac.ts) and the profile-summary route's
groomerLinkageCheck then denies the request with 403 Forbidden, because
the auto-provisioned customer-as-groomer has no appointment linkage.
This adds an owner-bypass: when a groomer-role staff row is making the
request with a valid X-Impersonation-Session-Id header, and the resolved
impersonation session's clientId matches the pet's clientId, we treat
the caller as the pet's owner and skip the groomerLinkageCheck.
The bypass is intentionally scoped to the profile-summary endpoint and
to the existing portal session mechanism (no new roles, no staff-row
shape changes). Cross-tenant access is still blocked because the
bypass requires session.clientId === pet.clientId.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The 'Source of truth for UAT passwords' subsection under Pre-conditions
records:
- The seed-uat-passwords Secret in groombook-uat is the live source.
- The Bitnami SealedSecret apps/overlays/uat/ss-seed-uat-passwords.yaml
in groombook/infra is the single upstream source of truth.
- A kubectl recipe to pull the current values for SUPER / GROOMER /
TESTER / CUSTOMER at the start of every UAT run.
- The 'captured env var from a previous rotation produces 401' failure
mode that GRO-2000 hit, and the manual-reseed escape hatch if the
login still 401s after pulling the live value.
Refs: GRO-2000, GRO-1977 (idempotent re-hash), GRO-1999 (enum fix that
allowed the seed Job to run cleanly again).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>