Skip to content

feat: delivery-scoped chat, profile picture cleanup, admin escrow resolution & escrow expiry - #306

Merged
Tybravo merged 2 commits into
SwiftChainn:mainfrom
josephchimebuka:feat/escrow-expiry-resolution-chat-profile-cleanup
Oct 21, 2026
Merged

Tybravo merged 2 commits into
SwiftChainn:mainfrom
josephchimebuka:feat/escrow-expiry-resolution-chat-profile-cleanup

Conversation

@josephchimebuka

Copy link
Copy Markdown
Contributor

Closes #241
Closes #240
Closes #239
Closes #238

Summary

#241 Delivery-scoped socket chat

  • join_room for delivery:<id> rooms now enforces membership (sender, recipient, driver, or admin); denied joins get a chat_error.
  • New message, typing, read_receipt socket events, only accepted from sockets that joined the delivery room and emitted only to that room. Messages carry deliveryId and sender metadata (user id + role); the sender is taken from the authenticated socket, not the payload.
  • ChatMessage now stores delivery, senderRole, readBy (indexed on delivery, createdAt).
  • GET /api/v1/deliveries/:id/messages: paginated history, participants/admins only (Controller -> Service -> Repository).

#240 Profile picture cleanup

  • StorageDriver.delete implemented for local (path-traversal guarded, ENOENT ignored) and S3 (DeleteObjectCommand).
  • Previous file is deleted after a successful replace, on picture delete, and on user (soft) delete.
  • Delete failures are logged and never fail the request.

#239 Admin flagged-escrow resolution

  • GET /api/v1/admin/escrows/flagged?type=disputed|expired|suspicious paginated/sorted via the shared query middleware.
  • PATCH /api/v1/admin/escrows/:id/resolve with resolution: release_to_driver | refund_to_payer | keep_locked and required reason; runs under a Redlock lock, rejects terminal statuses, updates the delivery and writes an AuditLog entry (actor, escrow id, reason).
  • Routes moved to a dedicated router mounted in src/routes/index.ts at /api/v1/admin/escrows behind authenticate + requireRole(admin).

#238 Escrow expiry

  • EXPIRED added to the lock-status enum; expiredAt added next to expiresAt.
  • scanForExpiredEscrows transitions pending/locked escrows past expiresAt to expired, then cancels the delivery and notifies stakeholders through the notification and webhook services (best effort, per escrow).
  • POST /api/v1/admin/escrows/:id/expired/retry with action: refund (re-lock with fresh expiry, delivery back to FUNDED) or cancel (close escrow, delivery CANCELLED); locked and audit-logged.

Notes

  • tsc --noEmit passes for src/; ESLint shows no new errors.

Made with Cursor

@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

@josephchimebuka 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

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