Skip to content

feat: validate dropoff location on delivery completion - #165

Merged
Tybravo merged 2 commits into
SwiftChainn:mainfrom
obswrld:feat-Fix-token-expiration-edge-cases-causing-location-updates
Aug 30, 2026
Merged

feat: validate dropoff location on delivery completion#165
Tybravo merged 2 commits into
SwiftChainn:mainfrom
obswrld:feat-Fix-token-expiration-edge-cases-causing-location-updates

Conversation

@obswrld

@obswrld obswrld commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

closes #150

Summary

Add a server‑side geofence check that guarantees a driver can only set a delivery’s status to completed when they are physically
at the drop‑off location. The validation pulls the driver’s latest GPS coordinates from the LocationUpdate collection,
calculates the haversine distance to the delivery’s dropoffCoordinates, and rejects the request if the driver is farther than
200 m (0.2 km).
──────

Problem

• The updateDeliveryStatus endpoint allowed any client to mark a delivery as completed regardless of the driver’s actual
location.
• This opened the door for fraudulent “completed” reports (e.g., a driver could claim delivery was finished without delivering
the package).
──────

🛠️ Solution / Changes

File Change
src/controllers/deliveryStatusController.ts Import LocationUpdate model.After loading the Delivery
                                                             | document, query the most recent LocationUpdate for that driver
                                                             | & delivery.Introduce a small haversine‑distance helper
                                                             | (returns kilometers).Define ACCEPTABLE_RADIUS_KM = 0.2 (200
                                                             | m).If nextStatus === 'completed', validate that a recent
                                                             | location exists and that the distance to
                                                             | delivery.dropoffCoordinates ≤ 0.2 km; otherwise return 400 Bad
                                                             | Request with an explanatory message.Fix driver reference to
                                                             | use delivery.driverId (the driver stored on the delivery
                                                             | document).

src/services/authService.ts, | No functional changes – these files were staged automatically
src/sockets/connectionHandler.ts, src/sockets/socket.types.ts | during the commit but remain untouched.
src/models/LocationUpdate.ts (already present) | Utilized for fetching the driver’s latest GPS record; no
| source modifications required.

All modifications respect the existing Controller → Service → Model layered architecture and only use data retrieved from
MongoDB—no hard‑coded or mock values.
──────

Impact

• Security – Prevents fraudulent completion reports; helps enforce proof‑of‑delivery integrity.
• User Experience – Drivers whose device fails to send a location will receive a clear error (No recent driver location
available for validation).
• Performance – A single indexed lookup on LocationUpdate (driverId + deliveryId) and a lightweight distance calculation;
negligible overhead.
──────

Verification / Testing

  1. Positive Path
    • Send PATCH /api/v1/deliveries/:id/status with body { "status": "completed" } while the driver’s last known location (in
    LocationUpdate) is inside the 200 m radius.
    • Expected: 200 OK, delivery status updated to completed.
  2. Negative Path – Too Far
    • Same request, but the driver’s location is > 200 m from dropoffCoordinates.
    • Expected: 400 Bad Request with message like Driver is too far from drop-off location (distance: X.XX km).
  3. Negative Path – No Recent Location
    • No LocationUpdate record for the driver/delivery.
    • Expected: 400 Bad Request with message No recent driver location available for validation.
  4. Other Status Transitions
    • Verify that transitions such as pending → assigned, assigned → picked_up, etc., bypass the proximity check and succeed as
    before.
  5. Run the Full Test Suite
    • npm test (or pnpm test) – all existing tests should still pass.

Add automated unit tests for the new validation logic if the project’s CI requires coverage.
──────

Files Modified

src/controllers/deliveryStatusController.ts
src/services/authService.ts               (no change, staged)
src/sockets/connectionHandler.ts          (no change, staged)
src/sockets/socket.types.ts               (no change, staged)

@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@obswrld Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

- Fix authService.verifyToken to check decoded.userId first
- Store raw JWT token on socket.data during connection handshake
- Add SocketService.validateSocketToken for DB-backed token validation
- Implement setupTokenExpirationCheck in locationHandler:
  - Periodic JWT validation on configurable interval (default 60s)
  - Emit auth_expired event with grace period (default 30s)
  - Handle auth_refresh to accept new JWT without reconnecting
  - Graceful disconnect if token not refreshed in time
- Extend socket.types with AuthExpiredPayload, AuthRefreshPayload, etc.
- Add unit tests for validateSocketToken and token expiration flow
@Tybravo

Tybravo commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

@obswrld Thanks for contributing

@Tybravo
Tybravo merged commit d9b2cdb into SwiftChainn:main Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Add strict validation to prevent 'Completed' status if GPS coordinates do not match drop-off

2 participants