🛠️ Đặc tả Kiến Trúc APIs & Sơ đồ Tuần tự
Giải pháp quản lý hành trình Pallet được vận hành theo mô hình Clean Architecture & Domain-Driven Design (DDD) trong hệ thống Kingston MES, khởi đầu từ màn hình quản lý Nhu Cầu Sản Xuất (Demand Console):
sequenceDiagram
actor Planner as Kế hoạch (Planner)
actor Leader as Tổ trưởng sản xuất
participant API as Web API Server
participant DB as Database (Postgres)
Planner->>API: 1. Truy vấn Nhu Cầu Gỗ (GET /api/production-demands)
API->>DB: Query các Component có Lệnh sản xuất duyệt (WorkOrder)
API-->>Planner: Trả về danh sách Cụm & Chi tiết chưa tạo phiếu
Planner->>API: 2. Tạo phiếu hành trình tùy biến (POST /api/pallet-tickets/generate)
API->>DB: Lưu các PalletTicket & PalletStep phân loại rõ chốt máy và kho đệm
API-->>Planner: In phiếu thành công
Leader->>API: 3. Xem danh sách phiếu (GET /api/pallet-tickets?status=ACTIVE)
API->>DB: Lấy danh sách phiếu hành trình đang lưu thông (WIP)
API-->>Leader: Hiển thị bảng danh sách các phiếu trong xưởng
Leader->>API: 4. Xem chi tiết tiến trình phiếu (GET /api/pallet-tickets/{id}/steps)
API->>DB: Truy vấn lịch sử check-in các chốt công đoạn & kho đệm của phiếu
API-->>Leader: Trả về quy trình trong xưởng (vertical timeline node) kèm OK/NG, mốc thời gian
💾 Sơ Đồ Thực Thể Cơ Sở Dữ Liệu (Prisma ORM)
Trường dữ liệu `isWarehouseStep` (boolean) trong bảng `PalletStep` đóng vai trò phân loại hành vi kiểm soát chéo (Double-check) tại kho đệm:
model Product {
id String @id @default(uuid()) @map("id")
code String @unique @map("code")
name String @map("name")
createdAt DateTime @default(now()) @map("created_at")
components Component[]
workOrders WorkOrder[]
@@map("products")
}
model Component {
id String @id @default(uuid()) @map("id")
productId String @map("product_id")
parentId String? @map("parent_id") // NULL: Cụm | NOT NULL: Chi tiết con
code String @map("code") // Ví dụ: '1' cho Cụm, '1.4' cho Chi tiết
name String @map("name")
specification String? @map("specification")
unit String @default("Cái") @map("unit")
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
parent Component? @relation("BOMHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
children Component[] @relation("BOMHierarchy")
pallets PalletTicket[]
@@unique([productId, code])
@@map("components")
}
model WorkOrder {
id String @id @default(uuid()) @map("id")
woNumber String @unique @map("wo_number")
productId String @map("product_id")
quantity Int @map("quantity")
status String @default("RELEASED") @map("status")
product Product @relation(fields: [productId], references: [id])
pallets PalletTicket[]
@@map("work_orders")
}
model PalletTicket {
id String @id @default(uuid()) @map("id")
palletNumber String @unique @map("pallet_number")
workOrderId String @map("work_order_id")
componentId String @map("component_id")
quantity Int @map("quantity")
status String @default("PLANNED") @map("status")
qrCode String @unique @map("qr_code")
workOrder WorkOrder @relation(fields: [workOrderId], references: [id], onDelete: Cascade)
component Component @relation(fields: [componentId], references: [id])
steps PalletStep[]
@@map("pallet_tickets")
}
model PalletStep {
id String @id @default(uuid()) @map("id")
palletId String @map("pallet_id")
stepOrder Int @map("step_order")
operationName String @map("operation_name")
workshopCode String @map("workshop_code")
isWarehouseStep Boolean @default(false) @map("is_warehouse_step") // TRUE: Chốt Kho | FALSE: Trạm Máy
status String @default("PENDING") @map("status")
quantityOk Int @default(0) @map("quantity_ok")
quantityError Int @default(0) @map("quantity_error")
pallet PalletTicket @relation(fields: [palletId], references: [id], onDelete: Cascade)
@@unique([palletId, stepOrder])
@@map("pallet_steps")
}
Mã nguồn PostgreSQL DDL hoàn chỉnh có thể tìm thấy trong tệp tin: db_schema.sql