Implement guard availability slot endpoints (Ticket #20) - #449
Open
Houda135 wants to merge 1 commit into
Open
Conversation
The Guard App (guard_app/src/api/availability.ts) already calls four calendar-slot endpoints that did not exist on the backend, so those requests returned 404. This implements them end to end. - New AvailabilitySlot model (per-date slots: guardId, date, fromTime, toTime, optional recurring). Distinct from the existing Availability model, which is left untouched. - availabilitySlot service + thin controller following the team's controller -> service -> model direction. guardId is always taken from the authenticated user, never the request body. - Routes: POST /slots, GET /slots/my-slots, DELETE /slots/clear-all, DELETE /slots/:id. Literal paths are registered before /slots/:id so they are not captured as an id param. - Input validation (date/time formats, from<to, recurring object, optional startDate/endDate range) with clear 400s; ownership 404s. - 23 Jest tests covering success, validation, unauth and ownership. - Swagger docs for the new endpoints; new audit ACTIONS. Contract confirmed with Krisha Patel (Guard App Lead).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Ticket #20 - Guard Availability Slot Endpoints.
The Guard App (
guard_app/src/api/availability.ts) already calls four calendar-slot endpoints that did not exist on the backend, so every one of those requests returned 404. This PR builds the backend half, end to end.POST /api/v1/availability/slotsGET /api/v1/availability/slots/my-slotsstartDate/endDaterange)DELETE /api/v1/availability/slots/:idDELETE /api/v1/availability/slots/clear-allWhat's included
models/AvailabilitySlot.js- per-date slots (guardId,date,fromTime,toTime, optionalrecurring), many per guard. This is a separate concept from the existingAvailabilitymodel (one unique doc per user,days[]/timeSlots[]/ livestatus), which is left completely untouched.services/availabilitySlot.service.js- validation and ownership scoping.controllers/availabilitySlot.controller.js- thin HTTP layer, following thecontroller → service → modeldirection indocs/system-architecture.md.availability.routes.js.middleware/logger.js.Contract
Confirmed with Krisha Patel (Guard App Lead) before implementation, per Lou's pre-req:
{ message, availability: <slot> }; list returns{ availability: [...] }.dateis"YYYY-MM-DD",fromTime/toTimeare"HH:MM"24-hour./slots/my-slotsand/slots/clear-allare registered before/slots/:idso they aren't captured as an:idparam.Security notes for review
guardIdalways comes fromreq.user, never the request body. The service builds the document from a validated whitelist, so a client posting its ownguardIdcannot write to another guard's account. Covered by a dedicated test.findOneAndDelete({ _id, guardId }). One atomic operation, no time-of-check/time-of-use gap.Decision worth flagging
The ticket plan specified 403 when a slot isn't the caller's. This returns 404 instead, for two reasons:
Happy to switch to 403 if you'd rather stay consistent with the plan.
Testing evidence - live endpoints
Run against the Docker stack on this branch (
docker compose up backend mongodb), authenticated as the seeded guardmia.guard@secureshift.test(Mia Thompson,5ec2f5c3…).Create - 201, returned under
availabilityas agreed with KrishaCreate with
recurring- 201Validation - 400s with actionable messages
List - 200, array under
availabilityDate-range filter - 200, correctly narrowed to one slot
This also demonstrates the route ordering is correct -
/slots/my-slotsis resolved as a literal path, not captured as/slots/:id.Ownership - a forged
guardIdin the body is ignoredThe slot is persisted against the authenticated guard, not the id supplied in the body.
Ownership - deleting another guard's slot returns 404
Auth - no token is rejected
Delete own slot, then clear-all - scoped to the caller
Database check immediately after: Isha slots remaining: 1 | Mia slots remaining: 0 -
clear-allremoved only the authenticated guard's slots.Testing evidence - unit tests
Lint and formatting both clean against the CI commands:
Notes