Compare commits

..

1 Commits

Author SHA1 Message Date
Flea Flicker e8ef481a11 fix(ci): run api root lint/typecheck/test scripts; remove dead servicesTable (GRO-2197)
CI / Test (pull_request) Successful in 1m20s
CI / Lint & Typecheck (pull_request) Successful in 1m23s
CI / Build & Push Docker Images (pull_request) Successful in 3m43s
The api gate ran `pnpm --filter @groombook/api <script>`, but @groombook/api
is the workspace ROOT package and pnpm-workspace.yaml only includes packages/*,
so --filter excluded the root and the lint/typecheck/test steps silently
no-op'd (false-green). Invoke the root scripts directly instead.

Now that the gate actually runs eslint, fix the latent unused-var error in
src/__tests__/petProfileSummary.test.ts: servicesTable was declared and
assigned in resetMock but never enqueued/read. Remove the declaration, the
dead write, and the now-orphaned makeService helper (its only caller).

Verified locally: pnpm run typecheck, pnpm --filter @groombook/db typecheck,
pnpm run lint (0 errors), pnpm run test (602 passed) all green.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-08 11:02:29 +00:00
3 changed files with 3 additions and 21 deletions
+3 -3
View File
@@ -33,11 +33,11 @@ jobs:
- name: Typecheck
run: |
pnpm --filter @groombook/api typecheck
pnpm run typecheck
pnpm --filter @groombook/db typecheck
- name: Lint
run: pnpm --filter @groombook/api lint
run: pnpm run lint
test:
name: Test
@@ -58,7 +58,7 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Run tests
run: pnpm --filter @groombook/api test
run: pnpm run test
docker:
name: Build & Push Docker Images
-2
View File
@@ -147,8 +147,6 @@ Expected: one row, `role = 'groomer'`. If zero rows return, the request hit the
| TC-API-3.19b | Get pet profile summary — customer cross-tenant blocked (GRO-2013) | Sign in as `uat-customer@groombook.dev`; reuse the customer's sessionId from TC-API-3.19a; `GET /api/pets/{otherClientPetId}/profile-summary` for a pet owned by a different client (`c0000002-...` or any non-customer pet) | 403 Forbidden (owner-bypass requires session.clientId === pet.clientId) |
| TC-API-3.19c | Get pet profile summary — customer without portal session header | Same as TC-API-3.19a but omit the `X-Impersonation-Session-Id` header | 403 Forbidden (no owner-bypass without valid portal session) |
| TC-API-3.19d | Get pet profile summary — owner-bypass writes audit row (GRO-2063) | Same setup as TC-API-3.19a (sign in as `uat-customer@groombook.dev`, establish a portal session for the customer's own clientId, call `GET /api/pets/{ownPetId}/profile-summary` with `X-Impersonation-Session-Id: {sessionId}` and a 200 OK response). Then call `GET /api/impersonation/sessions/{sessionId}/audit-log` and confirm there is exactly one entry with `action === "read_profile_summary"`, `pageVisited` matching the profile-summary path, and `metadata` containing `petId` and `actorStaffId` for the customer. Repeat TC-API-3.19b (cross-tenant attempt) and confirm NO new `read_profile_summary` row was written for the cross-tenant attempt. | 200 OK on the profile-summary call AND an audit log entry is present with the correct shape (defense-in-depth audit row; bypass attempts against other clients must NOT log) |
| TC-UAT-2 | Groomer accesses linked pet profile summary (GRO-2100) | Sign in as `uat-groomer@groombook.dev`; `GET /api/pets/c0000001-0000-0000-0000-000000000002/profile-summary` (UAT Pup Alpha — linked via deterministic completed appointment `a0000001-0000-0000-0000-000000000001`, service `b0000001-…-0001` "Bath & Brush", `startTime` ~7 days ago) | 200 OK, `recentGroomingHistory[]` non-empty (>=1 entry), `visitCount >= 1`, `upcomingAppointment` null (the seeded appointment is in the past) |
| TC-UAT-3 | Groomer blocked from unlinked pet profile summary (GRO-2100) | Sign in as `uat-groomer@groombook.dev`; `GET /api/pets/c0000001-0000-0000-0000-000000000003/profile-summary` (UAT Pup Beta — intentionally UNLINKED; no appointment row references this pet's clientId+groomerId combo) | 403 Forbidden (RBAC `groomer` role lacks the appointment-linkage grant for this pet). NOTE: if 404 is returned instead of 403, file a separate RBAC defect (not against the seed) — see GRO-2100 verification note |
| TC-API-3.29 | Get pet profile summary — unknown UUID returns 404 (GRO-2014) | GET /api/pets/00000000-0000-0000-0000-000000000001/profile-summary while authenticated (any role) | 404 Not Found with body `{"error":"Not found"}` (was empty-body 500 in GRO-2014) |
| TC-API-3.30 | Get pet profile summary — malformed UUID returns 404 (GRO-2014) | GET /api/pets/not-a-uuid/profile-summary while authenticated | 404 Not Found with body `{"error":"Not found"}` (was empty-body 500 in GRO-2014 — Postgres uuid cast failure) |
| TC-API-3.31 | Get pet profile summary — never empty-body 500 (GRO-2014) | GET /api/pets/{anyId}/profile-summary across the test sweep | No response has status 500 with an empty body. Any 500 must include a JSON body `{"error":"Internal Server Error"}` |
-16
View File
@@ -131,20 +131,6 @@ function makeAppointment(overrides: Record<string, unknown> = {}) {
};
}
function makeService(overrides: Record<string, unknown> = {}) {
return {
id: "service-1",
name: "Full Groom",
description: null,
basePriceCents: 6000,
durationMinutes: 120,
active: true,
createdAt: new Date(),
updatedAt: new Date(),
...overrides,
};
}
function makeSession(overrides: Record<string, unknown> = {}) {
return {
id: "sess-owner",
@@ -164,7 +150,6 @@ function makeSession(overrides: Record<string, unknown> = {}) {
let petsTable: Record<string, unknown>[];
let appointmentsTable: Record<string, unknown>[];
let servicesTable: Record<string, unknown>[];
let sessionsTable: Record<string, unknown>[];
// selectQueue: queries resolve in FIFO order. Each .from(table) result
@@ -198,7 +183,6 @@ function enqueueThrow(table: string, message: string) {
function resetMock() {
petsTable = [makePet()];
appointmentsTable = [makeAppointment()];
servicesTable = [makeService()];
sessionsTable = [makeSession()];
selectQueue = [];
insertCapture = [];