Background
The Inbound Yard team at a large online retailer lets carriers book a dock door before their trucks arrive. The booking service picks a door, blocks it for as long as unloading takes, and shows the yard the day's schedule. Since the last release, trucks that arrive right after another one are sent to a different door even though theirs is free, and bookings with nonsense data (no carrier, zero pallets) are accepted.
How the system works
Doors
The yard has doors 1–4 (DRY) and 5–6 (REEFER, with power for refrigerated trailers). GET /api/doors lists them, lowest number first.
Times and length
- Start times are
HH:MMon a half hour (:00or:30), from00:00to23:30. Anything else isINVALID_TIME. - Unloading takes one 30-minute slot per started 10 pallets: 1–10 pallets → 30 min, 11–20 → 60 min, ..., 31–40 → 120 min.
- A booking covers the half-open interval
[start, end). Two bookings on the same door overlap only if they share a minute: one ending at 09:00 and another starting at 09:00 don't overlap, so they can use the same door. - The yard is open 06:00–22:00: a booking must start at 06:00 or later and end at 22:00 or earlier (
OUTSIDE_HOURSotherwise).
Choosing a door
- Refrigerated loads need a
REEFERdoor; dry loads useDRYdoors only (reefer doors are kept free for cold loads). - With a requested door: it must exist (
404 NOT_FOUND), be the right type (409 WRONG_DOOR_TYPE) and be free for the whole booking on that day (409 DOOR_TAKEN). - Without one: the yard picks the lowest-numbered door of the right type that's free for the whole booking; if there's none,
409 NO_DOOR_AVAILABLE. - Bookings on other days never block each other.
API
| Method and path | Body / parameters | Success |
|---|---|---|
POST /api/appointments | {carrier, date, start, pallets, refrigerated, door} | 201 appointment |
GET /api/appointments?date=YYYY-MM-DD | 200 the day's appointments, by start time then door | |
DELETE /api/appointments/{id} | 204 | |
GET /api/doors | 200 doors |
carriermust not be blank,dateandstartare required,palletsis 1 to 40,refrigerateddefaults to false anddooris optional. A body that breaks these rules is rejected with400 INVALID_REQUESTbefore any booking logic runs.- An appointment is
{id, carrier, date, door, start, end, pallets, refrigerated}, with times asHH:MM. Ids areAPT-1,APT-2, ... - Deleting an unknown id is
404 NOT_FOUND.
Errors
Errors return {"error": "<CODE>", "message": "..."}: 400 for INVALID_REQUEST and INVALID_TIME; 404 for NOT_FOUND; 409 for OUTSIDE_HOURS, WRONG_DOOR_TYPE, DOOR_TAKEN and NO_DOOR_AVAILABLE.
Project structure
src/main/java/com/bugnik/dock/
DockApplication.java Spring Boot entry point
model/ Door, DoorType, Appointment
repository/ in-memory DoorRepository and AppointmentRepository
service/DockService.java booking rules (door choice, hours, cancel, schedule)
service/DockException.java business errors (status + code)
util/TimeSlots.java time parsing/formatting, slots per pallets, overlap check
web/ DockController, BookRequest, AppointmentView, ApiError, ApiExceptionHandler
src/test/java/com/bugnik/dock/ unit and MockMvc tests
Your task
The yard team has reported problems since the last release:
- The project no longer builds.
- A truck booked to start exactly when the previous one on a door finishes is sent to another door (or refused when the yard is busy).
- Bookings with zero pallets or no carrier name are accepted instead of being rejected.
Find and fix the defects so that all tests pass.
- Do not modify
src/test/orpom.xml. - Keep your changes minimal. Fix the defects; don't rewrite modules.
- Additional hidden tests check the behaviour described in this README.