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