Pada 2025, 85% perusahaan B2B menawarkan portal pemasok atau vendor online, naik dari 68% setahun sebelumnya. Kasus bisnis sudah jelas: portal vendor mengurangi biaya pemrosesan AP dengan menghilangkan entri faktur manual, mempercepat siklus pembayaran, dan meningkatkan hubungan pemasok. Untuk perusahaan manufaktur dan dagang Indonesia yang mengelola ratusan vendor — banyak yang masih mengirim faktur PDF melalui email dan menindaklanjuti via WhatsApp — portal vendor adalah peningkatan operasional yang signifikan.
Portal vendor produksi membutuhkan empat kapabilitas inti: pengiriman faktur (vendor mengunggah PDF faktur, memasukkan item baris, memetakan ke PO), pelacakan pembayaran (vendor dapat melihat status pembayaran untuk setiap faktur), manajemen dokumen (vendor memperbarui detail bank, dokumen pajak, sertifikat hukum), dan komunikasi (pesan terstruktur yang terhubung ke PO atau faktur tertentu).
Kami menggunakan aplikasi Next.js yang menghadap vendor terpisah dengan autentikasi tersendiri. Vendor mendaftar dengan NPWP (nomor registrasi pajak Indonesia), nama bisnis, dan email. Admin ERP menyetujui pendaftaran dan menghubungkan akun vendor ke vendor master di ERP. Autentikasi menggunakan JWT dengan kedaluwarsa lebih pendek (4 jam) daripada pengguna internal.
Vendor Portal Architecture
┌─────────────────────┐ ┌─────────────────────────┐
│ Vendor Portal │ │ Internal ERP │
│ (Next.js PWA) │ │ (Next.js + NestJS) │
│ │ │ │
│ 📋 Submit Invoice │ │ 📊 AP Module │
│ 💳 Track Payment │◄───►│ 📦 Purchase Orders │
│ 📄 Docs Upload │ │ ✅ 3-Way Matching │
│ 💬 Messages │ │ 💰 Payment Batches │
└──────────┬──────────┘ └──────────┬──────────────┘
│ Vendor-scoped JWT │
▼ ▼
┌────────────────────────────────────────────────────┐
│ NestJS API (shared) │
│ │
│ VendorGuard: extracts vendor from JWT │
│ → injects vendor_id into every query │
│ → PostgreSQL RLS enforces row-level isolation │
└──────────────────────┬─────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────┐
│ PostgreSQL (RLS enabled on vendor-facing tables) │
│ │
│ vendors │ purchase_orders │ ap_invoices │ payments│
└────────────────────────────────────────────────────┘Dari pengalaman saya membangun sistem ERP di Commsult: berikan portal yang ramah mobile kepada vendor, bukan hanya desktop. Banyak kontak pemasok Indonesia beroperasi terutama di mobile — mereka akan memotret faktur dan mengirimkannya dari ponsel. Kami membangun portal sebagai PWA dengan formulir yang dioptimalkan untuk mobile. Pengambilan foto faktur (dengan konversi PDF otomatis menggunakan pdf-lib) adalah fitur yang paling banyak digunakan di bulan pertama.
Alur pengiriman faktur: vendor memilih PO dari PO terbuka mereka, mengkonfirmasi item baris dan kuantitas yang difakturkan, memasukkan nomor dan tanggal faktur, mengunggah PDF, dan mengirimkan. ERP secara otomatis menjalankan three-way matching: kuantitas faktur vs. kuantitas PO vs. kuantitas penerimaan barang. Jika ketiganya cocok dalam toleransi, faktur disetujui otomatis ke antrian pembayaran. Ini menghilangkan 80% pekerjaan pencocokan AP manual.
Vendor dapat melihat pelacak pembayaran untuk setiap faktur: dikirim, dalam peninjauan, disetujui, pembayaran dijadwalkan (dengan perkiraan tanggal pembayaran), dan dibayar (dengan referensi transfer bank). Visibilitas ini hampir sepenuhnya menghilangkan panggilan 'kapan saya akan dibayar?' ke tim AP.
-- PostgreSQL: Row-Level Security for vendor portal
-- Vendors can ONLY see their own data
ALTER TABLE purchase_orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE ap_invoices ENABLE ROW LEVEL SECURITY;
ALTER TABLE payments ENABLE ROW LEVEL SECURITY;
-- Policy: vendor can only see their own POs
CREATE POLICY vendor_po_isolation ON purchase_orders
USING (vendor_id = current_setting('app.vendor_id')::UUID);
CREATE POLICY vendor_invoice_isolation ON ap_invoices
USING (vendor_id = current_setting('app.vendor_id')::UUID);
-- NestJS: Set vendor context before every query
@Injectable()
export class VendorContextMiddleware implements NestMiddleware {
async use(req: Request, res: Response, next: NextFunction) {
const vendor = req.user as VendorJwtPayload;
if (vendor?.vendorId) {
// Set PostgreSQL session variable for RLS
await this.dataSource.query(
"SELECT set_config('app.vendor_id', $1, true)",
[vendor.vendorId]
);
}
next();
}
}
// 3-way matching on invoice submission
async validateInvoiceAgainstPo(dto: SubmitInvoiceDto) {
const po = await this.poRepo.findOneOrFail(dto.poId);
const gr = await this.grRepo.findByPoId(dto.poId);
const grQty = gr.reduce((sum, r) => sum + r.quantity, 0);
const tolerance = 0.02; // 2% tolerance
for (const line of dto.lines) {
const poLine = po.lines.find(l => l.itemId === line.itemId);
if (!poLine) throw new BadRequestException(`Item ${line.itemId} not on PO`);
if (Math.abs(line.quantity - poLine.quantity) / poLine.quantity > tolerance) {
return { status: 'DISCREPANCY', requiresReview: true };
}
}
return { status: 'MATCHED', autoApprove: true };
}Portal vendor adalah aplikasi Next.js terpisah yang memanggil API NestJS yang sama dengan ERP internal, tetapi dengan kunci API yang dibatasi vendor. Modul vendor NestJS memberlakukan vendor_id pada setiap query menggunakan guard kustom yang mengekstrak vendor dari JWT dan menyuntikkannya ke setiap panggilan service.
Portal vendor berisi data keuangan sensitif — jumlah pembayaran, detail rekening bank, dokumen pajak. Row-level security di PostgreSQL harus memastikan setiap vendor hanya dapat melihat data mereka sendiri. Kami memiliki implementasi awal di mana endpoint API yang salah konfigurasi mengembalikan status pembayaran semua vendor jika parameter vendor_id dimanipulasi. Selalu gunakan kebijakan RLS PostgreSQL pada tabel yang menghadap vendor.
Regulasi pengadaan Indonesia mengharuskan vendor mempertahankan sertifikat PKP (Pengusaha Kena Pajak), NPWP, SIUP (izin usaha), dan untuk beberapa sektor, sertifikasi ISO atau SNI yang masih berlaku. Portal kami memungkinkan vendor mengunggah dan memperbarui dokumen-dokumen ini. ERP melacak tanggal kedaluwarsa dan menandai vendor yang dokumennya akan kedaluwarsa dalam 30 atau 60 hari.
Enam bulan setelah meluncurkan portal vendor untuk klien kami, peningkatan terukur meliputi: waktu pemrosesan AP per faktur turun dari 45 menit menjadi 8 menit, panggilan pertanyaan pembayaran vendor turun 65%, tingkat pembayaran tepat waktu meningkat dari 72% menjadi 91%, dan waktu onboarding vendor berkurang dari 5 hari menjadi 1 hari. CFO klien menyebutnya 'modul tunggal paling berdampak yang kami deploy.'