Skip to content

Repository files navigation

Simple POS — Aplikasi Studi Kasus Pemrograman Web Lanjut (SIB)

Aplikasi Point of Sale (POS)/kasir UMKM sederhana berbasis Laravel 13. Ini adalah demonstrasi dosen untuk mata kuliah Pemrograman Web Lanjut (RTI254007, Prodi D4 Sistem Informasi Bisnis) — dibangun bertahap mengikuti RPS di ../RTI254007-pemrograman-web-lanjut-sib/, dan menjadi rujukan arsitektur bagi proyek PBL mahasiswa.

Seluruh dokumentasi proyek ada di file ini — tidak ada file dokumentasi terpisah.

Stack

  • Laravel 13 (PHP ^8.3, dijalankan dengan PHP 8.4 lewat Nix)
  • SQLite — zero-setup, file-based
  • Tailwind CSS via CDN — tidak ada langkah build frontend (npm/Vite tidak diperlukan)
  • Laravel Sanctum — token-based API authentication

Menjalankan proyek

Environment PHP disediakan lewat Nix (lihat shell.nix, dibuat dengan php-init 8.4).

# masuk shell (php + composer tersedia)
nix-shell shell.nix

# atau via direnv (sekali izinkan)
direnv allow

composer install
cp .env.example .env      # jika belum ada .env
php artisan key:generate
touch database/database.sqlite
php artisan migrate:fresh --seed
php artisan serve

Buka http://127.0.0.1:8000. Cukup php artisan serve — tidak ada langkah build frontend.

Akun demo (dari seeder)

Peran Email Password
Admin admin@pos.test password
Kasir kasir@pos.test password

Menjalankan test

nix-shell shell.nix --run "php artisan test"

13 test (27 assertion): login/logout, otorisasi berbasis peran (kasir diblokir dari halaman admin), transaksi POS (dekremen stok & perhitungan total), alur token API (login → transaksi).

Data seed, pagination, dan performa

database/seeders/DatabaseSeeder.php sengaja mengisi data dalam skala nyata, bukan sekadar beberapa baris — supaya paginasi (paginate()) benar-benar terlihat, dan supaya cara mengisinya sendiri jadi contoh sadar-performa, bukan cuma "lebih banyak data".

Volume yang di-seed (php artisan migrate:fresh --seed, ±1.8 detik):

Tabel Jumlah baris Halaman paginasi
categories 8
products 300 (12 kurasi manual + 288 sintetis, 15 sengaja stok < 10) 30 halaman @ paginate(10)
transactions 2.500 (tersebar 120 hari terakhir) ±167 halaman @ paginate(15)
transaction_details 6.250 (1–4 item per transaksi)

Kenapa bulk insert, bukan Model::create() per baris. Dengan ribuan baris, memanggil Product::create()/Transaction::create() satu per satu berarti ribuan query individual plus overhead event Eloquent (observer, casting, dirty-tracking) per baris — lambat dan tidak representatif untuk skala produksi. Seeder ini membangun array PHP dulu, lalu insert lewat DB::table(...)->insert($chunk) dalam batch 100 baris/statement (dijaga di bawah batas ~999 parameter terikat SQLite per statement), dibungkus satu DB::transaction() untuk transaksi

  • detail agar commit sekali, bukan per baris. Hasilnya: 300 produk + 2.500 transaksi + 6.250 baris detail selesai dalam ±2 detik.

Kenapa perlu index eksplisit — bug performa nyata yang ditemukan. Migrasi memakai foreignId()->constrained() untuk semua foreign key. Di MySQL, kolom FK otomatis ter-index; di SQLite, tidakconstrained() hanya menambah constraint, bukan index. Pada skala 12 baris hal ini tidak kelihatan; pada skala ribuan baris, query listing/laporan akan melakukan full table scan. Migrasi di proyek ini menambahkan $table->index(...) eksplisit pada: products.category_id, transactions.user_id, transactions.created_at (dipakai ORDER BY di listing transaksi dan whereBetween di filter laporan), transaction_details.transaction_id, transaction_details.product_id. Dikonfirmasi dengan EXPLAIN QUERY PLAN:

SEARCH transactions USING INDEX transactions_created_at_index (created_at>? AND created_at<?)
SEARCH transaction_details USING INDEX transaction_details_transaction_id_index (transaction_id=?)

tanpa index eksplisit, baris di atas akan berbunyi SCAN transactions (full table scan).

Membuktikan paginasi bekerja (bukan single-page no-op): GET /products?page=2 dan GET /transactions?page=2 mengembalikan baris yang benar-benar berbeda dari halaman 1 (SKU GEN-0146... vs AIR-001... pada products; invoice tanggal berbeda pada transactions) — sudah diverifikasi manual lewat curl.

Increment ↔ minggu RPS

Setiap commit git dilabeli increment N dan berkorespondensi dengan minggu RPS di RTI254007 Pemrograman Web Lanjut SIB - RPS.tex. Ini adalah artefak yang didemonstrasikan dosen tiap minggu di kelas.

Increment Minggu RPS Topik Yang dibangun
1 1 Arsitektur web, framework, environment Setup proyek Laravel, repo Git, SQLite
2 2 HTTP, MVC, routing, controller Route & controller produk/transaksi
3 3 Templating, komponen, asset bundling Layout Blade + Tailwind CDN, halaman POS
4–5 4–5 Desain DB, migrasi, ORM, relasi Skema (produk, kategori, transaksi), model Eloquent, index FK
6 6 Validasi & sanitasi FormRequest produk & transaksi
7 7 Autentikasi, RBAC Login, middleware role:admin
8 (UTS) Milestone studi kasus Demo aplikasi hasil increment 1–7
9 9 Pengolahan data, import/export Laporan penjualan (CSV export), import produk (CSV)
10 10 Arsitektur & desain API Sanctum token auth, API produk/transaksi untuk kasir mobile

Minggu 11–15 (PBL): tim mahasiswa membangun aplikasi pada domain bisnis pilihan sendiri, menjadikan struktur proyek ini (skema → model → controller/route → view → validasi → auth → laporan → API) sebagai referensi arsitektur.

Struktur fitur

  • Kasir (POS)/pos: pilih produk dari grid, keranjang dinamis (JS), simpan transaksi (stok didekremen dalam DB transaction dengan row lock).
  • Admin/products, /categories: CRUD produk & kategori (middleware role:admin), dengan paginasi (30 halaman produk pada data seed).
  • Laporan/reports: filter tanggal, total penjualan, export CSV; /reports/import: import produk dari CSV.
  • API kasir mobilePOST /api/login (token Sanctum), GET /api/products, POST /api/transactions (header Authorization: Bearer <token>).

Model data

categories 1──* products 1──* transaction_details *──1 transactions *──1 users
  • users.role: admin | kasir
  • transactions.total, transaction_details.subtotal: dihitung server-side, bukan dari input klien.
  • Index eksplisit pada semua kolom foreign key + transactions.created_at (lihat bagian "Data seed, pagination, dan performa" di atas).

About

Simple POS — Laravel demo app for Pemrograman Web Lanjut (mirrored from dhanifudin/simple-pos)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages