Sentra Laundry — Database Design¶
Database dirancang dengan fokus pelacakan status cucian, catatan kondisi barang, integrasi kurir, dan kalkulasi insentif operasional.
4.1 Entity Relationship Diagram (ERD)¶
erDiagram
OUTLETS ||--o{ LAUNDRY_ORDERS : "receives"
CUSTOMERS ||--o{ LAUNDRY_ORDERS : "places"
LAUNDRY_ORDERS ||--o{ LAUNDRY_ORDER_ITEMS : "contains"
LAUNDRY_ORDER_ITEMS ||--o{ ITEM_PHOTOS : "documented_by"
LAUNDRY_ORDER_ITEMS ||--o{ LAUNDRY_TAGS : "identified_by"
LAUNDRY_ORDER_ITEMS ||--o{ OPERATIONAL_QUEUES : "routed_to"
MACHINES ||--o{ OPERATIONAL_QUEUES : "uses"
USERS ||--o{ OPERATIONAL_QUEUES : "processed_by"
LAUNDRY_ORDERS ||--o{ COURIER_DISPATCHES : "shipped_via"
USERS ||--o{ COURIER_DISPATCHES : "delivered_by"
4.2 Skema Tabel DDL (PostgreSQL Dialect)¶
-- 1. Tabel Outlets (Daftar Cabang Laundry)
CREATE TABLE outlets (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
address TEXT,
phone VARCHAR(20),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 2. Tabel Users (Pegawai: Kasir, Operator Cuci, Setrika, QC, Kurir)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100) NOT NULL,
role VARCHAR(30) CHECK (role IN ('OWNER', 'SYSTEM_ADMIN', 'OUTLET_MANAGER', 'CASHIER_FRONTDESK', 'OPERATOR_WASHING', 'OPERATOR_IRONING', 'QC_PACKER', 'COURIER')),
base_salary DECIMAL(15,2) DEFAULT 0.00,
performance_score DECIMAL(3,2) DEFAULT 5.00, -- Nilai rating kepatuhan SLA (1-5)
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 3. Tabel Customers (Membership Program)
CREATE TABLE customers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
phone VARCHAR(20) UNIQUE NOT NULL,
full_name VARCHAR(100) NOT NULL,
email VARCHAR(100),
membership_tier VARCHAR(20) CHECK (membership_tier IN ('REGULAR', 'SILVER', 'GOLD', 'VIP')) DEFAULT 'REGULAR',
loyalty_points INT DEFAULT 0,
subscription_balance DECIMAL(15,2) DEFAULT 0.00, -- Saldo paket kuota kiloan prabayar
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 4. Tabel Laundry Services (Jasa Laundry Kiloan & Satuan Premium)
CREATE TABLE laundry_services (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(150) NOT NULL,
category VARCHAR(50) CHECK (category IN ('KILOAN', 'SATUAN_PREMIUM', 'SHOES_BAG', 'AUTO_DETAILING', 'HOME_CLEANING')),
price_per_unit DECIMAL(15,2) NOT NULL, -- Harga per kg atau per pcs
unit_type VARCHAR(10) CHECK (unit_type IN ('KG', 'PCS', 'METER')), -- Satuan ukur
duration_hours_regular INT NOT NULL DEFAULT 72, -- SLA Regular (3 hari)
duration_hours_express INT NOT NULL DEFAULT 6, -- SLA Express (6 jam)
is_active BOOLEAN DEFAULT TRUE
);
-- 5. Tabel Laundry Orders
CREATE TABLE laundry_orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
outlet_id UUID REFERENCES outlets(id),
customer_id UUID REFERENCES customers(id),
order_number VARCHAR(100) UNIQUE NOT NULL,
service_type VARCHAR(20) CHECK (service_type IN ('REGULAR', 'EXPRESS', 'SUPER_EXPRESS')) DEFAULT 'REGULAR',
subtotal DECIMAL(15,2) NOT NULL,
express_surcharge DECIMAL(15,2) DEFAULT 0.00,
grand_total DECIMAL(15,2) NOT NULL,
payment_status VARCHAR(20) CHECK (payment_status IN ('UNPAID', 'PAID', 'COD_RECONCILE')) DEFAULT 'UNPAID',
order_status VARCHAR(30) CHECK (order_status IN ('RECEIVED', 'PROCESSING', 'QC_COMPLETED', 'SHIPPING', 'READY_FOR_COLLECTION', 'COMPLETED', 'REWASH_HOLD')) DEFAULT 'RECEIVED',
sla_deadline TIMESTAMP WITH TIME ZONE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 6. Tabel Laundry Order Items (Pakaian Konsumen per Order)
CREATE TABLE laundry_order_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
laundry_order_id UUID REFERENCES laundry_orders(id) ON DELETE CASCADE,
service_id UUID REFERENCES laundry_services(id),
weight_kg DECIMAL(6,2), -- Terisi jika kategori KILOAN
qty_pcs INT NOT NULL DEFAULT 1, -- Jumlah fisik pakaian
fabric_notes VARCHAR(255), -- Catatan jenis kain (e.g. Sutra, Katun)
special_treatment TEXT
);
-- 7. Tabel Item Photos (Dokumentasi Kondisi Awal Pakaian Premium/Sepatu)
CREATE TABLE item_photos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_item_id UUID REFERENCES laundry_order_items(id) ON DELETE CASCADE,
photo_url TEXT NOT NULL, -- URL CDN penyimpanan foto noda/kerusakan bawaan
description VARCHAR(255), -- Deskripsi noda/sobekan saat diterima
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- 8. Tabel Machines (Manajemen Mesin Cuci / Pengering)
CREATE TABLE machines (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
outlet_id UUID REFERENCES outlets(id),
name VARCHAR(50) NOT NULL, -- Washer-01, Dryer-02
type VARCHAR(20) CHECK (type IN ('WASHER', 'DRYER', 'DRY_CLEANING_MACHINE')),
capacity_kg DECIMAL(5,2) NOT NULL, -- Kapasitas maksimum beban mesin
status VARCHAR(20) CHECK (status IN ('IDLE', 'RUNNING', 'MAINTENANCE', 'BROKEN')) DEFAULT 'IDLE'
);
-- 9. Tabel Operational Queues (Antrean Kerja Staf BOH)
CREATE TABLE operational_queues (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
order_item_id UUID REFERENCES laundry_order_items(id) ON DELETE CASCADE,
operator_id UUID REFERENCES users(id), -- Staf pelaksana stasiun ini
machine_id UUID REFERENCES machines(id), -- Mesin yang digunakan
station_type VARCHAR(20) CHECK (station_type IN ('WASHING', 'DRYING', 'IRONING', 'QC')),
status VARCHAR(20) CHECK (status IN ('PENDING', 'PROCESSING', 'COMPLETED', 'REWASH')) DEFAULT 'PENDING',
started_at TIMESTAMP WITH TIME ZONE,
completed_at TIMESTAMP WITH TIME ZONE
);
-- 10. Tabel Courier Dispatches (Pengiriman Pickup & Delivery)
CREATE TABLE courier_dispatches (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
laundry_order_id UUID REFERENCES laundry_orders(id),
courier_id UUID REFERENCES users(id),
dispatch_type VARCHAR(20) CHECK (dispatch_type IN ('PICKUP', 'DELIVERY')),
delivery_fee DECIMAL(15,2) DEFAULT 0.00,
google_maps_distance_km DECIMAL(5,2),
status VARCHAR(20) CHECK (status IN ('ASSIGNED', 'PICKING_UP', 'COLLECTED', 'DELIVERING', 'DELIVERED', 'FAILED')) DEFAULT 'ASSIGNED',
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP WITH TIME ZONE
);