Row-level data scoping for groomer role (RBAC Phase 2) #118

Closed
opened 2026-03-26 21:41:47 +00:00 by the-dogfather-cto[bot] · 1 comment
the-dogfather-cto[bot] commented 2026-03-26 21:41:47 +00:00 (Migrated from github.com)

Summary

Phase 1 of RBAC (endpoint-level authorization) shipped in #88. This issue tracks Phase 2: row-level data scoping for the groomer role.

Problem

Groomers currently have read access to all clients, pets, and appointments. In a multi-groomer salon, a groomer can see every client and every appointment — not just their own. While they can't write to data outside their role, the privacy exposure is a concern for salon managers.

Scope

Filter data returned to groomers at the query level so they only see records they're actually working with:

  • Appointments (GET /api/appointments) — return only appointments where staffId matches the authenticated groomer's staff ID
  • Clients (GET /api/clients, GET /api/clients/:id) — return only clients who have at least one appointment assigned to this groomer
  • Pets (GET /api/pets, GET /api/pets/:petId) — return only pets whose owner is a client assigned to this groomer

Managers and receptionists retain full read access (no filtering).

Out of Scope

  • Grooming logs access for groomers (tracked separately — groomers currently have no access; evaluate whether they should be able to create logs for their own appointments)
  • UI changes to reflect filtering
  • Appointment group / waitlist access for groomers

Implementation Notes

  • Filter logic should live in the route handlers, not the RBAC middleware, to keep the middleware thin and testable
  • Use c.get("staff") (set by resolveStaffMiddleware) to get the current staff role and ID
  • Add integration tests covering groomer read isolation

Acceptance Criteria

  • Groomer receives only their own appointments on GET /api/appointments
  • Groomer receives only clients/pets linked to their appointments
  • Manager and receptionist reads are unaffected
  • GET /api/appointments/:id returns 403 if the appointment is not assigned to the requesting groomer
  • Tests cover all three resources for groomer isolation

Context

cc @cpfarhood

## Summary Phase 1 of RBAC (endpoint-level authorization) shipped in #88. This issue tracks **Phase 2: row-level data scoping** for the groomer role. ## Problem Groomers currently have read access to all clients, pets, and appointments. In a multi-groomer salon, a groomer can see every client and every appointment — not just their own. While they can't write to data outside their role, the privacy exposure is a concern for salon managers. ## Scope Filter data returned to groomers at the query level so they only see records they're actually working with: - **Appointments (`GET /api/appointments`)** — return only appointments where `staffId` matches the authenticated groomer's staff ID - **Clients (`GET /api/clients`, `GET /api/clients/:id`)** — return only clients who have at least one appointment assigned to this groomer - **Pets (`GET /api/pets`, `GET /api/pets/:petId`)** — return only pets whose owner is a client assigned to this groomer Managers and receptionists retain full read access (no filtering). ## Out of Scope - Grooming logs access for groomers (tracked separately — groomers currently have no access; evaluate whether they should be able to create logs for their own appointments) - UI changes to reflect filtering - Appointment group / waitlist access for groomers ## Implementation Notes - Filter logic should live in the route handlers, not the RBAC middleware, to keep the middleware thin and testable - Use `c.get("staff")` (set by `resolveStaffMiddleware`) to get the current staff role and ID - Add integration tests covering groomer read isolation ## Acceptance Criteria - [ ] Groomer receives only their own appointments on `GET /api/appointments` - [ ] Groomer receives only clients/pets linked to their appointments - [ ] Manager and receptionist reads are unaffected - [ ] `GET /api/appointments/:id` returns 403 if the appointment is not assigned to the requesting groomer - [ ] Tests cover all three resources for groomer isolation ## Context - Phase 1 (endpoint RBAC): #88 — **closed/shipped** - Product backlog: #84 - Related Paperclip: GRO-45 cc @cpfarhood
the-dogfather-cto[bot] commented 2026-03-27 16:54:10 +00:00 (Migrated from github.com)

Row-level data scoping for groomer role is live on main (commit 9eb0c3d). All 6 endpoints scoped per spec. PR #125 closed as redundant — changes were already merged. Closing.

Row-level data scoping for groomer role is live on main (commit 9eb0c3d). All 6 endpoints scoped per spec. PR #125 closed as redundant — changes were already merged. Closing.
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: groombook/app#118