Skip to main content

Shipping Service

Overview​

The Shipping Service handles shipment creation, tracking, and status management for ordered products. It integrates with major Korean carriers (CJ Logistics, Hanjin Express, Lotte Global Logistics) to provide real-time shipment tracking.

ItemValue
LanguagePython 3.11
FrameworkFastAPI
DatabaseAurora PostgreSQL
Namespacemall-services
Port8000
Health CheckGET /health

Architecture​

API Endpoints​

Shipping API​

MethodPathDescription
GET/api/v1/shipments/{order_id}Get shipment by order
POST/api/v1/shipmentsCreate shipment
PUT/api/v1/shipments/{shipment_id}/statusUpdate shipment status
GET/api/v1/shipments/{shipment_id}/trackingGet tracking history

Request/Response Examples​

Get Shipment by Order​

Request:

GET /api/v1/shipments/order_001

Response:

{
"id": "ship_001",
"order_id": "order_001",
"user_id": "user_001",
"shipping_address": "123 Teheran-ro, Gangnam-gu, Seoul, Apt 456",
"carrier": "CJ Logistics",
"tracking_number": "1234567890123",
"status": "IN_TRANSIT",
"tracking_history": [
{
"status": "PENDING",
"location": null,
"description": "Preparing for shipment",
"timestamp": "2024-01-15T10:00:00Z"
},
{
"status": "PICKED_UP",
"location": "Seoul Songpa Distribution Center",
"description": "Package picked up",
"timestamp": "2024-01-15T14:00:00Z"
},
{
"status": "IN_TRANSIT",
"location": "Daejeon Hub Terminal",
"description": "In transit",
"timestamp": "2024-01-16T08:00:00Z"
}
],
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-16T08:00:00Z"
}

Create Shipment​

Request:

POST /api/v1/shipments
Content-Type: application/json

{
"order_id": "order_002",
"user_id": "user_002",
"shipping_address": "456 Centum-ro, Haeundae-gu, Busan",
"carrier": "Hanjin Express"
}

Response (201 Created):

{
"id": "ship_002",
"order_id": "order_002",
"user_id": "user_002",
"shipping_address": "456 Centum-ro, Haeundae-gu, Busan",
"carrier": "Hanjin Express",
"tracking_number": "9876543210987",
"status": "PENDING",
"tracking_history": [
{
"status": "PENDING",
"location": null,
"description": "Preparing for shipment",
"timestamp": "2024-01-16T09:00:00Z"
}
],
"created_at": "2024-01-16T09:00:00Z",
"updated_at": "2024-01-16T09:00:00Z"
}

Update Shipment Status​

Request:

PUT /api/v1/shipments/ship_002/status
Content-Type: application/json

{
"status": "OUT_FOR_DELIVERY",
"location": "Busan Haeundae Delivery Center",
"description": "Out for delivery"
}

Response:

{
"id": "ship_002",
"order_id": "order_002",
"user_id": "user_002",
"shipping_address": "456 Centum-ro, Haeundae-gu, Busan",
"carrier": "Hanjin Express",
"tracking_number": "9876543210987",
"status": "OUT_FOR_DELIVERY",
"tracking_history": [
{
"status": "PENDING",
"location": null,
"description": "Preparing for shipment",
"timestamp": "2024-01-16T09:00:00Z"
},
{
"status": "OUT_FOR_DELIVERY",
"location": "Busan Haeundae Delivery Center",
"description": "Out for delivery",
"timestamp": "2024-01-17T08:30:00Z"
}
],
"created_at": "2024-01-16T09:00:00Z",
"updated_at": "2024-01-17T08:30:00Z"
}

Get Tracking History​

Request:

GET /api/v1/shipments/ship_001/tracking

Response:

[
{
"status": "PENDING",
"location": null,
"description": "Preparing for shipment",
"timestamp": "2024-01-15T10:00:00Z"
},
{
"status": "PICKED_UP",
"location": "Seoul Songpa Distribution Center",
"description": "Package picked up",
"timestamp": "2024-01-15T14:00:00Z"
},
{
"status": "IN_TRANSIT",
"location": "Daejeon Hub Terminal",
"description": "In transit",
"timestamp": "2024-01-16T08:00:00Z"
},
{
"status": "DELIVERED",
"location": "Seoul Gangnam-gu",
"description": "Delivered",
"timestamp": "2024-01-16T14:00:00Z"
}
]

Data Models​

