본문으로 건너뛰기

창고 서비스 (Warehouse Service)

개요

창고 서비스는 창고 관리, 재고 할당, 주문 배송을 위한 재고 추적을 담당합니다. 주문 확정 이벤트를 수신하여 자동으로 가장 가까운 창고에 재고를 할당합니다.

항목내용
언어Java 17
프레임워크Spring Boot 3.2
데이터베이스Aurora PostgreSQL (Global Database)
네임스페이스mall-warehouse
포트8080
헬스체크/actuator/health

아키텍처

API 엔드포인트

메서드경로설명
GET/api/v1/warehouses창고 목록 조회
GET/api/v1/warehouses/{id}창고 상세 조회
POST/api/v1/warehouses/{id}/allocate주문 할당
GET/api/v1/warehouses/{id}/inventory창고 재고 현황 조회

창고 목록 조회

GET /api/v1/warehouses

응답 (200 OK):

[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "서울 물류센터",
"location": "서울특별시 강남구",
"capacity": 10000,
"active": true,
"createdAt": "2024-01-01T00:00:00"
},
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "부산 물류센터",
"location": "부산광역시 해운대구",
"capacity": 8000,
"active": true,
"createdAt": "2024-01-01T00:00:00"
}
]

창고 상세 조회

GET /api/v1/warehouses/{id}

응답 (200 OK):

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "서울 물류센터",
"location": "서울특별시 강남구",
"capacity": 10000,
"active": true,
"createdAt": "2024-01-01T00:00:00"
}

주문 할당

POST /api/v1/warehouses/{id}/allocate

요청:

{
"orderId": "660e8400-e29b-41d4-a716-446655440000"
}

응답 (200 OK):

{
"id": "770e8400-e29b-41d4-a716-446655440000",
"warehouseId": "550e8400-e29b-41d4-a716-446655440000",
"warehouseName": "서울 물류센터",
"orderId": "660e8400-e29b-41d4-a716-446655440000",
"status": "ALLOCATED",
"createdAt": "2024-01-15T10:35:00",
"updatedAt": "2024-01-15T10:35:00"
}

창고 재고 현황 조회

GET /api/v1/warehouses/{id}/inventory

응답 (200 OK):

{
"warehouseId": "550e8400-e29b-41d4-a716-446655440000",
"warehouseName": "서울 물류센터",
"totalCapacity": 10000,
"activeAllocations": 150,
"availableCapacity": 9850
}

데이터 모델

Warehouse 엔티티

@Entity
@Table(name = "warehouses")
public class Warehouse {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@Column(nullable = false)
private String name;

private String location;

@Column(columnDefinition = "INTEGER DEFAULT 0")
private Integer capacity = 0;

@Column(columnDefinition = "BOOLEAN DEFAULT true")
private Boolean active = true;

@Column(name = "created_at")
private LocalDateTime createdAt;
}

Allocation 엔티티

@Entity
@Table(name = "allocations")
public class Allocation {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@ManyToOne
@JoinColumn(name = "warehouse_id")
private Warehouse warehouse;

@Column(name = "order_id", nullable = false)
private UUID orderId;

@Enumerated(EnumType.STRING)
@Column(length = 50)
private AllocationStatus status = AllocationStatus.PENDING;

@Column(name = "created_at")
private LocalDateTime createdAt;

@Column(name = "updated_at")
private LocalDateTime updatedAt;
}

AllocationStatus 열거형

public enum AllocationStatus {
PENDING, // 대기 중
ALLOCATED, // 할당됨
PICKING, // 피킹 중
PACKED, // 포장 완료
SHIPPED // 출고 완료
}

데이터베이스 스키마

CREATE TABLE warehouses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
location VARCHAR(255),
capacity INTEGER DEFAULT 0,
active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE allocations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
warehouse_id UUID REFERENCES warehouses(id),
order_id UUID NOT NULL,
status VARCHAR(50) DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_allocations_warehouse_id ON allocations(warehouse_id);
CREATE INDEX idx_allocations_order_id ON allocations(order_id);
CREATE INDEX idx_allocations_status ON allocations(status);

이벤트 (Kafka)

구독 토픽

토픽명설명
orders.confirmed주문 확정 이벤트 수신하여 자동 할당

orders.confirmed 처리

@KafkaListener(topics = "orders.confirmed", groupId = "warehouse-service")
public void handleOrderConfirmed(Map<String, Object> orderData) {
UUID orderId = UUID.fromString(orderData.get("order_id").toString());
warehouseService.allocateOrderToNearestWarehouse(orderId);
}

수신 페이로드:

{
"event": "order.confirmed",
"order_id": "660e8400-e29b-41d4-a716-446655440000",
"user_id": "user-123",
"total_amount": 687000.00
}

환경 변수

변수명설명기본값
SPRING_DATASOURCE_URLAurora PostgreSQL 연결 URL-
SPRING_DATASOURCE_USERNAMEDB 사용자명-
SPRING_DATASOURCE_PASSWORDDB 비밀번호-
SPRING_KAFKA_BOOTSTRAP_SERVERSKafka 브로커 주소-
SPRING_KAFKA_CONSUMER_GROUP_IDKafka 컨슈머 그룹 IDwarehouse-service
SERVER_PORT서비스 포트8080

서비스 의존성

자동 할당 프로세스

할당 상태 흐름

에러 처리

HTTP 상태 코드에러설명
404WarehouseNotFoundException창고를 찾을 수 없음
400IllegalStateException할당 불가능 상태 (비활성 창고 등)
400InsufficientCapacityException창고 용량 부족