Shipment tracking and NDR
Three ways a scan enters the system:
| Path | Entry | Job or event |
|---|---|---|
| Poll | ShipmentTrackingScheduler 0 */3 * * * | poll-shipment-tracking |
| Manual | ShipmentController | refresh-shipment-tracking |
| Webhook | Shiprocket, Shipway, iThink, and other handlers that call WebhookQueue | webhook_queue job *, 8 attempts, exponential 5s, concurrency 10 |
shipment.status.changed is not an outbox event. Listeners must be loaded in the same process as the emitter. Webhook processing runs on the worker, so worker-loaded listeners see it. An API-only listener would not.
NDR (ndr.service.ts) writes NdrEventType rows in a transaction.
Idempotency
Unknown. A webhook and the 3-hour poller might apply one scan twice. That depends on a unique key on tracking events, which was not verified.
Failure
Webhook queue retries when the processor throws. A catch that returns normally does not. Carrier modules often catch and update local state. Read the specific controller before you claim the signature was checked. Shopify and WhatsApp verification were specifically noted. Courier webhooks need a per-controller check. See Couriers.