Skip to content

About

Enterprise Procurement Management RESTful API built with Laravel 12 & Service Layer architecture. Features multi-stage approval workflows, FSM, pessimistic locking, immutable audit trail, and analytical reporting.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

🏒 Enterprise Procurement Management API

Laravel PHP MySQL Sanctum Architecture Audit Compliance

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.


πŸ“Œ Executive Summary

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:

  1. Perencanaan Kebutuhan (Requisition) oleh unit kerja/divisi.
  2. Pemeriksaan Stok Real-time (Warehouse Inventory Check) dengan mekanisme concurrency lock.
  3. Persetujuan Bertingkat (Multi-Stage Approval Hierarchy) oleh manajemen.
  4. Penerbitan Kontrak / Purchase Order (PO) ke mitra rekanan (vendor).
  5. Penerimaan Logistik & Verifikasi (Delivery & Fulfillment).
  6. Pelaporan Eksekutif & Analisis Lead Time (Business Intelligence).

🎯 Keselarasan Standar Industri & Tata Kelola Enterprise

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.

πŸ— Enterprise Architecture & Design Patterns

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

πŸ”„ Alur Bisnis & Finite State Machine (FSM)

Sistem pengadaan menerapkan State Machine deterministik untuk menjamin tidak ada satupun pesanan yang melompati tahapan audit.

1. Diagram Transisi Status Pengadaan (Procurement Request FSM)

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 --> [*]
Loading

2. Diagram Urutan Proses Antar-Aktor (Sequence Flow)

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
Loading

πŸ” Matriks Hak Akses & Peran (Role-Based Access Control)

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 ❌ βœ… ❌ ❌ βœ…

πŸ›‘οΈ Keunggulan Rekayasa Perangkat Lunak (Engineering Highlights)

1. πŸ“œ Immutable Audit Trail & Regulatory Compliance

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_address dan user_agent.
  • Metode delete() dan update() pada model sengaja di-override untuk melempar exception, memastikan bukti audit tidak dapat dimanipulasi (anti-tampering).

2. ⚑ Penanganan Konkurensi & Race Condition (Pessimistic Locking)

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);
    }
    // ...
});

3. πŸ”‘ Proteksi Enumerasi Identitas (UUIDv4)

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.

4. πŸ“Š Kueri Analitik & Business Intelligence

Sistem menyediakan endpoint intelijen bisnis yang dioptimasi pada level basis data:

  • averageLeadTime: Menghitung rata-rata, waktu tercepat, dan waktu terlama proses pengadaan dari status SUBMITTED hingga COMPLETED menggunakan subkueri TIMESTAMPDIFF(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)).

πŸ“š Dokumentasi Endpoint API

Base URL: http://localhost:8000/api/v1
Semua endpoint terproteksi memerlukan header:

Authorization: Bearer <your_access_token>
Accept: application/json

Format Standar Respon (Envelope Pattern)

{
  "meta": {
    "code": 200,
    "status": "success",
    "message": "Data request retrieved."
  },
  "result": { ... }
}

1. Autentikasi (/auth)

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"
      }
    }
  }
}

2. Permohonan Pengadaan (/requests)

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"
}

3. Purchase Order & Logistik (/procures)

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

4. Manajemen Stok & Pergudangan (/stocks)

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

5. Mitra Rekanan / Vendor (/vendors)

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

6. Departemen & Organisasi (/departments)

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

7. Manajemen Pengguna (/users)

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

8. Laporan & Intelijen Bisnis (/reports)

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)

πŸ—„οΈ Relasi Basis Data & Integritas Skema

[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).

πŸš€ Panduan Instalasi & Eksekusi Lokal

Prasyarat Lingkungan

  • PHP >= 8.2 (dengan ekstensi pdo_mysql, openssl, mbstring, curl)
  • Composer >= 2.x
  • MySQL >= 8.0
  • Git

Langkah-Langkah Setup

# 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 serve

Server API akan aktif dan siap menerima request pada: http://localhost:8000.


πŸ‘₯ Akun Simulasi & Pengujian Bawaan (Seeders)

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 Pengujian API (Postman)

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).

πŸ‘¨β€πŸ’» Profil Pengembang

Muhammad Hafizh Azzasafah
Fullstack & Backend Engineer


πŸ“„ Lisensi

Proyek ini dilisensikan di bawah lisensi terbuka MIT License.

About

Enterprise Procurement Management RESTful API built with Laravel 12 & Service Layer architecture. Features multi-stage approval workflows, FSM, pessimistic locking, immutable audit trail, and analytical reporting.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages