Azure Service Bus — Integration Architecture
Overview
CustomsTUF integrates with third-party logistics platforms (e.g. Qargo) and downstream filing systems (e.g. Descartes) via two Azure Service Bus queues:
| Queue | Direction | Purpose |
|---|---|---|
customstuf-inbound |
→ CustomsTUF | Logistics providers push trip/dossier JSON |
customstuf-outbound |
CustomsTUF → | Generated XMLs ready for SFTP upload |
Flow diagram
flowchart TD
subgraph Third["Third-party logistics (e.g. Qargo)"]
Q["Qargo\n(per rit / trip)"]
end
subgraph ASB_IN["Azure Service Bus — inbound queue\n(customstuf-inbound)"]
MSG_IN["Message\n{ trip_id, dossiers: [...] }"]
end
subgraph CSTUF["CustomsTUF (Azure / Docker)"]
BGW["Background Worker\n(IHostedService)"]
DB["CustomsTUF Database\n(dossiers, declarations)"]
GEN["XML Generator\n(CC015C / IE415B)"]
end
subgraph ASB_OUT["Azure Service Bus — outbound queue\n(customstuf-outbound)"]
MSG_OUT["Message\n{ dossier_id, xml_base64, filename }"]
end
subgraph DESC["Descartes (Azure Function / Logic App)"]
FN["Queue trigger\nfunction"]
SFTP["SFTP Upload\n(customs authority)"]
end
Q -->|"POST JSON per rit\n(1 msg = 1 trip)"| MSG_IN
MSG_IN -->|"peek-lock / complete"| BGW
BGW -->|"create/update dossiers\nper trip"| DB
DB -->|"trigger generation\n(manual or auto)"| GEN
GEN -->|"put XML message"| MSG_OUT
MSG_OUT -->|"triggers"| FN
FN -->|"uploads XML file"| SFTP
Message formats (draft)
Inbound — Qargo trip message
{
"trip_id": "QARGO-2026-001234",
"dossiers": [
{
"ucr": "TUF/2026/001",
"regime": "T1",
"shipper": { "name": "...", "country": "BE" },
"consignee": { "name": "...", "country": "CH" },
"goods": [
{ "hs_code": "84713000", "description": "...", "gross_weight": 125.5 }
]
}
]
}
Outbound — XML ready for SFTP
{
"dossier_id": 42,
"ucr": "TUF/2026/001",
"message_type": "CC015C",
"filename": "SMF_NCTS_CC015C_TUF2026001_20260518.xml",
"xml_base64": "<base64-encoded XML>"
}
Processing logic (background worker)
sequenceDiagram
participant SB as Service Bus<br/>(inbound)
participant BG as Background Worker
participant DB as Database
participant GEN as XML Generator
participant SB2 as Service Bus<br/>(outbound)
BG->>SB: PeekLock message (trip)
SB-->>BG: Message (trip JSON)
loop for each dossier in trip
BG->>DB: Upsert dossier + lines
end
BG->>SB: Complete message
alt auto-generate XML enabled
BG->>GEN: Generate CC015C / IE415B
GEN->>DB: Store generated XML reference
GEN->>SB2: Publish outbound message
end
SB2-->>Descartes: Queue trigger fires
Descartes->>SFTP: Upload XML to customs authority
Notes
- One message = one trip (rit). A trip may contain multiple dossiers; the worker creates one CustomsTUF dossier per entry.
- Peek-lock is used on the inbound queue so that a crash before
Complete()re-queues the message automatically. - XML generation can be manual (user clicks Generate on the dossier page) or automatic (background worker publishes to outbound queue immediately after dossier creation).
- The outbound queue decouples CustomsTUF from Descartes — Descartes can be unavailable without blocking the filing workflow.