Nalala Store — Dokumen Skripsi

Rekayasa Perangkat Lunak & Basis Data

DOKUMEN REKAYASA PERANGKAT LUNAK

Perancangan dan Pengujian Sistem
E-Commerce Nalala Store

Penjualan Tas Fashion Berbasis Paket Usaha, Capacity Checker, dan Otomatisasi Logistik

Stack: Node.js + Express + MySQL (Prisma) + Midtrans + J&T + WhatsApp September 2026

Klik Export PDF di pojok kanan atas untuk simpan sebagai PDF. Daftar Isi di samping bisa diklik untuk lompat antar bab.

BAB I — PENDAHULUAN

Bab ini menjelaskan alasan kenapa sistem Nalala Store perlu dibangun, masalah apa yang ingin diselesaikan, serta tujuan dan batasan pengerjaannya.

1.1 Latar Belakang

Nalala Store adalah toko yang menjual tas fashion seperti tote bag, sling bag, shoulder bag, dan ransel. Selama ini penjualan masih dikelola manual, sehingga muncul tiga masalah utama:

  1. Urus reseller masih manual. Untuk dapat harga reseller, pembeli harus verifikasi manual oleh admin. Proses jadi lambat dan menghambat penjualan grosir.
  2. Urus pengiriman masih manual. Admin harus buat resi satu per satu, input nomor resi dari J&T, dan cetak struk thermal secara manual.
  3. Pembeli bingung kapasitas tas. Pembeli online tidak yakin apakah tas muat untuk laptop, botol minum, atau mukena. Akibatnya banyak yang ragu beli atau minta retur.

Untuk itu dibangun website e-commerce yang otomatis: ada program Paket Usaha untuk jadi reseller otomatis, ada fitur Capacity Checker untuk cek muat tidaknya barang, serta sistem yang otomatis buat resi J&T dan kirim notifikasi WhatsApp setelah bayar.

Website dibangun pakai Node.js + Express di backend, MySQL dengan Prisma untuk database, dan proses berat seperti buat PDF dan kirim WA dijalankan di latar belakang (async) supaya tidak bikin webhook Midtrans timeout.

1.2 Rumusan Masalah

  1. Bagaimana membuat sistem reseller yang otomatis tanpa verifikasi manual?
  2. Bagaimana menangani stok agar tidak terjadi rebutan saat dua pembeli checkout bersamaan?
  3. Bagaimana membantu pembeli yakin soal daya muat tas sebelum beli?
  4. Bagaimana mengotomatiskan pembuatan resi J&T, cetak PDF thermal 58mm, dan notifikasi WhatsApp setelah pembayaran berhasil?
  5. Bagaimana memastikan semua alur sudah benar lewat pengujian White Box dan Black Box?

1.3 Tujuan Penelitian

  1. Membangun sistem e-commerce Nalala Store yang terintegrasi pembayaran Midtrans dan pengiriman J&T.
  2. Menerapkan aturan Paket Usaha: beli 11 tas dapat 1 bonus, otomatis jadi reseller selamanya setelah lunas.
  3. Menyediakan Capacity Checker agar pembeli bisa cek muat tidaknya barang ke dalam tas.
  4. Mengotomatiskan resi, PDF struk, dan WA notifikasi tanpa proses manual admin.
  5. Menyusun dokumen perancangan basis data, perancangan sistem UML, dan pengujian yang bisa dipakai untuk laporan skripsi.

1.4 Manfaat Penelitian

  • Bagi toko: Proses reseller dan pengiriman jadi lebih cepat, stok lebih aman, penjualan paket usaha meningkat.
  • Bagi pembeli: Lebih yakin memilih tas, dapat harga reseller mulai 1 pcs tanpa minimal order, dan dapat info resi otomatis via WhatsApp.
  • Bagi akademik: Menjadi contoh penerapan ERD ke LRS, diagram UML, serta pengujian White Box dan Black Box pada studi kasus e-commerce nyata.

1.5 Batasan Masalah

  • Pembayaran hanya lewat Midtrans Snap (VA bank dan QRIS).
  • Kurir yang dipakai hanya J&T Express, ongkir ditanggung pembeli.
  • Paket Usaha yang dibahas adalah Paket A: 11 tas pilihan + 1 bonus acak seharga Rp0, harga flat Rp500.000 (dikonfigurasi admin).
  • Capacity Checker menghitung berdasar volume sederhana, bukan simulasi 3D.
  • Role pengguna hanya GUEST, RESELLER, dan ADMIN. Reseller bersifat permanen setelah upgrade.

1.6 Alur Sistem Keseluruhan (Master Flowchart)

Flowchart di bawah merangkum alur lengkap dari pengunjung datang sampai pesanan selesai dikirim. Jika bingung baca diagram lain, lihat flowchart ini dulu sebagai peta besarnya.

Cara baca: Kotak persegi = proses, belah ketupat = keputusan (ya/tidak), oval = mulai/selesai, panah = arah alur.

flowchart TD START([Pengunjung Masuk Website]) --> CHOOSE{Pilih Jalur Belanja} CHOOSE -->|Belanja Reguler| P_DETAIL[Buka Halaman Produk Tas] P_DETAIL --> SIMULATE{Pakai Capacity Checker?} SIMULATE -->|Ya| CALC_CAP[Input Ukuran / Pilih Preset Barang] CALC_CAP --> CHECK_VOL{Kapasitas Muat?} CHECK_VOL -->|Overload| WARN_OVER[Tampilkan Warning Tidak Muat] WARN_OVER --> ADD_CART[Konfirmasi Masuk Keranjang] CHECK_VOL -->|Muat| ADD_CART SIMULATE -->|Tidak| ADD_CART ADD_CART --> CHECK_ROLE{Cek Role User} CHECK_ROLE -->|RESELLER| PRICE_RESELLER[Harga Reseller Berlaku] CHECK_ROLE -->|GUEST| PRICE_RETAIL[Harga Retail Berlaku] PRICE_RETAIL --> POPUP_NUDGE[Tampilkan Pop-up Ajakan Paket Usaha] PRICE_RESELLER --> CART_VIEW[Menuju Checkout] POPUP_NUDGE --> CART_VIEW CHOOSE -->|Beli Paket Usaha| PKT_PAGE[Buka Halaman Paket Usaha] PKT_PAGE --> PKT_CONFIG[Load Aturan Paket Aktif] PKT_CONFIG --> PKT_CATALOG[Filter Produk Non-HPP Tinggi] PKT_CATALOG --> PKT_PICK[Pembeli Pilih 11 Tas] PKT_PICK --> PKT_VALIDATE{Jumlah Tepat 11?} PKT_VALIDATE -->|Belum| PKT_PICK PKT_VALIDATE -->|Valid| PKT_BONUS[Sistem Kunci 1 Tas Bonus Acak Rp0] PKT_BONUS --> CART_VIEW CART_VIEW --> INPUT_ADDR[Input Alamat dan Pilih J&T] INPUT_ADDR --> CALC_ONGKIR[Panggil API Tarif J&T] CALC_ONGKIR --> CREATE_ORDER[Buat Order dan Kunci Stok 15 Menit] CREATE_ORDER --> MIDTRANS_SNAP[Muncul Popup Midtrans Snap] MIDTRANS_SNAP --> PAY_STATUS{Status Webhook} PAY_STATUS -->|Gagal atau Expired| PAY_FAIL[Order Jadi EXPIRED] PAY_FAIL --> RELEASE_STOCK[Lepas Kuncian Stok] RELEASE_STOCK --> ROLE_STAY[Role Tetap Guest] ROLE_STAY --> END_FAIL([Selesai Gagal]) PAY_STATUS -->|Sukses Settlement| PAY_SUCCESS[Verifikasi Signature SHA512] PAY_SUCCESS --> ATOMIC_UPDATE[Update Order Jadi PAID] ATOMIC_UPDATE --> IS_PAKET{Order Paket Usaha?} IS_PAKET -->|Ya| UPGRADE_RESELLER[Auto-Upgrade Jadi RESELLER Permanen] IS_PAKET -->|Tidak| DISPATCH_ASYNC[Lanjut ke Logistik] UPGRADE_RESELLER --> DISPATCH_ASYNC DISPATCH_ASYNC --> ACK_FAST[Kirim HTTP 200 OK ke Midtrans < 1 detik] ACK_FAST --> BG_PROCESS[Jalankan Worker Latar Belakang] subgraph Pipeline Latar Belakang BG_PROCESS --> API_JNT[Request AWB ke J&T] API_JNT --> GEN_PDF[Render PDF Thermal 58mm] GEN_PDF --> SEND_WA[Trigger WhatsApp Gateway] end SEND_WA --> WA_CUST[Kirim Resi ke Pembeli] SEND_WA --> WA_ADMIN[Kirim PDF ke Admin] WA_CUST --> END_SUCCESS([Pesanan Selesai]) WA_ADMIN --> END_SUCCESS

BAB II — PERANCANGAN BASIS DATA

Bab ini membahas bagaimana data toko disusun di database. Mulai dari gambar hubungan antar data (ERD), penjelasan tiap hubungan dengan bahasa sederhana, aturan ubah ERD jadi tabel nyata (LRS), sampai bentuk tabel akhirnya.

