Use `corepack install -g` instead of `corepack prepare --activate` to write
pnpm to a stable global path (/usr/local/bin/pnpm) rather than relying on
corepack shims that re-validate against npmjs.org at runtime.
Set COREPACK_ENABLE_DOWNLOAD_PROMPT=0 and COREPACK_ENABLE_STRICT=0 to suppress
the interactive download prompt and strict version checks that also trigger
network access.
Remove the dead `RUN mkdir -p /home/node/.cache/node/corepack` line from the
builder stage (vestigial cache-location configuration).
Fixes: GRO-1916 (prod migrate-schema EAI_AGAIN on registry.npmjs.org)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Updated UAT_PLAYBOOK.md §4.3 — new seed data verification tests.
GRO-1898: After populating extended profile fields in the UAT seed, add
test cases to verify the data is actually present and shaped correctly.
Test cases cover:
- /api/clients returns seed data
- /api/pets/{id} returns all 5 extended fields for UAT test pets
- medicalAlerts shape is correct ({type, description, severity})
- Deterministic UAT pets (Charlie = behavioral alert, Delta = skin alert)
are verifiably populated
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GRO-1898: Ensure UAT seed data includes clients and pets with extended
profile fields (temperamentScore, temperamentFlags, medicalAlerts,
preferredCuts, coatType).
- Add data pools for extended profile fields in pet batch generation
- Populate all 5 extended fields for randomly generated pets
- Update UAT test client pets with fully populated extended profiles
- Fix type mismatches: medicalAlerts uses MedicalAlert[] with
{type, description, severity} shape per @groombook/types
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Conflicts resolved:
- src/middleware/rbac.ts: keep dev version (email null-guard, type assertion, single null-check)
- .gitea/workflows/ci.yml: keep uat version (branches: [main, dev, uat])
Co-Authored-By: Paperclip <noreply@paperclip.ing>
fix(gro-1866): add session-from-auth portal endpoint + role scope (#93)
Bridges Better Auth SSO sessions to portal sessions for real customers.
Adds role to genericOAuth scopes for Authentik role propagation.
Closes GRO-1866
Fixes two bugs found in QA review:
- ReferenceError: getAuth not defined in beforeEach - add import
- TypeError: wrong mock chain insert().into().values() vs insert().values()
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds POST /api/portal/session-from-auth which bridges a valid Better Auth
customer session (from SSO login) to a portal impersonation session, so
real SSO customers can access the client portal.
The endpoint is registered before the validatePortalSession catch-all so it
is not subject to that middleware. It validates the Better Auth session
from request cookies, looks up the client by email, creates an active
impersonation session, and returns { sessionId, clientId, clientName }.
Also adds "role" to the genericOAuth scopes so Authentik propagates the
role claim into Better Auth user objects (GRO-1862 root cause fix).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
GRO-1850: Adds temperament_score, temperament_flags, medical_alerts,
and preferred_cuts to the pets table.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
feat(GRO-1177): add pet profile summary endpoint (#30)
Adds GET /api/pets/:id/profile-summary with aggregated pet profile,
grooming history, visit count, and upcoming appointment.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Replace .select({ count: appointments.id }).limit(1) + .length with
sql<number>`count(*)::int` pattern per project standard (references invoices.ts:86)
- Add gte(appointments.startTime, new Date()) to upcomingAppointment query
so past appointments in scheduled/confirmed status are excluded
- Add visitCount regression tests: 2+ completed appointments → visitCount >= 2,
no completed → visitCount = 0
Updated UAT_PLAYBOOK.md §profile-summary (visitCount regression + date filter)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
With noUncheckedIndexedAccess:true, split("@")[0] returns string|undefined,
making `name` typed as string|undefined and failing the notNull staff.name
insert constraint. Fix by using ?? fallback on the array access.
Also add newStaff null guard after .returning() destructure — array
destructuring yields T|undefined with noUncheckedIndexedAccess enabled.
With noUncheckedIndexedAccess:true, split("@")[0] returns string|undefined,
making `name` typed as string|undefined and failing the notNull staff.name
insert constraint. Fix by using ?? fallback on the array access.
Also add newStaff null guard after .returning() destructure — array
destructuring yields T|undefined with noUncheckedIndexedAccess enabled.
Duplicate 'provenance: false' in each docker/build-push-action step caused
Gitea to reject the workflow file, breaking push CI and workflow_dispatch.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The DB coat_type enum only accepts: smooth, double, wire, curly, long, hairless.
"short" is not a valid value — corrected to "smooth".
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Lint Roller (QA) flagged that buildPet in factories.ts was missing the
4 fields added to the pets table schema, causing TS2739 in the Docker
build job (run 1701, job 3717).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>