Pada 2025, 85% perusahaan B2B menawarkan portal pelanggan online, naik dari 68% tahun sebelumnya. Perusahaan yang mengadopsi saluran B2B digital melaporkan rata-rata peningkatan pendapatan penjualan 41%. Untuk bisnis B2B Indonesia yang melayani klien korporat, portal pelanggan mengubah proses pemesanan via email dan telepon menjadi pengalaman swalayan yang berkembang tanpa pertumbuhan headcount yang proporsional.
Portal pelanggan B2B bukan toko ecommerce. Klien B2B membutuhkan: memesan berdasarkan daftar harga yang dinegosiasikan, melacak status pesanan dan pengiriman secara real-time, mengakses dan membayar faktur mereka, melihat riwayat transaksi mereka, dan berkomunikasi tentang pesanan tertentu.
Dalam B2B Indonesia, setiap klien utama memiliki daftar harga yang dinegosiasikan. Portal kami membaca harga dari tabel customer_price_list ERP: setiap klien memiliki price list ID, dan ketika mereka menelusuri produk, mereka melihat harga kontrak mereka, bukan harga publik. Portal juga menampilkan batas kredit tersedia dan saldo outstanding mereka saat ini.
B2B Customer Portal Architecture
Customer (browser / mobile)
│
▼
┌─────────────────────────────────┐
│ Next.js Customer Portal │ (deployed: Vercel)
│ │
│ 🛒 Place Order (vs. price list)│
│ 📦 Track Shipment Status │
│ 🧾 View & Pay Invoices │
│ 📄 Download e-Faktur PDF │
└──────────────┬──────────────────┘
│ customer-scoped JWT
▼
┌─────────────────────────────────┐
│ NestJS API (shared) │
│ │
│ CustomerGuard → customer_id │
│ PostgreSQL RLS enforcement │
│ │
│ /pricing → customer_price_list │
│ /orders → sales_orders │
│ /invoices → ar_invoices │
│ /pay → Midtrans gateway │
└──────────────┬──────────────────┘
│
┌──────────────┴──────────────────┐
│ Internal ERP (Next.js) │
│ Sales Order sync ↔ portal │
│ Shipment updates → portal │
│ Invoice status → portal │
└─────────────────────────────────┘Dari pengalaman saya membangun sistem ERP di Commsult: bangun pemeriksaan kredit di tingkat API, bukan hanya frontend. Kami memiliki implementasi awal di mana pemeriksaan batas kredit hanya ada di UI React — klien yang canggih dapat melewatinya dengan memanggil API langsung. Selalu paksakan aturan bisnis (batas kredit, minimum kuantitas pesanan, produk terbatas) di lapisan NestJS service.
Alur pesanan: pelanggan membuat pesanan di portal → pesanan disinkronkan ke ERP sebagai Sales Order → staf gudang ERP memilih dan mengirim → pembaruan pengiriman mengalir kembali ke portal → pelanggan melihat status real-time. Sinkronisasi bidireksional ini adalah tantangan integrasi inti.
Klien B2B perlu mengunduh dokumen: faktur pajak (PDF e-Faktur untuk rekonsiliasi PPN), Surat Jalan (untuk proses penerimaan barang mereka), dan Sertifikat Analisis untuk pemasok bahan baku. Semua ini dihasilkan di ERP dan disimpan dalam object storage dengan signed URL. Portal mengekspos pusat dokumen per pesanan dan per faktur.
// NestJS: Midtrans webhook handler (idempotent)
@Post('/webhooks/midtrans')
async handleMidtransWebhook(@Body() body: MidtransNotification) {
// 1. Validate Midtrans signature
const expectedSig = crypto
.createHash('sha512')
.update(body.order_id + body.status_code + body.gross_amount
+ process.env.MIDTRANS_SERVER_KEY)
.digest('hex');
if (expectedSig !== body.signature_key) {
throw new UnauthorizedException('Invalid webhook signature');
}
// 2. Idempotency check — skip if already processed
const alreadyProcessed = await this.paymentRepo.existsByMidtransId(
body.transaction_id
);
if (alreadyProcessed) {
return { message: 'Already processed — skipping' };
}
// 3. Only process successful payments
if (body.transaction_status === 'settlement'
|| body.transaction_status === 'capture') {
await this.arService.recordPayment({
invoiceId: body.order_id.replace('INV-', ''),
amount: parseFloat(body.gross_amount),
paymentDate: new Date(body.settlement_time),
reference: body.transaction_id,
method: body.payment_type,
});
}
return { message: 'OK' };
}Portal pelanggan adalah aplikasi Next.js terpisah yang diautentikasi melalui JWT khusus pelanggan. API NestJS memiliki konteks pelanggan yang membatasi setiap query ke data pelanggan yang terautentikasi — semua pesanan, faktur, dan pengiriman difilter berdasarkan customer_id di tingkat database menggunakan Row Level Security PostgreSQL.
Daftar harga pelanggan berubah — kontrak baru ditandatangani, harga promosi berakhir, biaya produk berubah. Jika Anda meng-cache daftar harga di lapisan aplikasi portal (misalnya di Redis untuk performa), Anda harus membatalkan cache ketika daftar harga diperbarui di ERP. Kami mengalami insiden memalukan di mana klien mendapat harga lama selama satu bulan penuh karena TTL cache diatur 24 jam. Untuk data harga, gunakan TTL yang jauh lebih pendek (maksimal 5 menit).
Kami mengintegrasikan Midtrans (payment gateway terkemuka Indonesia) untuk pembayaran faktur online. Klien dapat membayar faktur outstanding langsung dari portal. Alur pembayaran: klien memilih faktur yang akan dibayar → halaman pembayaran Midtrans terbuka → pada sukses, Midtrans mengirim webhook ke handler pembayaran NestJS → pembayaran dicatat di modul AR → status faktur diperbarui menjadi 'Dibayar'.
Setelah 6 bulan portal pelanggan di klien kami: 73% pesanan ditempatkan melalui portal (naik dari 0%), waktu pemrosesan pesanan rata-rata turun dari 4 jam menjadi 15 menit, dan panggilan layanan pelanggan turun 55%. Metrik yang penting untuk keberhasilan portal B2B: tingkat adopsi portal per akun pelanggan, pesanan melalui portal vs. saluran tradisional, tingkat pembayaran faktur secara online vs. transfer bank, dan waktu dari pesanan ke konfirmasi pesanan ERP.