Files

16 KiB
Raw Permalink Blame History

PRD — BerasPro

Produk: Sembara — Kelola Stok Beras dan Kebutuhan Sembako Versi dokumen: 1.1 (amandemen hasil sesi grilling 2026-08-25) Tanggal: 2026-08-25 Status: Aktif

Catatan amandemen v1.1: stack frontend diubah menjadi Filament-only; akses data dikunci ke REST API InsForge (JWT per-user); model data disamakan dengan skema live proyek InsForge yang sudah ter-deploy dan berisi data nyata.


1. Ringkasan (Overview)

Sembara adalah aplikasi web untuk pengelolaan stok beras dan pesanan pelanggan pada bisnis distribusi/grosir beras. Aplikasi membantu tim operasional mencatat master produk, memantau stok dan mutasinya, memproses sales order dari awal hingga selesai, mencetak surat jalan (delivery note), menangani komplain pelanggan, dan melihat laporan penjualan.

Target pengguna: pemilik/usaha beras skala kecil–menengah dengan 2 peran internal — admin dan operator.

2. Masalah

Pengelolaan bisnis beras yang masih manual (buku/Excel) menimbulkan:

  • Selisih stok tidak terlacak (tidak ada riwayat mutasi stok).
  • Pesanan hilang atau dobel-proses karena tidak ada alur status yang jelas.
  • Stok tidak otomatis berkurang saat order selesai → oversell.
  • Komplain pelanggan tidak tercatat dan tidak ada penanggung jawab.
  • Laporan penjualan sulit disusun.

3. Tujuan & Ukuran Sukses

Tujuan Metrik sukses
Stok akurat Setiap perubahan stok tercatat di stock_movements; selisih fisik vs sistem = 0 pada rekonsiliasi bulanan
Pesanan tertib 100% order melewati alur status valid (pending → processing → delivering → completed / cancelled)
Tanpa oversell Stok hanya berkurang sekali per order (idempotent), duplikat proses ditolak/dilewati
Keluhan terselesaikan Semua komplain berstatus open/resolved dengan jejak kepemilikan
Laporan cepat Ringkasan penjualan & stok tersedia dari halaman Reports tanpa olah manual

4. Pengguna & Peran

4.1 Admin

  • Mengelola user/operator.
  • Mengelola master produk dan stok (penyesuaian/restok).
  • Menyetujui/memproses/menyelesaikan/membatalkan order; menghapus order (soft-delete deleted_at).
  • Melihat semua keluhan dan menutupnya.
  • Mengakses laporan, log aktivitas, dan manajemen user.

4.2 Operator

  • Membuat dan mengubah pesanan.
  • Mengelola data pelanggan.
  • Menutup keluhan miliknya sendiri saja (validasi kepemilikan created_by).
  • Tidak dapat menghapus order, mengelola user, mengubah master produk/stok, atau mengakses laporan.

4.3 Pelanggan (indirek)

Tidak login. Datanya dikelola operator sebagai customers; komplain atas nama pelanggan dicatat lewat modul Complaints.

5. Fitur & Kebutuhan Fungsional

5.1 Autentikasi & Otorisasi

  • F1 — Login/logout berbasis sesi server-side. Autentikasi terjadi di InsForge (POST /api/auth/sessions). Access token (JWT) + refresh token disimpan dalam sesi Laravel terenkripsi (SESSION_DRIVER=file) dan di-refresh otomatis oleh middleware saat mendekati kedaluwarsa. Profil user diambil dari tabel users proyek (role, is_active).
  • F2 — Role-based access. Dua peran: admin, operator — kolom enum users.role. Diimplementasi via policy + Gate Laravel (Gate::before untuk admin). Satu panel Filament /admin; menu dan aksi difilter per ability; akses langsung ditolak 403.
  • Kriteria terima:
    • User belum login dialihkan ke halaman login.
    • Operator yang mengakses fitur admin mendapat 403.

5.2 Produk

  • F3 — Master produk (CRUD, admin). Atribut sesuai skema live: code, name, unit, weight, stock_minimum, cost_price, is_active.
  • Harga jual tidak disimpan di master produk; harga transaksi ditetapkan per baris item pada order_items.unit_price.
  • Kriteria terima: produk tampil di daftar, dapat dibuat/diedit; produk dipakai di order tetap konsisten (harga order tersimpan pada item).

5.3 Stok

  • F4 — Stok per produk. Melihat kuantitas tersedia per produk (stocks.quantity, denormalisasi terkontrol).
  • F5 — Penyesuaian/restok stok (admin). Mencatat penambahan (restok) atau koreksi; setiap perubahan menghasilkan baris mutasi dan update saldo dalam satu operasi.
  • F6 — Riwayat mutasi stok (stock_movements). Kolom: product_id, type (mis. restock, adjustment, order_out), quantity, reference_type/reference_id, notes, created_by, waktu.
  • Kriteria terima: saldo stok selalu = hasil agregat mutasi (rekonsiliasi); riwayat dapat difilter/dilihat per produk.

