fix(portal): implement PATCH /portal/pets/:petId + enrich GET (GRO-2187, fixes GRO-1480 §5.23) #165

Merged
Flea Flicker merged 1 commits from fix/gro-2187-portal-pets-patch into dev 2026-06-08 08:18:13 +00:00
Member

What & why

UAT §5.23 (parent GRO-1480) failed: the customer portal pet-save calls PATCH /api/portal/pets/{petId}, which the deployed src/ tree never registered → 404, no persistence. GET /portal/pets also omitted the extended fields, so a write would not be visible on reload.

Gitea source-of-truth issue: groombook/api #162.

Changes (src/routes/portal.ts)

  1. PATCH /portal/pets/:petId with ownership enforcement (pet.clientId === portalClientId → 403; missing pet → 404), mirroring the appointment-notes handler.
  2. Payload → column mapping: name, breed, weightKg (accepts weightKg/weight), dateOfBirth (birthDate), groomingNotes (notes), healthAlerts, photoKey (photoUrl), coatType, petSizeCategory (web xlarge → DB extra_large), preferredCuts, medicalAlerts; sets updatedAt. The web form spreads the GET-shaped pet plus its own edited keys, so both spellings are accepted.
  3. Invalid coatType/petSizeCategory → 422 (validated in-handler; zValidator failures would surface as 400).
  4. GET /portal/pets enriched with coatType, petSizeCategory, healthAlerts, preferredCuts, medicalAlerts.
  5. Tests (src/__tests__/portalPets.test.ts): owner success + persistence, weight fallback, non-owner 403, not-found 404, invalid enum 422 (coat + size), missing-session 401.

The coatType/petSizeCategory enums were already present in packages/db/src/schema.ts (no change needed).

UAT Playbook

Updated UAT_PLAYBOOK.md §4.8 (Customer Portal) — added TC-API-8.12 (GET extended fields), TC-API-8.13 (owner PATCH success + persistence, xlargeextra_large), TC-API-8.14 (non-owner blocked), TC-API-8.15 (invalid enum 422).

Verification

  • pnpm test — 582 passed (incl. 7 new portal-pet tests, both src/ and apps/api/ trees).
  • pnpm typecheck — clean.
  • Lint clean on changed files.

cc @cpfarhood

## What & why UAT §5.23 (parent [GRO-1480](/GRO/issues/GRO-1480)) failed: the customer portal pet-save calls `PATCH /api/portal/pets/{petId}`, which the deployed `src/` tree never registered → **404, no persistence**. `GET /portal/pets` also omitted the extended fields, so a write would not be visible on reload. Gitea source-of-truth issue: groombook/api **#162**. ## Changes (`src/routes/portal.ts`) 1. **`PATCH /portal/pets/:petId`** with ownership enforcement (`pet.clientId === portalClientId` → 403; missing pet → 404), mirroring the appointment-notes handler. 2. **Payload → column mapping**: name, breed, weightKg (accepts `weightKg`/`weight`), dateOfBirth (`birthDate`), groomingNotes (`notes`), healthAlerts, photoKey (`photoUrl`), coatType, petSizeCategory (web `xlarge` → DB `extra_large`), preferredCuts, medicalAlerts; sets `updatedAt`. The web form spreads the GET-shaped pet plus its own edited keys, so both spellings are accepted. 3. **Invalid `coatType`/`petSizeCategory` → 422** (validated in-handler; zValidator failures would surface as 400). 4. **`GET /portal/pets` enriched** with coatType, petSizeCategory, healthAlerts, preferredCuts, medicalAlerts. 5. **Tests** (`src/__tests__/portalPets.test.ts`): owner success + persistence, weight fallback, non-owner 403, not-found 404, invalid enum 422 (coat + size), missing-session 401. The `coatType`/`petSizeCategory` enums were already present in `packages/db/src/schema.ts` (no change needed). ## UAT Playbook Updated `UAT_PLAYBOOK.md` §4.8 (Customer Portal) — added **TC-API-8.12** (GET extended fields), **TC-API-8.13** (owner PATCH success + persistence, `xlarge`→`extra_large`), **TC-API-8.14** (non-owner blocked), **TC-API-8.15** (invalid enum 422). ## Verification - `pnpm test` — 582 passed (incl. 7 new portal-pet tests, both `src/` and `apps/api/` trees). - `pnpm typecheck` — clean. - Lint clean on changed files. cc @cpfarhood
Flea Flicker added 1 commit 2026-06-08 08:13:30 +00:00
fix(portal): implement PATCH /portal/pets/:petId + enrich GET /portal/pets (GRO-2187)
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 16s
CI / Build & Push Docker Images (pull_request) Successful in 3m50s
23be6230ba
The customer portal pet-save calls PATCH /api/portal/pets/{petId}, which the
deployed src/ tree never registered → 404, no persistence (UAT §5.23 / GRO-1480
regression). Also GET /portal/pets omitted the extended fields, so a write was
not visible on reload.

- Add portalRouter.patch("/pets/:petId", …) with ownership enforcement
  (pet.clientId === portalClientId → 403, missing pet → 404), mirroring the
  appointment-notes handler.
- Map the web payload to pets columns: name, breed, weightKg (accept
  weightKg/weight), dateOfBirth (birthDate), groomingNotes (notes), healthAlerts,
  photoKey (photoUrl), coatType, petSizeCategory (web "xlarge" → DB
  "extra_large"), preferredCuts, medicalAlerts; set updatedAt.
- Reject invalid coatType/petSizeCategory with 422 (validated in-handler).
- Enrich GET /portal/pets with coatType, petSizeCategory, healthAlerts,
  preferredCuts, medicalAlerts.
- Add src/__tests__/portalPets.test.ts: owner success + persistence, weight
  fallback, non-owner 403, not-found 404, invalid enum 422, missing session 401.
- UAT_PLAYBOOK.md §4.8: add TC-API-8.12–8.15 for portal pet GET/PATCH.

coatType/petSizeCategory enums already present in packages/db/src/schema.ts.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Flea Flicker merged commit 6be78cae35 into dev 2026-06-08 08:18:13 +00:00
Sign in to join this conversation.