Shipping Service

shipping-service is a Quarkus service that owns shipping zone configuration, rate calculation, carrier integration, shipment creation, and tracking for ShopSTAR3. Storage is PostgreSQL with store_id as a discriminator column for multi-tenant isolation. Carrier API credentials are stored in Vault — they are never written to the database.

Carrier Abstraction#

All live-rate carrier integrations implement a common CarrierAdapter interface. This decouples the rate calculation and shipment creation flows from any specific carrier.

interface CarrierAdapter {
    List<RateOption>  getRates(RateRequest request);
    ShipmentResult    createShipment(ShipmentRequest request);
    LabelResult       fetchLabel(String providerShipmentId);
    TrackingResult    getTracking(String trackingNumber);
}

Built-in Adapters#

AdapterNotes
FedExAdapterLive rates + label generation via FedEx Web Services
DhlAdapterLive rates + label generation via DHL Express API
UpsAdapterLive rates + label generation via UPS Developer API
AusPostAdapterLive rates + label generation via Australia Post eParcel API

Adding a new carrier requires only a new class implementing CarrierAdapter and the corresponding Vault entries for its credentials.

Rate Engine#

The rate engine is hybrid. Each shipping zone can be served by the built-in rules engine, a live carrier adapter, or both. The store admin configures this per zone.

Built-in Rate Types#

TypeBehaviour
FLATFixed price regardless of weight or order value
WEIGHT_BASEDPrice derived from total shipment weight within configured bands
VALUE_BASEDPrice derived from order total within configured bands
FREE_THRESHOLDZero charge when order total meets a minimum value

Zones#

A shipping zone groups destination regions (country, state, postal-code pattern). A zone matches a destination if any of its regions matches. Overlapping zones are resolved by specificity — more specific region patterns take precedence.

Data Model#

Core tables#

shipping_zoneszone_id UUID PK, store_id, name.

shipping_zone_regionsregion_id UUID PK, zone_id FK, country_code CHAR(2), state_code (nullable), postal_pattern (nullable, supports wildcards).

carrier_configsconfig_id UUID PK, store_id, carrier_type (FEDEX / DHL / UPS / AUSPOST), display_name, is_active, settings JSONB (non-sensitive: enabled service types, weight unit).

shipping_ratesrate_id UUID PK, zone_id FK, store_id, name, rate_type ENUM, base_amount, currency, min_weight, max_weight, min_value, max_value, position.

Shipments#

shipmentsshipment_id UUID PK, store_id, order_id, carrier_type, carrier_config_id FK (nullable for rules-based), provider_shipment_id, tracking_number, label_url (object storage reference), status ENUM (PENDING / LABEL_CREATED / SHIPPED / IN_TRANSIT / OUT_FOR_DELIVERY / DELIVERED / FAILED / RETURNED), estimated_delivery, shipped_at, delivered_at.

shipment_itemsitem_id UUID PK, shipment_id FK, order_item_id, quantity.

Checkout Integration#

checkout-service calls GetAvailableRates before the shipping selection step. The call is stateless — no shipment record is created at this point. The customer’s selected rate is stored on the order by order-service and passed back to shipping-service when CreateShipment is called post-order.

checkout-service → GetAvailableRates(storeId, shippingAddress, lineItems[weight])
→ rates[{ rateId, name, carrier, amount, currency, estimatedDays }]

Fulfillment Flow#

Triggered when order-service publishes order.fulfillment_started (staff initiates fulfillment in admin).

  1. shipping-service resolves the selected rate from the order
  2. For carrier-based rates: CarrierAdapter.createShipment()CarrierAdapter.fetchLabel() → label stored in object storage
  3. Shipment record created with tracking number and label URL
  4. shipment.created published to Kafka

A scheduled polling job checks active in-transit shipments against carrier tracking APIs and publishes shipment.tracking.updated for each status change.

gRPC Interface#

MethodCallerPurpose
GetAvailableRates(RatesRequest)checkout-serviceReturn available rate options for a cart and destination
CreateShipment(ShipmentRequest)order-serviceCreate shipment record and generate label
GetShipmentStatus(ShipmentIdRequest)order-serviceReturn current shipment status and tracking

Kafka Topics#

Consumed#

TopicAction
order.fulfillment_startedTrigger shipment creation and label generation

Published#

TopicPayload
shipment.createdshipmentId, orderId, storeId, trackingNumber, carrier
shipment.shippedshipmentId, orderId, storeId, shippedAt
shipment.tracking.updatedshipmentId, orderId, storeId, status, location, updatedAt
shipment.deliveredshipmentId, orderId, storeId, deliveredAt

Vault Configuration#

Key pathPurpose
ss3/kv/shipping-service/db.urlPostgreSQL JDBC URL
ss3/kv/shipping-service/db.usernameDatabase username
ss3/kv/shipping-service/db.passwordDatabase password
ss3/kv/shipping-service/fedex.api-keyFedEx API key
ss3/kv/shipping-service/fedex.account-numberFedEx account number
ss3/kv/shipping-service/dhl.api-keyDHL Express API key
ss3/kv/shipping-service/ups.client-idUPS OAuth client ID
ss3/kv/shipping-service/ups.client-secretUPS OAuth client secret
ss3/kv/shipping-service/auspost.api-keyAustralia Post eParcel API key
ss3/kv/shared/Shared Kafka bootstrap and OTel config