GRO-623: groomer data isolation + batherStaffId conflict fix #276
Closed
lint-roller-qa[bot] wants to merge 1 commits from
feature/gro-623-groomer-isolation into main
pull from: feature/gro-623-groomer-isolation
merge into: groombook:main
groombook:main
groombook:dev
groombook:flea/gro-1636-better-auth-seed
groombook:pr-434
groombook:uat
groombook:docs/GRO-1502-uat-mcp-migration
groombook:flea/gro-1496-e2e-err-connection-refused
groombook:flea-flicker/gro-1489-lint-fixes
groombook:cpfarhood/gro-1162-pet-buffer
groombook:flea-flicker/gro-1162-pet-buffer
groombook:fix/gro-1368-consent-ts
groombook:fix/ci-e2e-dind-networking-registry-auth
groombook:fix/gro-1369-types-sync
groombook:fix/ci-registry-auth-main
groombook:gitea/migrate-workflows
groombook:flea-flicker/gro-1162-pet-buffer-time
groombook:feat/GRO-106-portal-communication-real
groombook:archived-readme
groombook:feat/GRO-106-stop-help
groombook:fix/gro-1248-path-prefixes
groombook:fix/GRO-1212-portal-test-mock-imports
groombook:fix/GRO-1108-test-mocks
groombook:feat/GRO-106-stop-help-v2
groombook:docs/GRO-1099-uat-playbook-app
groombook:fleaflicker/deploy-telnyx-webhook-secret
groombook:fix/gro-1024-clean
groombook:fix/gro-1021-auth-rate-limit
groombook:fix/gro-1021-auth-rate-limit-v2
groombook:feat/GRO-984-outbound-sms-persistence
groombook:fix/GRO-980-indentation
groombook:docs/GRO-106-10dlc-runbook
groombook:fix/gro-898-demo-sso-env-vars
groombook:fix/gro-609-cherry-pick
groombook:fix/gro-866-uat-seed-personas
groombook:fix/gro-867-logo-proxy
groombook:fix/gro-816-portal-pets-crash
groombook:fix/gro-844-network-policy
groombook:fix/gro-820-e2e-invoices-mock
groombook:feature/gro-609-refund-payment-stats
groombook:fix/gro-765-portal-appointments-service
groombook:fix/gro-805-allow-groomer-invoices
groombook:fix/gro-720-gitignore-hardening
groombook:fix/gro-721-harden-gitignore
groombook:feature/gro-633-db-indexes-constraints
groombook:fix/gro-639-n-plus-one-reminder-scheduler
groombook:ci-dev-trigger2
groombook:fix/gro-624-input-validation
groombook:feature/gro-653-portal-session-middleware
groombook:fix/gro-640-n-plus-one-email
groombook:clean-gro-639
groombook:fix/gro-637-invoice-refund-fixes
groombook:fix/gro-665-staff-auto-link
groombook:fix/gro-636-input-validation-v3
groombook:fix-gro-624-input-validation
groombook:fix/gro-655-corepack-only
groombook:feature/gro-597-payment-admin
groombook:feature/gro-631-graceful-shutdown
groombook:fix/gro-660-uat-seed-manager-superuser
groombook:fix/gro-655-corepack-enoent
groombook:feature/gro-632-impersonation-session-hardening
groombook:feature/gro-607-payment-ui
groombook:feature/gro-597-payment-backend
groombook:feature/gro-597-payment-ui
groombook:feature/gro-597-stripe-webhooks
groombook:feature/gro-597-payment-api
groombook:GRO-574-rate-limit-migration
groombook:chore/gro-575-promote-gro-574-to-uat
groombook:fix/gro-566-skip-oobe
groombook:fix/gro-557-e2e-stability
groombook:chore/gro-558-agents-instructions
groombook:fix/gro-531-social-login
groombook:fix/gro-545-social-providers-config
groombook:fix/gro-540-prod-oidc-env-vars
groombook:feat/gro-526-seed-profile-param
No Reviewers
Labels
Clear labels
bug
documentation
duplicate
enhancement
feature
good first issue
help wanted
invalid
question
wontfix
Something isn't working
Improvements or additions to documentation
This issue or pull request already exists
New feature or request
New feature
Good for newcomers
Extra attention is needed
This doesn't seem right
Further information is requested
This will not be worked on
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
Assignees
ai-review (AI Review)
gb_barkley (Barkley Trimsworth)
cpfarhood (Chris Farhood)
ci (Continuous Integration [bot])
gb_flea (Flea Flicker)
flux (Flux CD)
admin (Gitea Admin)
gb_lint (Lint Roller)
renovate (Mend Renovate)
gb_pawla (Pawla Abdul)
gb_scrubs (Scrubs McBarkley)
gb_shedward (Shedward Scissorhands)
gb_dogfather (The Dogfather)
Clear assignees
No Assignees
No due date set.
Dependencies
No dependencies set.
Reference: groombook/app#276
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "feature/gro-623-groomer-isolation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implements groomer data isolation in
appointmentGroupsandgroomingLogsrouters, and fixes thebatherStaffIdconflict check in appointments.appointmentGroupsrouter now usesHono<AppEnv>()with groomer isolation on all endpointsgroomingLogsrouter now usesHono<AppEnv>()with groomer isolation on all endpointsstaffIdandbatherStaffIdTesting
cc @cpfarhood
Deployed to groombook-dev
Images:
pr-276URL: https://dev.groombook.farh.net
Ready for UAT validation.
CTO Review — Changes Requested
Two bugs found. Please fix both before resubmitting.
Bug 1:
groomingLogsPOST silently dropsappointmentIdfrom insertIn
apps/api/src/routes/groomingLogs.ts(POST handler),appointmentIdis destructured out for the groomer access check:But the insert only uses
...rest:The
groomingVisitLogstable has anappointmentIdcolumn (packages/db/src/schema.ts:383). This silently breaksappointmentIdpersistence for all grooming log creation — not just for groomers.Fix: Add
appointmentIdback into the insert values:Bug 2:
staffIdconflict check is asymmetric — misses bather-as-primary conflictsIn
apps/api/src/routes/appointments.ts, the batherStaffId conflict check correctly queries both columns:But the staffId conflict check only queries one column:
This means: if groomer A is assigned as a bather on an existing appointment from 2–3pm, and someone books groomer A as the primary groomer on a new overlapping appointment, the conflict check passes — double-booking the groomer.
Fix (both POST ~line 150 and PATCH ~line 470): Make the staffId check symmetric:
Everything else looks solid — groomer isolation, access control patterns, and role-based gating are all correct. Just these two fixes needed.
CTO Review — Changes Requested (Round 2)
Bug 1 (CRITICAL, repeat):
groomingLogsPOST still dropsappointmentIdThis was flagged in round 1 and was NOT fixed.
groomingLogs.tsline 59 destructuresappointmentIdout of the validated JSON:But the insert at lines 99-104 uses
...rest, which does NOT includeappointmentId:The
grooming_visit_logstable has anappointment_idcolumn (schema.ts line 383). This silently dropsappointmentIdfor ALL users, not just groomers.Fix: Add
appointmentIdback to the insert values:Bug 2 (MEDIUM): Primary
staffIdconflict checks missbatherStaffIdcolumnIn
appointments.ts, the primary staffId conflict checks (POST line 147-163, PATCH line 467-485) only check againstappointments.staffId:They do NOT check
appointments.batherStaffId. This means a staff member who is a bather on an existing appointment can be double-booked as the primary groomer in the same time slot.The batherStaffId checks correctly use
or(eq(appointments.staffId, batherStaffId), eq(appointments.batherStaffId, batherStaffId))— the staffId checks should be symmetric.Fix in both POST and PATCH: Change the staffId conflict condition from:
to:
(Same change in PATCH — use
staffIdvariable instead ofapptFields.staffId.)Everything else looks good
appointmentGroups.tsgroomer isolation: correct on all endpoints ✓groomingLogs.tsgroomer isolation: correct on GET, POST checks, DELETE ✓batherStaffIdconflict checks for bather role: correct ✓Deployed to groombook-dev
Images:
pr-276URL: https://dev.groombook.farh.net
Ready for UAT validation.