2.1 Entity Relationship Diagram (ERD) Konseptual

ERD adalah gambar yang menunjukkan entitas (tabel) dan hubungannya. Simbol yang dipakai adalah Crow's Foot:

  • ||--o{ artinya One-to-Many (1 ke Banyak) — satu baris di tabel kiri bisa terhubung ke banyak baris di tabel kanan.
  • }o--o{ artinya Many-to-Many (Banyak ke Banyak) — banyak baris di kiri bisa terhubung ke banyak baris di kanan (nanti dipecah jadi tabel perantara).
  • ||--|| artinya One-to-One (1 ke 1) — satu baris hanya pasangan dengan satu baris.

Arahkan kursor ke garis atau label relasi pada diagram untuk melihat keterangan kardinalitasnya. Simbol akan menyala biru saat di-hover.

erDiagram USERS ||--o{ CARTS : "memiliki" USERS ||--o{ ORDERS : "melakukan" USERS { int id PK string email string phone string name string role } CATEGORIES ||--o{ PRODUCTS : "mengelompokkan" CATEGORIES { int id PK string name } PRODUCTS }o--o{ CARTS : "dimuat_dalam" PRODUCTS }o--o{ ORDERS : "dipesan_dalam" PRODUCTS { int id PK string name decimal price_retail decimal price_reseller int stock boolean is_excluded_from_paket_usaha } PAKET_USAHA ||--o{ ORDERS : "menjadi_acuan" PAKET_USAHA ||--o{ CARTS : "diterapkan_pada" PAKET_USAHA { int id PK string name decimal price_flat int required_qty int bonus_qty } CARTS { int id PK string session_token string cart_type } ORDERS ||--|| PAYMENTS : "memiliki" ORDERS ||--|| SHIPMENTS : "menghasilkan" ORDERS { int id PK string order_no decimal total_amount string status } PAYMENTS { int id PK string gateway string status } SHIPMENTS { int id PK string awb_number string wa_status }

2.2 Penjelasan Relasi ERD (by Text)

Tabel di bawah menjelaskan tiap garis di ERD dengan bahasa sederhana: siapa terhubung ke siapa, simbolnya apa, dan kenapa begitu.

RelasiSimbolPenjelasan Sederhana
CATEGORIES ke PRODUCTS||--o{
One-to-Many
Satu kategori (misal "Sling Bag") bisa punya banyak produk. Satu produk hanya masuk satu kategori.
USERS ke CARTS||--o{
One-to-Many
Satu user bisa punya beberapa keranjang dari waktu ke waktu. Satu keranjang hanya milik satu user.
USERS ke ORDERS||--o{
One-to-Many
Satu user bisa pesan berkali-kali. Satu pesanan hanya milik satu user.
PRODUCTS ke CARTS}o--o{
Many-to-Many
Satu keranjang bisa berisi banyak produk. Satu produk bisa ada di banyak keranjang milik user berbeda. Nanti dipecah jadi CART_ITEMS.
PRODUCTS ke ORDERS}o--o{
Many-to-Many
Satu pesanan bisa berisi banyak produk. Satu produk bisa dibeli di banyak pesanan berbeda. Nanti dipecah jadi ORDER_ITEMS.
PAKET_USAHA ke CARTS||--o{
One-to-Many
Satu aturan Paket Usaha (misal Paket 500rb isi 11+1) bisa dipakai di banyak keranjang. Paket Usaha bukan tas, tapi aturan promo. Keranjang yang pakai paket ditandai supaya sistem cek kuota 11 item.
PAKET_USAHA ke ORDERS||--o{
One-to-Many
Satu aturan paket bisa dibeli di banyak pesanan. Tanda ini yang bikin sistem otomatis naikkan user jadi RESELLER setelah lunas.
ORDERS ke PAYMENTS||--||
One-to-One
Satu pesanan hanya punya satu pembayaran Midtrans. Tidak boleh ada dua pembayaran untuk satu pesanan yang sama.
ORDERS ke SHIPMENTS||--||
One-to-One
Satu pesanan lunas hanya menghasilkan satu resi J&T dan satu file PDF struk thermal.

2.3 Aturan Transformasi ERD ke LRS

LRS (Logical Record Structure) adalah bentuk nyata tabel di database MySQL. Cara mengubah ERD jadi LRS ada 4 aturan sederhana:

Aturan 1: Entitas jadi tabel

Tiap kotak entitas di ERD menjadi satu tabel beneran. Primary Key (PK) tetap jadi kunci utama tabel. Contoh: entitas USERS jadi tabel users.

Aturan 2: Many-to-Many dipecah jadi tabel perantara

Hubungan Banyak-ke-Banyak tidak bisa langsung dibuat di database relasional. Jadi dipecah jadi tabel baru di tengah:
- PRODUCTS }o--o{ ORDERS dipecah jadi ORDER_ITEMS (simpan product_id + order_id + qty + price_at_purchase + is_bonus_item).
- PRODUCTS }o--o{ CARTS dipecah jadi CART_ITEMS.

Aturan 3: One-to-Many pakai Foreign Key

Kunci dari sisi "satu" dipindah jadi kolom Foreign Key (FK) di sisi "banyak". Contoh: users.id dipindah jadi orders.user_id.

Aturan 4: One-to-One pakai UNIQUE

Untuk ORDERS ke PAYMENTS dan SHIPMENTS, kolom order_id di tabel tujuan diberi constraint UNIQUE supaya benar-benar 1 lawan 1.

2.4 Logical Record Structure (LRS) Fisik

Diagram di bawah adalah bentuk tabel jadi di MySQL lengkap dengan kolom dan Foreign Key-nya.

classDiagram direction LR class USERS { +int id PK string email string phone string name string password_hash string role string reseller_source datetime reseller_since datetime created_at } class CATEGORIES { +int id PK string name string slug } class PRODUCTS { +int id PK int category_id FK string name string sku decimal price_retail decimal price_reseller decimal hpp int stock int weight_grams boolean is_excluded_from_paket_usaha string dimensions_cm boolean is_active } class PAKET_USAHA { +int id PK string code string name decimal price_flat int required_qty int bonus_qty string description boolean is_active } class CARTS { +int id PK int user_id FK string session_token string cart_type int paket_usaha_id FK datetime expires_at } class CART_ITEMS { +int id PK int cart_id FK int product_id FK int qty boolean is_bonus } class ORDERS { +int id PK string order_no int user_id FK string order_type int paket_usaha_id FK decimal subtotal decimal shipping_cost decimal total_amount string status string snap_token datetime created_at datetime paid_at } class ORDER_ITEMS { +int id PK int order_id FK int product_id FK int qty decimal price_at_purchase decimal subtotal_item boolean is_bonus_item } class PAYMENTS { +int id PK int order_id FK string gateway string transaction_id string payment_type string va_number string bank_name decimal gross_amount string status datetime paid_at } class SHIPMENTS { +int id PK int order_id FK string courier string service_type string awb_number string receiver_name string receiver_phone string shipping_address string destination_code decimal shipping_fee string pdf_resi_url string wa_status datetime awb_generated_at datetime wa_sent_at } class STOCK_RESERVATIONS { +int id PK int product_id FK int order_id FK int qty datetime expires_at } USERS "1" --> "0..*" ORDERS : places USERS "1" --> "0..*" CARTS : owns USERS "1" --> "0..*" STOCK_RESERVATIONS : holds CATEGORIES "1" --> "0..*" PRODUCTS : classifies PRODUCTS "1" --> "0..*" CART_ITEMS : referenced_in PRODUCTS "1" --> "0..*" ORDER_ITEMS : referenced_in PRODUCTS "1" --> "0..*" STOCK_RESERVATIONS : locked_in PAKET_USAHA "1" --> "0..*" ORDERS : applies_to PAKET_USAHA "1" --> "0..*" CARTS : applies_to CARTS "1" --> "1..*" CART_ITEMS : contains ORDERS "1" --> "1..*" ORDER_ITEMS : contains ORDERS "1" --> "1" PAYMENTS : receives ORDERS "1" --> "1" SHIPMENTS : generates

2.5 Penjelasan Relasi LRS dan Fungsi Foreign Key (FK)

Foreign Key (FK) adalah kolom yang menunjuk ke tabel lain. Fungsinya supaya data saling terhubung dan tidak berantakan.

TabelFKPenjelasan Sederhana
CATEGORIES → PRODUCTScategory_idMenandai produk masuk kategori apa. Jadi filter "tampilkan Sling Bag saja" tinggal pakai FK ini.
PRODUCTS → CART_ITEMSproduct_idMenghubungkan item di keranjang ke produk aslinya untuk cek stok dan harga.
PRODUCTS → ORDER_ITEMSproduct_idMenyimpan jejak produk yang sudah dibeli beserta harga saat beli (snapshot) agar tidak berubah kalau harga master naik.
PRODUCTS → STOCK_RESERVATIONSproduct_idMengunci stok sementara 15 menit saat checkout supaya tidak rebutan. Kalau tidak dibayar, stok dilepas lagi.
PAKET_USAHA → CARTSpaket_usaha_idMenandai keranjang ini adalah keranjang paket. Sistem jadi tahu harus cek kuota 11 item dan hitung harga flat Rp500rb.
PAKET_USAHA → ORDERSpaket_usaha_idMenandai pesanan ini berasal dari paket usaha. Tanda ini yang memicu webhook untuk ubah role jadi RESELLER.
USERS → ORDERSuser_idMenandai pesanan milik siapa, sekaligus menentukan harga retail atau reseller yang dipakai.
ORDERS → PAYMENTSorder_id UNIQUESatu pesanan satu pembayaran Midtrans. Dipakai webhook untuk update status lunas.
ORDERS → SHIPMENTSorder_id UNIQUESatu pesanan satu resi J&T dan satu PDF struk thermal.

BAB III — PERANCANGAN SISTEM

Bab ini menjelaskan bagaimana sistem bekerja dari sisi pengguna dan alur antar komponen. Ada Use Case (siapa bisa apa), Activity Diagram (alur langkah), dan Sequence Diagram (urutan komunikasi antar sistem).

3.1 Use Case Diagram

Use Case menunjukkan aktor (siapa) dan apa yang bisa mereka lakukan di sistem.

flowchart LR subgraph Aktor_Pengguna [Aktor Pengguna] GUST((Customer Guest)) RESL((Reseller)) ADMN((Admin)) end subgraph Aktor_Sistem [Sistem Eksternal] MID((Midtrans)) JNT((J&T Express)) WAG((WhatsApp)) end subgraph Sistem_Nalala [Sistem Nalala Store] UC01([UC01: Lihat Katalog dan Cek Kapasitas]) UC02([UC02: Belanja Reguler]) UC03([UC03: Beli Paket Usaha dan Bonus]) UC04([UC04: Checkout dan Bayar]) UC05([UC05: Webhook Pembayaran]) UC06([UC06: Upgrade Reseller Otomatis]) UC07([UC07: Buat Resi J&T]) UC08([UC08: Cetak PDF Thermal 58mm]) UC09([UC09: Kirim WA Notifikasi]) UC10([UC10: Kelola Produk dan HPP]) UC11([UC11: Atur Paket Usaha]) UC12([UC12: Pantau Pesanan]) end GUST --> UC01 GUST --> UC02 GUST --> UC03 GUST --> UC04 RESL --> UC01 RESL --> UC02 RESL --> UC04 ADMN --> UC10 ADMN --> UC11 ADMN --> UC12 MID --> UC05 UC05 -.->|include| UC06 UC05 -.->|include| UC07 UC07 -.->|include| UC08 UC08 -.->|include| UC09 UC07 --- JNT UC09 --- WAG UC04 --- MID

3.2 Spesifikasi Use Case

Di bawah adalah contoh paling penting: UC-03 (Beli Paket Usaha). Penjelasan dibuat singkat dan mudah dipahami.

BagianIsi
KodeUC-03: Beli Paket Usaha dan Dapat Bonus
AktorCustomer Guest
Syarat awalAda paket aktif di database (misal Paket A 11+1 Rp500.000).
Hasil akhirKeranjang jadi pesanan, stok dikunci 15 menit, token Midtrans siap dibayar.
Alur utama1. Buka halaman Paket Usaha.
2. Sistem tampilkan produk yang boleh ikut paket (non-HPP tinggi).
3. Pembeli pilih 11 tas.
4. Sistem cek jumlah harus pas 11.
5. Sistem otomatis tambahkan 1 tas bonus acak Rp0 yang terkunci.
6. Input alamat.
7. Sistem buatkan token bayar Midtrans.
Jika gagal4a. Jika belum 11, tombol lanjut tidak aktif.
5a. Jika stok bonus habis, sistem cari bonus lain yang stoknya ada.
7a. Jika stok rebutan, sistem balas HTTP 409.

3.3 Activity Diagram

Activity Diagram menggambarkan langkah demi langkah seperti flowchart, tapi fokus ke alur kerja sistem.

Diagram 1: Belanja Reguler dan Capacity Checker

flowchart TD A([Mulai]) --> B[Buka Halaman Produk] B --> C[Lihat Ukuran Tas] C --> D{Pakai Capacity Checker?} D -->|Ya| E[Pilih Barang / Input Ukuran] E --> F[Sistem Hitung Volume] F --> G{Muat?} G -->|Overload| H[Tampilkan Warning] H --> I[Masuk Keranjang] G -->|Muat| I D -->|Tidak| I I --> J{Cek Role User} J -->|RESELLER| K[Pakai Harga Reseller] J -->|GUEST| L[Pakai Harga Retail] L --> M[Tampilkan Pop-up Paket Usaha] K --> N[Ke Checkout] M --> N N --> O[Input Alamat untuk Ongkir J&T] O --> P[Bayar via Midtrans] P --> Q([Selesai])

Diagram 2: Webhook dan Logistik Otomatis

flowchart TD A([Webhook Midtrans Masuk]) --> B[Cek Signature SHA512] B --> C{Valid?} C -->|Tidak| D[Tolak 401] D --> E([Stop]) C -->|Ya| F[Update Order Jadi PAID] F --> G[Balas HTTP 200 ke Midtrans < 1 detik] G --> H[Jalankan Worker Latar Belakang] subgraph Pipeline Latar Belakang H --> I[Request AWB ke J&T] I --> J{Resi Jadi?} J -->|Ya| K[Simpan AWB ke SHIPMENTS] J -->|Tidak| L[Catat Log Error] K --> M[Render PDF Thermal 58mm] M --> N[Upload PDF dan Dapat URL] N --> O[Kirim WA] O --> P[Kirim Resi ke Pembeli] O --> Q[Kirim PDF ke Admin] P --> R[Update wa_status=SENT] Q --> R end R --> S([Selesai])

3.4 Sequence Diagram

Sequence Diagram menunjukkan urutan kirim pesan antar komponen: siapa hubungi siapa dan kapan.

Sequence: Beli Paket Usaha dan Resolusi Bonus

sequenceDiagram autonumber actor Guest as Customer Guest participant FE as Frontend participant API as Express API participant DB as MySQL participant MID as Midtrans Guest->>FE: Buka Paket Usaha FE->>API: GET /api/paket-usaha/active API->>DB: Ambil paket aktif DB-->>API: Paket A 11+1 Rp500.000 API-->>FE: Kirim data paket FE->>API: GET /api/paket-usaha/catalog API->>DB: Ambil produk non-HPP DB-->>API: List produk eligible API-->>FE: Tampilkan katalog Guest->>FE: Pilih 11 tas FE->>API: POST /api/paket-usaha/checkout Note over API,DB: Kunci Bonus Otomatis API->>DB: Cari 1 bonus acak stok aman DB-->>API: ID bonus API->>DB: Buat order 12 item dan kunci stok 15 menit API->>MID: Minta Snap token MID-->>API: Snap token API-->>FE: Kirim token bayar FE->>Guest: Tampilkan popup Midtrans

Sequence: Webhook Midtrans dan Pipeline Async

sequenceDiagram autonumber participant MID as Midtrans Webhook participant API as Webhook Controller participant ASYNC as Worker Async participant JNT as J&T API participant S3 as Storage participant WA as WhatsApp actor Cust as Pembeli actor Admin as Admin MID->>API: POST /webhooks/midtrans settlement API->>API: Cek signature SHA512 API->>API: Update order=PAID, jika Paket Usaha upgrade RESELLER Note over API,MID: Balas Cepat Biar Tidak Timeout API-->>MID: HTTP 200 OK < 1 detik API-)ASYNC: Jalankan processPaidOrderAsync() Note over ASYNC,WA: Proses Latar Belakang ASYNC->>JNT: Buat AWB JNT-->>ASYNC: Nomor resi ASYNC->>ASYNC: Render PDF 58mm ASYNC->>S3: Upload PDF S3-->>ASYNC: URL PDF par Kirim WA ASYNC->>WA: Kirim resi ke pembeli WA-->>Cust: WA diterima and Kirim PDF Admin ASYNC->>WA: Kirim PDF ke admin WA-->>Admin: PDF diterima end ASYNC->>ASYNC: Update wa_status=SENT

BAB IV — PENGUJIAN SISTEM

Bab ini membuktikan sistem berjalan benar lewat dua cara: White Box (cek logika dalam kode) dan Black Box (cek dari sisi pengguna tanpa lihat kode).

4.1 White Box Testing

Fungsi yang diuji adalah processOrderPaymentLogic() — fungsi yang menentukan status pesanan setelah webhook Midtrans masuk.

Pseudocode

1: function processOrderPaymentLogic(orderData, tStatus, fStatus) {
2:   if (tStatus === "settlement") {
3:     if (fStatus === "accept") {
4:       orderData.status = "PAID";
5:       orderData.paid_at = generateCurrentTime();
6:       if (orderData.type === "PAKET_USAHA") {
7:         executeRoleElevation(orderData.user_id, "RESELLER");
8:         writeAuditLogReseller(orderData.user_id);
9:       }
10:      triggerAsynchronousLogistics(orderData.id);
11:      return "STATUS_SUCCESS_FINAL";
12:    } else {
13:      orderData.status = "CHALLENGE_HELD";
14:      return "STATUS_FRAUD_HELD";
15:    }
16:  } else if (tStatus === "expire") {
17:    orderData.status = "EXPIRED";
18:    executeRevertStockReservations(orderData.id);
19:    return "STATUS_RELEASED_EXP";
20:  } else {
21:    orderData.status = "PENDING_AWAIT";
22:    return "STATUS_NO_ACTION";
23:  }
24: }

Flow Graph

flowchart TD N1((1 Mulai)) --> N2{2 Settlement?} N2 -->|Ya| N3{3 Fraud Accept?} N2 -->|Tidak| N16{16 Expire?} N3 -->|Ya| N4[4-5 Set PAID] N3 -->|Tidak| N13[13-14 Set CHALLENGE] N13 --> N24((24 Selesai)) N4 --> N6{6 Paket Usaha?} N6 -->|Ya| N7[7-9 Upgrade RESELLER] N6 -->|Tidak| N10[10 Trigger Logistik] N7 --> N10 N10 --> N11[11 Return SUCCESS] N11 --> N24 N16 -->|Ya| N17[17-19 Set EXPIRED Lepas Stok] N16 -->|Tidak| N21[21-22 Set PENDING] N17 --> N24 N21 --> N24

Cyclomatic Complexity

Rumus: V(G) = P + 1, P = jumlah titik keputusan (predicate node). Ditemukan 4 titik (Node 2, 3, 6, 16). Jadi V(G) = 4 + 1 = 5. Artinya butuh 5 jalur uji berbeda untuk cover semua kemungkinan.

Tabel Kasus Uji White Box

WB-01 sampai WB-05 adalah 5 jalur utama. WB-06 dan WB-07 tambahan untuk cek ketahanan.

KodeJalur (Node)InputHasil HarapanReturnStatus
WB-011-2-3-4-6-7-10-11-24
Settlement accept paket usaha
settlement, accept, PAKET_USAHAPAID, jadi RESELLER, logistik jalanSUCCESS_FINALPass
WB-021-2-3-4-6-10-11-24
Settlement accept reguler
settlement, accept, REGULERPAID, tetap GUEST, logistik jalanSUCCESS_FINALPass
WB-031-2-3-13-24
Settlement challenge
settlement, challengeCHALLENGE_HELD, tidak kirim resiFRAUD_HELDPass
WB-041-2-16-17-24
Expire
expireEXPIRED, stok dikembalikanRELEASED_EXPPass
WB-051-2-16-21-24
Pending
pendingPENDING_AWAIT, tidak ada perubahanNO_ACTIONPass
WB-061-2-16-21-24
Status tidak dikenal
denyTidak crash, masuk PENDINGNO_ACTIONPass
WB-071-2-3-4-6-7-10-11-24
Webhook dikirim 2x (idempoten)
settlement 2x order samaYang kedua diabaikan, tidak duplikat upgradeSUCCESS lalu NO_ACTIONPass

4.2 Black Box Testing

Black Box cek dari sisi luar: input apa, output apa, tanpa lihat kode dalam. Teknik yang dipakai EP (bagi input jadi kelompok valid/tidak valid) dan BVA (cek nilai batas).

KodeTeknikSkenarioData UjiHasil HarapanStatus
BB-01EP ValidHarga reseller mulai 1 pcs tanpa minimalRESELLER qty=1Subtotal pakai price_resellerPass
BB-02EP ValidHarga retail untuk GUEST + pop-up paketGUEST qty=1Pakai price_retail, pop-up muncul 1x per sesiPass
BB-03EP ValidUpgrade RESELLER permanen setelah paket lunasPaket A lunas settlementRole GUEST jadi RESELLER, reseller_since terisiPass
BB-04EP ValidKuota 11 item dapat 1 bonus terkunciPilih 11 produkOrder jadi 12 baris, 1 bonus Rp0 flag is_bonus=truePass
BB-05BVAKuota kurang/lebih ditolakqty 10 dan 12 (batas 11)Tombol checkout mati, pesan "harus tepat 11"Pass
BB-06EP ValidProduk HPP tinggi disaring dari paketis_excluded=trueTidak muncul di katalog paket, tetap ada di regulerPass
BB-07EP ValidFallback bonus jika stok habisBonus stok 0Sistem pilih bonus lain stok terbanyakPass
BB-08EP ValidCapacity Checker muatVolume 80%Status MUAT, langsung masuk keranjangPass
BB-09BVACapacity Checker overloadRasio 100% dan 120%Muncul warning, harus konfirmasi duluPass
BB-10BVAValidasi dimensi Capacity Checker0,1,100,101,9999 cm0,101,9999 ditolak, 1 dan 100 diterimaPass
BB-11EP InvalidRebutan stok terakhir2 user stok 1 bersamaanSatu sukses, satu dapat 409 ConflictPass
BB-12EP ValidOrder expired lepas stokTidak bayar 15 menitEXPIRED, stok balik, tetap GUESTPass
BB-13EP ValidOngkir J&T ditanggung pembeliJ&T REGshipping_cost masuk totalPass
BB-14EP ValidPipeline async: AWB, PDF, WASettlement acceptAWB terisi, PDF tersimpan, WA terkirim SENTPass
BB-15EP InvalidSignature webhook salahSHA512 salahDitolak 401, tidak ubah orderPass
BB-16EP InvalidEmail duplikat dan login salahEmail sama, password salah409 dan 401, tidak dapat JWTPass

BAB V — PENUTUP

5.1 Arsitektur Sistem

Sistem dibagi 4 lapisan supaya rapi dan mudah dirawat. Frontend hanya tampilkan data, backend yang atur logika, database simpan data, dan gateway eksternal untuk bayar dan kirim.

graph TB subgraph Tier_Klien [1. Client] FE[Storefront Next.js 15 React Tailwind] ADMIN[Admin Dashboard React SPA] end subgraph Tier_Backend [2. Backend Node.js Express] API[REST API JWT Zod Rate Limiter] SVC_PAKET[Paket Usaha Engine] SVC_WH[Webhook Handler] NATIVE_ASYNC[Native Async Worker] end subgraph Tier_Data [3. Data] MYSQL[(MySQL 8.0 Prisma)] S3[(Storage PDF Thermal 58mm)] end subgraph Tier_Eksternal [4. Gateway Eksternal] MID[Midtrans VA QRIS] JNT[J&T EzShip AWB Tarif] WA[WhatsApp Fonnte] end FE -->|REST JSON| API ADMIN -->|REST JSON| API API --> SVC_PAKET API --> SVC_WH SVC_PAKET --> MYSQL SVC_WH --> MYSQL SVC_WH -->|Trigger| NATIVE_ASYNC NATIVE_ASYNC -->|Simpan AWB| MYSQL NATIVE_ASYNC -->|1. Buat Resi| JNT NATIVE_ASYNC -->|2. Upload PDF| S3 NATIVE_ASYNC -->|3. Kirim WA| WA API -->|Snap Token| MID MID -->|Webhook POST| SVC_WH

5.2 Rekomendasi Teknologi

KomponenTeknologiAlasan Pilih
FrontendNext.js 15, React, TailwindCepat, SEO friendly, styling praktis
BackendNode.js + ExpressRingan, banyak library, cocok untuk async
DatabaseMySQL 8.0 + Prisma ORMStabil, migrasi mudah, type-safe
PembayaranMidtrans SnapMendukung VA dan QRIS, webhook jelas
PengirimanJ&T Express EzShipAPI tarif dan AWB tersedia
NotifikasiWhatsApp Gateway (Fonnte)Jangkauan luas, format PDF bisa dikirim
PDFpdf-libRender thermal 58mm di server tanpa dependensi berat
ValidasiZod + JWTValidasi input ketat dan auth aman berbasis role

5.3 Kesimpulan

  1. Sistem berhasil mengotomatiskan upgrade reseller lewat Paket Usaha. Guest yang beli paket dan lunas otomatis jadi RESELLER permanen tanpa verifikasi manual.
  2. Masalah rebutan stok diatasi dengan transaksi atomik dan kunci stok sementara 15 menit. Pengujian membuktikan satu transaksi sukses dan yang lain dapat 409 Conflict.
  3. Capacity Checker membantu pembeli cek muat tidaknya barang dengan peringatan overload yang jelas.
  4. Pipeline async setelah webhook (balas 200 dulu, baru buat resi, PDF, dan WA di belakang) membuat sistem tidak timeout dan tetap andal meski API eksternal lambat.
  5. Pengujian White Box V(G)=5 mencapai 100% path coverage dan Black Box 16 kasus semua Pass, menandakan sistem layak untuk dilanjutkan ke tahap implementasi.

5.4 Saran

  1. Tambah variasi paket usaha lain (misal 6+1 atau 20+2) agar lebih fleksibel.
  2. Kembangkan Capacity Checker ke visual 3D sederhana agar lebih mudah dipahami pembeli.
  3. Tambahkan dashboard analitik untuk admin memantau paket paling laku dan stok menipis.
  4. Jika trafik tinggi, pertimbangkan antrean job (BullMQ + Redis) untuk pipeline async agar lebih tahan beban.
  5. Lanjutkan ke penyusunan prisma/schema.prisma dan spesifikasi endpoint API (OpenAPI) sebagai langkah implementasi berikutnya.