ShipmentStatus (Enum)​

class ShipmentStatus(str, Enum):
PENDING = "PENDING" # Preparing for shipment
PICKED_UP = "PICKED_UP" # Package picked up
IN_TRANSIT = "IN_TRANSIT" # In transit
OUT_FOR_DELIVERY = "OUT_FOR_DELIVERY" # Out for delivery
DELIVERED = "DELIVERED" # Delivered

Shipment​

class Shipment(BaseModel):
id: Optional[str] = None
order_id: str
user_id: str
shipping_address: str
carrier: Optional[str] = None
tracking_number: Optional[str] = None
status: ShipmentStatus = ShipmentStatus.PENDING
tracking_history: list[TrackingEvent] = []
created_at: datetime
updated_at: datetime

TrackingEvent​

class TrackingEvent(BaseModel):
status: ShipmentStatus
location: Optional[str] = None
description: Optional[str] = None
timestamp: datetime

ShipmentCreate​

class ShipmentCreate(BaseModel):
order_id: str
user_id: str
shipping_address: str
carrier: Optional[str] = None

PostgreSQL Table Schema​

CREATE TABLE shipments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_id VARCHAR(50) NOT NULL UNIQUE,
user_id VARCHAR(50) NOT NULL,
shipping_address TEXT NOT NULL,
carrier VARCHAR(50),
tracking_number VARCHAR(50),
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE TABLE tracking_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
shipment_id UUID REFERENCES shipments(id),
status VARCHAR(20) NOT NULL,
location VARCHAR(200),
description TEXT,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_shipments_order_id ON shipments(order_id);
CREATE INDEX idx_shipments_user_id ON shipments(user_id);
CREATE INDEX idx_tracking_events_shipment_id ON tracking_events(shipment_id);

Events (Kafka)​

Subscribed Topics​

TopicEventDescription
orders.confirmedOrder confirmedTriggers shipment creation after inventory secured

Published Topics​

TopicEventDescription
shipping.createdShipment createdPublished when shipment is created
shipping.status-updatedStatus changedPublished when shipment status changes
shipping.deliveredDeliveredPublished when delivery is complete

Event Payload Examples​

orders.confirmed (subscribed):

{
"event_type": "order.confirmed",
"order_id": "order_001",
"user_id": "user_001",
"shipping_address": "123 Teheran-ro, Gangnam-gu, Seoul",
"items": [
{"product_id": "prod_001", "quantity": 2}
],
"timestamp": "2024-01-15T10:00:00Z"
}

shipping.status-updated (published):

{
"event_type": "shipping.status-updated",
"shipment_id": "ship_001",
"order_id": "order_001",
"user_id": "user_001",
"status": "OUT_FOR_DELIVERY",
"carrier": "CJ Logistics",
"tracking_number": "1234567890123",
"timestamp": "2024-01-16T08:30:00Z"
}

Environment Variables​

VariableDescriptionDefault
SERVICE_NAMEService nameshipping
PORTService port8080
AWS_REGIONAWS regionus-east-1
REGION_ROLERegion role (PRIMARY/SECONDARY)PRIMARY
DB_HOSTAurora PostgreSQL hostlocalhost
DB_PORTAurora PostgreSQL port5432
DB_NAMEDatabase nameshipping
DB_USERDatabase usermall
DB_PASSWORDDatabase password-
KAFKA_BROKERSKafka broker addresslocalhost:9092
LOG_LEVELLog levelinfo

Service Dependencies​

Services It Depends On​

  • Aurora PostgreSQL: Shipment data storage
  • MSK Kafka: Event publishing/subscription
  • Order Service: Receives orders.confirmed events

Services That Depend On This​

  • Notification Service: Shipping status notifications
  • Analytics Service: Shipping dashboard
  • Order Service: Order status update on delivery completion

Carrier Integration​

Supported Carriers​

CarrierCodeAPI Integration
CJ LogisticsCJReal-time tracking
Hanjin ExpressHANJINReal-time tracking
Lotte Global LogisticsLOTTEReal-time tracking

Status Mapping​

StatusCJ LogisticsHanjin ExpressLotte Global
PENDINGReceivedOrder ReceivedReceived
PICKED_UPPicked UpPackage Picked UpCollection
IN_TRANSITIn TransitIn TransitLinehaul
OUT_FOR_DELIVERYOut for DeliveryOut for DeliveryOut for Delivery
DELIVEREDDeliveredDeliveredDelivered