5.4 Pelanggan

  • F7 — CRUD pelanggan. Dapat dilakukan operator dan admin. Kolom live: customer_code (CUST-XXXX), nama, alamat, telepon, catatan.
  • Kriteria terima: pelanggan dapat dipilih saat membuat order; penghapusan diblokir jika masih direferensikan order.

5.5 Pesanan (Sales Order)

  • F8 — CRUD order + item order. Satu order memiliki ≥1 item (order_items: produk, qty, unit_price, subtotal). Nomor order otomatis ORD-YYYYMMDD-XXXX (sequence harian, immutable).
  • F9 — Alur status (orders.order_status): pending → processing → delivering → completed, alternatif cancelled hanya dari pending/processing oleh admin atau operator pembuat (created_by). Transisi forward-only, tidak boleh mundur; completed bersifat immutable.
  • F10 — Pengurangan stok otomatis & idempotent. Saat order menjadi completed: fungsi RPC di InsForge menyisipkan mutasi order_out (partial unique index stock_movements(reference_type, reference_id) sebagai gerbang idempotensi — duplikat dilewati) lalu decrement stocks.quantity, secara atomik.
  • F11 — Cetak surat jalan (PDF) via barryvdh/laravel-dompdf, pratinjau/stream di /orders/{id}/delivery-note, nomor berformat SJL-YYYY/MM/DD-<order_number>; aksi aktif saat status delivering/completed.
  • F12 — Hapus order (soft-delete deleted_at) hanya oleh admin.
  • F13 — Riwayat status (order_status_histories). Setiap perubahan status tercatat dengan old_status, new_status, changed_by, waktu, catatan.
  • Data pendukung (skema live): order_date, delivery_date, driver_id, payment_method (mis. cash), payment_status (mis. paid/unpaid), survey_status (survei kepuasan pasca-penerimaan barang; diisi setelah order completed), notes, completed_at.
  • Validasi dua gerbang oversell: qty divalidasi terhadap saldo saat create/update order dan saat transisi ke completed (stok kurang → transisi ditolak dengan pesan jelas).
  • Kriteria terima:
    • Order tidak bisa completed jika transisi tidak valid.
    • Proses ulang "completed" pada order yang sama tidak mengurangi stok dua kali.
    • Driver/pengiriman dapat ditetapkan pada order (integrasi modul Drivers).

5.6 Pengemudi (Drivers)

  • F14 — Master driver (admin). Kolom live: driver_code (DRV-XXXX), nama, telepon, is_active, catatan.

5.7 Keluhan (Complaints)

  • F15 — Catat komplain pelanggan, terhubung ke order/pelanggan. Nomor CMP-YYYYMMDD-XXXX. Status: open / resolved; kolom pendukung live: category, priority, resolution, resolved_at.
  • F16 — Validasi kepemilikan: operator hanya boleh menutup keluhan miliknya (created_by); admin bebas. Penutupan mengisi resolution + resolved_at.
  • Kriteria terima: transisi status keluhan tervalidasi; penutupan oleh pihak salah ditolak 403.

5.8 Dashboard & Laporan

  • F17 — Dashboard statistik ringkas untuk user login — empat widget: jumlah order per status, tabel stok kritis (quantity <= stock_minimum), komplain open berjalan, daftar pesanan terbaru.
  • F18 — Laporan (khusus admin): (1) ringkasan penjualan — filter periode, total & per produk; (2) posisi stok + riwayat mutasi. Ekspor CSV/laba masuk backlog.

5.9 Manajemen User

  • F19 — Kelola user (khusus admin): daftar, tambah (via admin API InsForge), ubah role/nonaktifkan (is_active).

6. Model Data

Sumber kebenaran skema = proyek InsForge live (dikelola via migrasi SQL InsForge, bukan migrasi Laravel). PK UUID di semua tabel; *_by mereferensi auth.users(id); waktu disimpan UTC, ditampilkan Asia/Jakarta.

Tabel Kolom utama (skema live)
users id, name, email, password (hash mirror), role (admin/operator), is_active
customers id, customer_code, name, address, phone, notes
products id, code, name, unit, weight, stock_minimum, cost_price, is_active
stocks id, product_id, quantity (saldo denormalized), updated_at
stock_movements id, product_id, type, quantity, reference_type, reference_id, notes, created_by — partial unique index (reference_type, reference_id)
orders id, order_number, order_date, delivery_date, delivery_note_number, customer_id, driver_id, payment_method, payment_status, order_status, survey_status, notes, completed_at, created_by, deleted_at
order_items id, order_id, product_id, quantity, unit_price, subtotal
order_status_histories id, order_id, old_status, new_status, changed_by, notes
complaints id, complaint_number, customer_id, order_id, complaint_date, category, description, status, priority, resolution, resolved_at, created_by
drivers id, driver_code, name, phone, is_active, notes
activity_logs id, user_id, action, entity_type, entity_id, description

Row Level Security (RLS) tetap aktif di sisi InsForge sebagai lapisan pertahanan kedua; seluruh panggilan data plane membawa JWT user (lihat §8).

7. Alur Utama

