CI failed on PR #137 because `tsc --project .` (the build path used by the
Docker image) is stricter than `pnpm typecheck` was reporting during local
iteration — two TS2322 errors surfaced in the new mock:
1. `chain.from = (table: { _name: string }) => ...` was assigned through
a `Record<string, (...args: unknown[]) => unknown>` index signature,
and `{ _name: string }` is not assignable from `unknown`.
2. `chain.then = (onFulfilled?: (v: unknown[]) => unknown) => ...` was
not assignable to the `PromiseLike<T>.then` signature TS now infers
for the awaitable, because TS expects `onfulfilled` to also accept
`null`.
Replace the proxy-based loose chain with a typed `ChainLike` interface so
the build typechecker is satisfied. Behaviour is unchanged — all 7 GRO-2014
regression tests still pass.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Defect: GET /api/pets/:id/profile-summary previously returned an empty-body
500 Internal Server Error for any UUID that the caller had no linkage to
(and presumably also for any malformed/non-UUID path param), because the
route had no upfront UUID validation, no defensive staff context guard,
and no router-level onError to catch downstream Drizzle/Postgres errors.
Changes:
- src/routes/pets.ts
- Add router.onError that returns a JSON envelope (`{"error":"Internal Server
Error"}`) instead of Hono's default empty-body 500. Mirrors the pattern
already used in invoices.ts and reports.ts.
- profile-summary: validate the :id path param with z.string().uuid()
before hitting Postgres. Malformed UUIDs now return 404 Not Found
instead of triggering a Postgres uuid cast that throws and bubbles
up as a 500.
- profile-summary: explicit `if (!staffRow)` guard returns 401 instead
of relying on optional chaining and risking a TypeError later in the
groomer linkage check on staffRow.id.
- src/__tests__/petProfileSummary.test.ts (new)
- 7 regression tests covering: malformed UUID → 404; missing staff →
401; pet not found → 404; groomer with no linkage → 403; manager
happy path → 200; groomer with linkage → 200; downstream DB throw
→ 500 with JSON body (never empty body).
- UAT_PLAYBOOK.md §3 (TC-API-3.29 / 3.30 / 3.31)
- Document the new 404 behaviour for unknown and malformed UUIDs and
the JSON-envelope requirement for any 500.
Notes for QA:
- Spec from GRO-2014: 404 if pet does not exist, 403 if no linkage, 401
if not authenticated. The "Forbidden if no linkage" path was already
correct for groomers; the 500 → 404/JSON-500 collapse is the actual
change in observable behaviour.
- The route's customer-as-groomer auto-provision issue (GRO-2013) is
*not* addressed here. It remains the customer-side defect; this PR
only fixes the error-handling regression.
Refs: GRO-1892, GRO-2013
Co-Authored-By: Paperclip <noreply@paperclip.ing>