System design · LLD design
Amazon Locker System
Functional Req
1.Single locker system
1.There can be multiple size locker
2.Package can be assigned of same size locker , and if not present then try for bigger locker (size matching logic)
3.no locker empty reject the drop with a clear reason (e.g., “no locker available”)
4 During drop-off assign a locker and generate a code
5.System generates a unique pickup code when the courier drops
6.During pickup, Customer enters a code and system verify the code matches assigned code
7.Allow max 3 retry attempts for code entry , -> will send a message (“flagged and locked for staff intervention )
8. If passed, Customer pick up the order , and package will be released from the locker
9.Pickup deadline for 3 days , after that remove from the locker - and locker will be again available for new packages
Non-functional
1.Extensible - Locker assignment strategy can be swapple with other logic
2. Scalable - handle more lockers
3.concurrency - handle concurrency if two courier try to drop off packages at the same instant and both get assigned the same locker?
(but to be honest i don’t think in real world its possible ? how can be two courier assigned at once ?
4.code uniqueness - all code generate will be unique - handle by generating random digits
Functional Requirements
- Support a single locker station with multiple locker sizes.
- On drop-off (given package details — ID, size, customer/order reference), assign a locker of matching size, or next-larger if exact size unavailable.
- If no suitable locker is available, reject the drop-off with a clear reason.
- Generate a unique pickup code upon successful drop-off.
- On pickup, validate the entered code against the package’s assigned code.
- Allow a maximum of 3 failed code-entry attempts; on the 3rd failure, lock the package and flag it for staff intervention.
- On successful validation, release the package and free the locker.
- Enforce a 3-day pickup deadline; if unmet, remove the package and make the locker available again.
Non-Functional Requirements
- Extensibility — locker-assignment strategy should be swappable without modifying core logic.
- Scalability — support adding more lockers/stations without restructuring core logic.
- Concurrency — the system must safely handle concurrent drop-off/pickup requests (e.g., from multiple kiosks or retried API calls) without double-assigning a locker or double-releasing a package.
- Code uniqueness — no two active packages should share a pickup code at the same time, including under concurrent code generation.
Entities
1.LockerSize - SMALL, MEDIUM , LARGE && LOCKERSTATE - AVAILABLE AND OCCUPIED
2. Package -
-packageID
-LockerSize size
-pickupCode
-expiryTime
-numberOfRety - 0 default
new Package(size, pickupcode) -> calc packageID uniqueid and expirytime 3 days from now()
+increseNumberOfRetry() - numberofrety++;
3.Locker
-LockerSize size
-State lockerstatus
-Package currentPackage
+boolean tryFit(package) - handle if free assign the package to currentpackage and status to OCCUPIED and return true else false
+removePackage() - remove the package + status to AVAILABLE
4.LockerStation
-List<Lockers> lockers
+addLocker()
5.LockerAssignmentStrategy
Find the locker for assigning the package
LockerAssignmentStrategy - interface
sizingMatchingStrategy - implement LockerAssignmentStrategy
+ findLocker(package) - synchronous call
-return all with this size and creator then in order from small size
and Call tryFit(package) in Locker
And if no empty left - return with a message “no locker empty left, try after sometime”
6.LockerSerivce
-assignmentStrategy
-list<lockers>
-Set<String> activeCode = ConcurrentHashMap.newKeySet();
// drop a package
+dropPackage(size , packageid)
Lock {
+generateUniqueCode() -> assign to package and add in activeCode
}
+assignLocker(package) ->
//pickup
+pickPackage(lockerID)
-getpackage detail from the lockerid
-input: customer code
-isValideCode() - code matches or not && canPickupPackage() - package expired & numbrofretry < 3
lock{
remove from active code
}
locker.removePackage()
+package.increseNumberOfRetry()
// expiry
+checkIFPackageExpiried()
Lock {
Check all locker which are occupied and check the package in it
And package with expirytime < now()
locker.removePackage() & remove from active code
}
7.LockerStation
// assign which strategy to use
//add lockers in locker station
//call locker service for
- dropPackage
- pickupPAckage
- checkIfPAckageExpiried() - this in some intervals