7.1 Siklus order (happy path)

  1. Operator membuat order (pilih pelanggan, tambah item produk+qty+harga; sistem validasi saldo stok).
  2. pending → diproses (processing) → siap kirim (delivering, tetapkan driver) → completed (RPC idempotent: mutasi order_out + decrement stok atomik).
  3. Operator/admin cetak surat jalan PDF (SJL-…) untuk diserahkan pengemudi.
  4. Setelah barang diterima: survey_status (survei kepuasan) dapat dicatat.
  5. Bila batal: cancelled (hanya dari pending/processing) tanpa efek stok.

7.2 Penanganan komplain

  1. Operator mencatat komplain pelanggan (status open, nomor CMP-…).
  2. Pemilik komplain atau admin menindaklanjuti, mengisi resolution, lalu menutup (resolved, resolved_at terisi).

8. Kebutuhan Non-Fungsional

Kategori Persyaratan
Arsitektur Laravel 12 + Filament 5 (server-rendered, panel tunggal); InsForge cloud sebagai satu-satunya backend data & auth via REST (/api/database/records/*, RPC); tanpa database lokal
Identitas akses Data plane memakai JWT user hasil login (RLS InsForge aktif sebagai lapis kedua); API key admin (ik_…) hanya untuk provisioning (manajemen user, seed)
Keamanan Sesi server-side (SESSION_DRIVER=file, terenkripsi); otorisasi policy/Gate; kredensial hanya di .env (tidak dikomit)
Konsistensi data Idempotensi stok wajib (unique index gerbang mutasi via RPC); validasi transisi status di server
Performa List terpaginasi server-side (offset/limit); query REST selalu menyebut kolom (select=…) dan dibatasi limit
Zona waktu Simpan UTC, tampilkan Asia/Jakarta
Auditability order_status_histories, stock_movements, activity_logs (ditulis service ActivityLogger: action snake-case EN, deskripsi ID)
Testability PHPUnit (±23 tes) dengan InsForgeFake untuk HTTP fake; suite Authentication, Authorization, OrderFlow (termasuk idempotensi stok), ComplaintFlow

9. Teknologi

  • Backend: PHP ^8.2, Laravel 12, Filament 5, laravel-dompdf (surat jalan PDF).
  • Frontend: Filament resources/pages (Blade + Livewire bawaan), Tailwind CSS.
  • Backend-as-a-Service: InsForge (Postgres + PostgREST-style REST, auth JWT, RLS) — client wrapper app/Services/InsForge/InsForgeClient.php di atas HTTP client Laravel.
  • Testing: PHPUnit + tests/Support/InsForgeFake.php.
  • Dibuang dari v1.0: Inertia, Vue, TypeScript, Sanctum, Ziggy (tidak dipakai; UI sepenuhnya Filament).

10. Batasan (Out of Scope)

  • Portal/e-commerce pelanggan mandiri (pelanggan tidak login).
  • Pembayaran online / invoice faktur pajak (kolom pembayaran hanyalah pencatatan manual status/method).
  • Multi-gudang / multi-lokasi stok.
  • Notifikasi WhatsApp/email otomatis.
  • Aplikasi mobile native untuk driver.

11. Rencana Lanjutan (Backlog)

  • Notifikasi status order ke pelanggan.
  • Laporan laba (cost_price vs unit_price) dan ekspor Excel/CSV.
  • Alert otomatis (notifikasi) minimum-stock di dashboard — saat ini baru widget daftar stok kritis.
  • Restore UI untuk order soft-deleted.
  • Chart tren penjualan di dashboard.

12. Akun Demo (seed)

Seed historis 20260818032150_seed-initial-data.sql di proyek InsForge:

Role Email Catatan
Admin admin@beraspro.test Password live berbeda dari dokumen v1.0 (terverifikasi 401)
Operator operator@beraspro.test Password live tidak diketahui dokumen ini

Akun integrasi khusus pengembangan (dibuat via admin API, fase 0):

Role Email Password
Admin dev@beraspro.test acak, dilaporkan sekali, disimpan di .env

Jangan komit password ke repository; simpan hanya di .env lokal.

13. Keputusan Arsitektur (hasil grilling 2026-08-25)

  1. Backend tunggal InsForge cloud live; tidak ada DB lokal dan tanpa koneksi Postgres langsung (port tidak diekspos).
  2. UI sepenuhnya Filament (panel /admin, label bahasa Indonesia); Inertia/Vue/Sanctum/Ziggy dihapus dari rencana.
  3. Skema live adalah sumber kebenaran — aplikasi menyesuaikan konvensi live: nomor ORD-/SJL-/CMP-, kolom order_status/survey_status/pembayaran, soft-delete deleted_at, harga jual per item.
  4. Panggilan data membawa JWT user (RLS hidup); refresh token disimpan di sesi server dan di-refresh otomatis; API key admin hanya untuk provisioning.
  5. Alur order forward-only; cancelled hanya dari pending/processing oleh admin/pembuat; completed immutable; pengurangan stok lewat RPC idempotent saat completed.
  6. Uang integer rupiah tanpa desimal; UUID untuk semua PK; audit via ActivityLogger.
  7. Implementasi bertahap 0–6 (fondasi → auth → master → stok → order+PDF → komplain → dashboard/laporan/user), tiap fase diakhiri suite hijau.