Enterprise-Grade RESTful API untuk otomasi tata kelola pengadaan barang/jasa (End-to-End Procurement Lifecycle), dirancang dengan standar keandalan tinggi, Segregation of Duties (SoD), Finite State Machine (FSM), Pessimistic Locking untuk pencegahan race condition, serta Audit Trail yang immutable.
Dalam ekosistem korporasi skala besar, BUMN, dan BUMD, proses pengadaan barang dan jasa (procurement) merupakan lini operasi krusial yang menuntut transparansi mutlak, akuntabilitas audit, pencegahan fraud, dan efisiensi anggaran.
Repository ini menyajikan solusi backend modern yang mengabstraksi seluruh siklus pengadaan:
- Perencanaan Kebutuhan (Requisition) oleh unit kerja/divisi.
- Pemeriksaan Stok Real-time (Warehouse Inventory Check) dengan mekanisme concurrency lock.
- Persetujuan Bertingkat (Multi-Stage Approval Hierarchy) oleh manajemen.
- Penerbitan Kontrak / Purchase Order (PO) ke mitra rekanan (vendor).
- Penerimaan Logistik & Verifikasi (Delivery & Fulfillment).
- Pelaporan Eksekutif & Analisis Lead Time (Business Intelligence).
Sistem ini dirancang untuk memenuhi standar kepatuhan regulasi, skalabilitas perangkat lunak tingkat korporasi, serta prinsip Good Corporate Governance (GCG) lintas sektor industri:
| Domain Industri | Kebutuhan Utama Tata Kelola | Solusi Teknis dalam Arsitektur Ini |
|---|---|---|
| Mission-Critical & Regulated Infrastructure (Aviation, Energy, Transportation) | Menuntut kepatuhan audit ketat, zero-tolerance terhadap manipulasi pengadaan suku cadang vital, serta alur otorisasi multi-level yang tidak dapat di-bypass. | β’ Immutable Audit Trail: Setiap perubahan status mencatat identitas aktor, stempel waktu, IP address, dan User-Agent tanpa izin edit/hapus. β’ Strict Finite State Machine: Menjamin alur persetujuan berjalan deterministik sesuai SOP. β’ Chronological Serial Numbering: Generator kode otomatis REQ-YYYYMMDD-XXXX dan PO-YYYYMMDD-XXXX. |
| Enterprise IT & Managed Services (Systems Integration, Cloud & Data Center) | Membutuhkan arsitektur bersih, concurrency safe, pencegahan race condition saat transaksi simultan tinggi, dan kemudahan integrasi API. | β’ Service Layer Architecture: Pemisahan jelas antara HTTP Transport, Form Request Validation, dan Business Domain. β’ Pessimistic Concurrency Control: Penerapan SELECT ... FOR UPDATE dan transaksi atomik DB::transaction pada mutasi inventaris.β’ UUIDv4 Identity: Melindungi sistem dari kerentanan ID Enumeration / IDOR. β’ High-Performance Aggregation: Kueri analitik berbasis SQL native untuk metrik performa real-time. |
| Public Utilities & Regional Logistics (Water Utilities, Municipal Asset Procurement) | Membutuhkan transparansi pengelolaan anggaran publik, pemantauan batas stok material operasional, dan evaluasi ketepatan waktu vendor. | β’ Inventory Threshold Alerts: Monitoring kuantitas stok gudang dengan minimum stock alert untuk mencegah keterlambatan suplai material. β’ Vendor Management & Lifecycle: Standardisasi katalog mitra rekanan terverifikasi. β’ Procurement Lead Time Analytics: Menghitung metrik SLA rata-rata, tercepat, dan terlama dari pengajuan hingga barang tiba di gudang. |
Aplikasi mengadopsi prinsip Clean Architecture dan Domain Separation berbasis Service Layer:
procurement-api/
βββ app/
β βββ Exceptions/
β β βββ BussinessException.php # Domain Exception untuk pelanggaran aturan bisnis (HTTP 422)
β βββ Helpers/
β β βββ GeneratePoNumber.php # Generator nomor PO terurut otomatis (PO-YYYYMMDD-XXXX)
β β βββ GenerateReqNumber.php # Generator nomor Request terurut otomatis (REQ-YYYYMMDD-XXXX)
β β βββ ResponseFormatter.php # Standarisasi JSON envelope (meta: code, status, message; result)
β βββ Http/
β β βββ Controllers/API/ # Transport Layer (Handling HTTP Request, delegasi ke Service)
β β β βββ AuthController.php
β β β βββ DepartmentController.php
β β β βββ ProcurementController.php
β β β βββ ReportController.php
β β β βββ RequestController.php
β β β βββ StockController.php
β β β βββ UserController.php
β β β βββ VendorController.php
β β βββ Middleware/
β β β βββ RoleMiddleware.php # Granular Role-Based Access Guard
β β βββ Requests/ # Validation Layer (Type casting & custom validation rules)
β βββ Models/ # Data Layer (Eloquent ORM, FSM definition, UUID, SoftDeletes)
β β βββ Approval.php
β β βββ Department.php
β β βββ ProcurementOrder.php
β β βββ ProcurementRequest.php
β β βββ RequestItem.php
β β βββ StatusHistory.php # Immutable Audit Model (delete & update di-override exception)
β β βββ Stock.php
β β βββ User.php
β β βββ Vendor.php
β βββ Services/ # Business Logic Layer (Transaksi database, State validation)
β βββ AuthService.php
β βββ ProcureService.php
β βββ ReportService.php
β βββ RequestService.php
β βββ StockService.php
βββ database/
β βββ migrations/ # DDL Skema Relasional, Foreign Key Constraints & Multi-column Indexing
β βββ seeders/ # Seed data multi-divisi dan multi-role untuk simulasi instan
βββ routes/
βββ api.php # Routing API v1 dengan pengelompokan middleware Sanctum & Role
Sistem pengadaan menerapkan State Machine deterministik untuk menjamin tidak ada satupun pesanan yang melompati tahapan audit.
stateDiagram-v2
[*] --> DRAFT : Employee Create Request
DRAFT --> SUBMITTED : Employee Submit Request
DRAFT --> DELETED : Soft Delete (Pembuat / Admin)
SUBMITTED --> APPROVED : Manager / Admin Approve
SUBMITTED --> REJECTED : Manager / Admin Reject (Notes Wajib)
APPROVED --> IN_PROCUREMENT : Purchasing / Admin Assign Vendor & PO
APPROVED --> COMPLETED : Direct In-Stock Fulfillment
IN_PROCUREMENT --> COMPLETED : PO Delivered & Warehouse Verified
REJECTED --> [*]
COMPLETED --> [*]
DELETED --> [*]
sequenceDiagram
autonumber
actor EMP as Staff / Requester (Employee)
actor MGR as Kepala Divisi (Manager)
actor PUR as Tim Pengadaan (Purchasing)
actor WRH as Logistik / Gudang (Warehouse)
participant API as Procurement Engine (API / Services)
participant DB as Relational DB & Audit Log
EMP->>API: POST /api/v1/requests (Draft item & estimasi)
API->>DB: Insert requests & request_items (Status: DRAFT)
API-->>EMP: Request Created (REQ-YYYYMMDD-0001)
EMP->>API: PUT /api/v1/requests/{id}/submit
API->>DB: Update Status SUBMITTED + Record StatusHistory
API-->>EMP: Request Submitted for Review
MGR->>API: PUT /api/v1/requests/{id}/approve
API->>DB: Insert Approval record + Status APPROVED + Audit Log
API-->>MGR: Request Approved
PUR->>API: PUT /api/v1/requests/{id}/procure (Vendor, Total, Delivery Date)
API->>DB: Create ProcurementOrder (PO-YYYYMMDD-0001) + Status IN_PROCUREMENT
API-->>PUR: PO Issued to Vendor
WRH->>API: POST /api/v1/stocks/check (Pessimistic Lock & Verification)
API->>DB: Lock row FOR UPDATE, check & deduct inventory
PUR->>API: PUT /api/v1/procures/{id}/deliver
API->>DB: Update PO DELIVERED & Request COMPLETED + Audit Log
API-->>PUR: Delivery Recorded & Closed
Sistem membagi operasional menjadi 5 peran spesifik demi menegakkan prinsip Segregation of Duties (SoD):
| Modul & Fungsionalitas | employee |
manager |
purchasing |
warehouse |
admin |
|---|---|---|---|---|---|
Autentikasi & Profile (/auth/*) |
β | β | β | β | β |
| Buat & Edit Draft Request Sendiri | β | β | β | β | β |
| Submit Request Milik Sendiri | β | β | β | β | β |
| Melihat Daftar Pengadaan (Scope Filter) | Milik Sendiri | Semua Divisi | Semua Divisi | Semua Divisi | Semua Divisi |
| Approve / Reject Permohonan Pengadaan | β | β | β | β | β |
Penerbitan PO & Assign Vendor (procure) |
β | β | β | β | β |
Penyelesaian PO (deliver & complete) |
β | β | β | β | β |
Cek Ketersediaan Stok (lockForUpdate) |
β | β | β | β | β |
| Input / Update Master Stok Gudang | β | β | β | β | β |
| Kelola Master Vendor & Rekanan | β | β | β | β | β |
| Kelola Master Departemen & Pengguna | β | β | β | β | β |
| Akses Laporan Analitik & KPI Dashboard | β | β | β | β | β |
Setiap perubahan status tersimpan di tabel status_histories. Model StatusHistory menerapkan proteksi ketat pada tingkat kode:
- Timestamp transaksi tersimpan otomatis (append-only).
- Menangkap
request_id,changed_by,from_status,to_status,notes, serta jejak digital jaringan:ip_addressdanuser_agent. - Metode
delete()danupdate()pada model sengaja di-override untuk melempar exception, memastikan bukti audit tidak dapat dimanipulasi (anti-tampering).
Ketika banyak operator gudang memeriksa atau mengambil alokasi stok material berbarengan, sistem mengisolasi record menggunakan lockForUpdate() di dalam transaksi atomik:
DB::transaction(function () use ($itemName, $requiredQty) {
$stock = Stock::where('item_name', 'like', '%' . $itemName . '%')
->lockForUpdate() // SELECT ... FOR UPDATE (Mencegah double-allocation)
->first();
if ($stock && $stock->isAvailable($requiredQty)) {
$stock->decrement('quantity', $requiredQty);
}
// ...
});Seluruh tabel transaksi dan master menggunakan Universally Unique Identifier (UUIDv4 / 36-karakter string), menghilangkan kerentanan ID Enumeration / Insecure Direct Object References (IDOR) yang sering ditemukan pada ID integer incremental biasa.
Sistem menyediakan endpoint intelijen bisnis yang dioptimasi pada level basis data:
averageLeadTime: Menghitung rata-rata, waktu tercepat, dan waktu terlama proses pengadaan dari statusSUBMITTEDhinggaCOMPLETEDmenggunakan subkueriTIMESTAMPDIFF(DAY, ...).categoryPerMonth: Agregasi tren belanja per kategori barang bulanan (DATE_FORMAT).topDepartments: Menampilkan 5 departemen paling aktif mengajukan permohonan dalam 3 bulan terakhir (DATE_SUB(NOW(), INTERVAL 3 MONTH)).
Base URL: http://localhost:8000/api/v1
Semua endpoint terproteksi memerlukan header:
Authorization: Bearer <your_access_token>
Accept: application/json{
"meta": {
"code": 200,
"status": "success",
"message": "Data request retrieved."
},
"result": { ... }
}| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
POST |
/auth/login |
Publik | Autentikasi kredensial & penerbitan Bearer Token |
POST |
/auth/register |
Publik | Pendaftaran pengguna baru |
POST |
/auth/logout |
π Terautentikasi | Pencabutan token sesi aktif |
GET |
/auth/me |
π Terautentikasi | Profil akun yang sedang login beserta data departemen |
Contoh Request & Response Login
Payload Request:
{
"email": "employee@procurement.app",
"password": "password"
}Respon Sukses (200 OK):
{
"meta": {
"code": 200,
"status": "success",
"message": "login berhasil"
},
"result": {
"access_token": "1|qXy...random_sanctum_token...",
"token_type": "Bearer",
"user": {
"id": "019e1304-e3c3-731d-b5c2-2a2c1be46252",
"name": "Budi Santoso",
"email": "employee@procurement.app",
"role": "employee",
"department": {
"id": "019e1304-e3c0-731d-b5c2-2a2c1be46251",
"name": "Finance",
"code": "FIN"
}
}
}
}| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
GET |
/requests |
π Terautentikasi | Daftar pengadaan (disaring otomatis per peran & query filter) |
POST |
/requests |
π Terautentikasi | Pembuatan draf pengadaan baru beserta daftar item (batch) |
PUT |
/requests/{id} |
π Terautentikasi | Pembaharuan catatan pengadaan (hanya status DRAFT) |
DELETE |
/requests/{id} |
π Terautentikasi | Pembatalan draf (hanya status DRAFT) |
PUT |
/requests/{id}/submit |
π Terautentikasi | Mengajukan draf untuk ditinjau (DRAFT β SUBMITTED) |
PUT |
/requests/{id}/approve |
π Manager, Admin | Menyetujui pengadaan (SUBMITTED β APPROVED) |
PUT |
/requests/{id}/reject |
π Manager, Admin | Menolak pengadaan beserta alasan penolakan |
PUT |
/requests/{id}/procure |
π Purchasing, Admin | Menerbitkan PO ke vendor (APPROVED β IN_PROCUREMENT) |
PUT |
/requests/{id}/complete |
π Purchasing, Admin | Menutup pengadaan (IN_PROCUREMENT β COMPLETED) |
Contoh Payload Pembuatan Pengadaan Multi-Item
{
"notes": "Pengadaan suku cadang perangkat telekomunikasi navigasi darurat",
"items": [
{
"item_name": "Switch Cisco Catalyst 24-Port",
"category": "Electronics",
"quantity": 2,
"unit": "unit",
"estimated_price": 18500000,
"notes": "Spesifikasi rackmount untuk data center cabang"
},
{
"item_name": "Kabel UTP Cat6 305m",
"category": "Office Equipment",
"quantity": 3,
"unit": "roll",
"estimated_price": 1750000,
"notes": "Roll kabel bersertifikat ISO"
}
]
}Contoh Payload Penerbitan Purchase Order (Procure)
{
"vendor_id": "019e1304-e7ba-73a2-820d-693700020831",
"expected_delivery_date": "2026-06-15",
"total_amount": 42250000,
"notes": "Pengiriman langsung ke Workshop Logistik Bagian Barat"
}| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
GET |
/procures |
π Purchasing, Admin | Melihat seluruh Purchase Order beserta vendor & status |
PUT |
/procures/{id}/deliver |
π Purchasing, Admin | Konfirmasi penerimaan barang & otomasi penutupan request |
| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
GET |
/stocks |
π Terautentikasi | Katalog stok barang dengan filter kategori & nama |
GET |
/stocks/{id} |
π Terautentikasi | Detail stok item |
POST |
/stocks |
π Warehouse, Admin | Registrasi material/stok baru |
PUT |
/stocks/{id} |
π Warehouse, Admin | Penyesuaian informasi/jumlah stok |
POST |
/stocks/check |
π Terautentikasi | Validasi ketersediaan barang dengan Pessimistic Lock |
| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
GET |
/vendors |
π Terautentikasi | Daftar vendor berstatus aktif beserta kategori layanan |
GET |
/vendors/{id} |
π Terautentikasi | Rincian profil rekanan |
POST |
/vendors |
π Purchasing, Admin | Registrasi vendor rekanan baru |
PUT |
/vendors/{id} |
π Purchasing, Admin | Update legalitas/kontak vendor |
DELETE |
/vendors/{id} |
π Purchasing, Admin | Nonaktifkan / hapus vendor |
| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
GET |
/departments |
π Terautentikasi | Daftar departemen beserta relasi pengguna |
GET |
/departments/{id} |
π Terautentikasi | Detail unit departemen |
POST |
/departments |
π Admin | Tambah struktur departemen baru |
PUT |
/departments/{id} |
π Admin | Edit kode atau nama departemen |
DELETE |
/departments/{id} |
π Admin | Hapus departemen |
| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
GET |
/users |
π Admin | Daftar seluruh karyawan & hak akses |
GET |
/users/{id} |
π Admin | Detail spesifik karyawan |
POST |
/users |
π Admin | Pembuatan akun baru dengan penetapan role |
PUT |
/users/{id} |
π Admin | Modifikasi profil karyawan (dilindungi dari modifikasi akun sendiri) |
PATCH |
/users/{id}/role |
π Admin | Mengubah role jabatan |
DELETE |
/users/{id} |
π Admin | Hapus pengguna & cabut seluruh token aktif |
| Metode | Endpoint | Akses | Keterangan |
|---|---|---|---|
GET |
/reports/summary |
π Manager, Admin | Ringkasan metrik eksekutif (total permohonan, antrean approval, vendor aktif) |
GET |
/reports/top-departments |
π Manager, Admin | 5 departemen dengan pengajuan terbanyak dalam 3 bulan terakhir |
GET |
/reports/category-per-month |
π Manager, Admin | Distribusi volume dan frekuensi belanja per kategori per bulan |
GET |
/reports/average-lead-time |
π Manager, Admin | Metrik SLA rata-rata, tercepat, dan terlama pengadaan (hari) |
[departments] ββ< [users] ββ< [requests] ββ< [request_items]
βββ< [approvals]
βββ< [status_histories] (Immutable Log)
βββ< [procurement_orders] >ββ [vendors]
[stocks]
- Foreign Key Constraints: Menggunakan aturan
restrictOnDelete()pada seluruh relasi inti untuk mencegah hilangnya riwayat historis pengadaan jika entitas master dihapus secara tidak sengaja. - Soft Deletes: Diterapkan pada data transaksional (
requests,request_items,procurement_orders) agar pemulihan data dan penelusuran audit tetap terjaga. - Compound Indexing: Index dipasang pada kolom filter yang sering diakses (
status,requester_id,department_id,created_at).
- PHP >= 8.2 (dengan ekstensi
pdo_mysql,openssl,mbstring,curl) - Composer >= 2.x
- MySQL >= 8.0
- Git
# 1. Kloning repository
git clone https://github.com/Azzasafah/procurement-api.git
cd procurement-api
# 2. Instal dependensi PHP via Composer
composer install
# 3. Siapkan file konfigurasi lingkungan
cp .env.example .env
# 4. Generate Application Encryption Key
php artisan key:generate
# 5. Konfigurasi kredensial basis data pada file .env
# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=procurement_db
# DB_USERNAME=root
# DB_PASSWORD=your_password
# 6. Jalankan migrasi tabel
php artisan migrate
# 7. Isi data awal (departemen, akun multi-role, vendor sampel, stok awal)
php artisan db:seed
# 8. Hubungkan storage symlink (jika menggunakan fitur foto profil)
php artisan storage:link
# 9. Jalankan server lokal
php artisan serveServer API akan aktif dan siap menerima request pada: http://localhost:8000.
Semua akun pengujian di bawah ini dibuat otomatis saat menjalankan php artisan db:seed dengan kata sandi universal: password.
| Peran | Nama Pengguna | Alamat Email | Departemen | Lingkup Tugas Pengujian |
|---|---|---|---|---|
| Admin | Admin System | admin@procurement.app |
Information Technology | Manajemen pengguna, role, dan konfigurasi master |
| Employee | Budi Santoso | employee@procurement.app |
Finance | Pengajuan draf kebutuhan barang operasional kantor |
| Manager | Andi Wijaya | manager@procurement.app |
Information Technology | Verifikasi & persetujuan/penolakan permohonan divisi |
| Purchasing | Siti Rahayu | purchasing@procurement.app |
Information Technology | Negosiasi vendor, penerbitan PO, dan penyelesaian order |
| Warehouse | Dewi Lestari | warehouse@procurement.app |
Operations | Validasi kuantitas stok gudang & penerimaan material |
Koleksi Postman siap pakai telah disediakan untuk mempermudah evaluasi pengujian menyeluruh:
- Menguji alur otorisasi Bearer Token.
- Menguji siklus hidup lengkap pengadaan dari status Draft hingga Completed.
- Menguji skenario negatif (Unauthorized access, Invalid status transitions, Forbidden role actions).
Muhammad Hafizh Azzasafah
Fullstack & Backend Engineer
- πΌ LinkedIn: linkedin.com/in/muhammad-hafizh-azzasafah
- π GitHub: github.com/Azzasafah
- π§ Email: muhammad.hafizh0408@gmail.com
Proyek ini dilisensikan di bawah lisensi terbuka MIT License.