Relay — parcel network
c4
C4 level 2: the containers inside Relay. Open Dispatch to go a level deeper.
/
Fit
SVG
PNG
Relay
SYSTEM BOUNDARY
Core services
DEPLOYMENT BOUNDARY
Uploads scan batches to [REST/JSON over mTLS]
Hands off out-of-area parcels to [HTTPS]
Reads tracking history from [REST/JSON]
Scans parcels with [Bluetooth scanner]
Requests a sequenced route from [gRPC]
Books and cancels via [REST/JSON]
Validates addresses with [HTTPS]
Books shipments in [HTTPS]
Tracks a parcel on [HTTPS]
Creates parcels in [gRPC]
Sends SMS through [HTTPS]
Reads / writes [SQL]
Publishes [Kafka]
Consumes [Kafka]
Consumes [Kafka]
Writes [SQL]
Reads [SQL]
Merchant — Books shipments and watches them until they land
Merchant
[Person]
Books shipments and watches
them until they land
Recipient — Tracks a parcel and reschedules when they will not be in
Recipient
[Person]
Tracks a parcel and
reschedules when they will
not be in
Courier — Scans parcels at every handover and records delivery attempts
Courier
[Person]
Scans parcels at every
handover and records
delivery attempts
Merchant portal — [Next.js] — Booking, labels, invoices and shipment history
Merchant portal
[Container: Next.js]
Booking, labels, invoices and
shipment history
Drill down ↗
Tracking page — [React] — The public page a recipient opens from an SMS. No login.
Tracking page
[Container: React]
The public page a recipient opens
from an SMS. No login.
Courier handheld — [Kotlin / Android] — Scans barcodes offline and syncs when it finds signal
Courier handheld
[Container: Kotlin / Android]
Scans barcodes offline and syncs
when it finds signal
Shipment API — [Go] — Booking, cancellation and the merchant-facing read model
Shipment API
[Container: Go]
Booking, cancellation and the
merchant-facing read model
Drill down ↗
Scan ingest — [Go] — Accepts batched, out-of-order scans from handhelds and makes them idempotent
Scan ingest
[Container: Go]
Accepts batched, out-of-order
scans from handhelds and makes
them idempotent
Dispatch — [Java / Spring] — Owns parcel state and decides which route a parcel joins
Dispatch
[Container: Java / Spring]
Owns parcel state and decides
which route a parcel joins
Drill down ↗
Routing engine — [Python] — Sequences stops for a van under time windows and vehicle capacity
Routing engine
[Container: Python]
Sequences stops for a van under
time windows and vehicle capacity
Notifier — [Node.js] — Sends the SMS and email a recipient actually reads
Notifier
[Container: Node.js]
Sends the SMS and email a
recipient actually reads
Relay DB — [PostgreSQL 15] — Shipments, parcels, routes and every scan ever taken
Relay DB
[Database: PostgreSQL 15]
Shipments, parcels, routes and
every scan ever taken
Parcel events — [Kafka] — parcel.scanned, parcel.delivered, parcel.attempt-failed
Parcel events
[Queue: Kafka]
parcel.scanned, parcel.delivered,
parcel.attempt-failed
Loqate — Address validation and geocoding
Loqate
[System, external]
Address validation and geocoding
Twilio — SMS delivery to recipients
Twilio
[System, external]
SMS delivery to recipients
Partner carriers — Final mile in postcodes Relay does not serve itself
Partner carriers
[System, external]
Final mile in postcodes Relay does
not serve itself
Uploads scan batches to [REST/JSON over mTLS]
Uploads scan batches to
[REST/JSON over mTLS]
Hands off out-of-area parcels to [HTTPS]
Hands off out-of-area parcels to
[HTTPS]
Reads tracking history from [REST/JSON]
Reads tracking history from
[REST/JSON]
Scans parcels with [Bluetooth scanner]
Scans parcels with
[Bluetooth scanner]
Requests a sequenced route from [gRPC]
Requests a sequenced route from
[gRPC]
Books and cancels via [REST/JSON]
Books and cancels via
[REST/JSON]
Validates addresses with [HTTPS]
Validates addresses with
[HTTPS]
Books shipments in [HTTPS]
Books shipments in
[HTTPS]
Tracks a parcel on [HTTPS]
Tracks a parcel on
[HTTPS]
Creates parcels in [gRPC]
Creates parcels in
[gRPC]
Sends SMS through [HTTPS]
Sends SMS through
[HTTPS]
Reads / writes [SQL]
Reads / writes
[SQL]
Publishes [Kafka]
Publishes
[Kafka]
Consumes [Kafka]
Consumes
[Kafka]
Consumes [Kafka]
Consumes
[Kafka]
Writes [SQL]
Writes
[SQL]
Reads [SQL]
Reads
[SQL]
drag to pan · wheel to zoom · click a node · Esc clears
Ownership
Merchant-facing: platform team
Dispatch, routing and scans: network team
Handheld app: field systems team
Watch out
Scan ingest must stay available when depots are busiest; it is the only write path for parcel movement
Handhelds go offline for hours, so scans arrive late and out of order