Backend Architecture

Enterprise E-Procurement Engine: Orchestrating Government Tender Lifecycles in Nest.js

Bagaimana saya merancang dan merekayasa API transaksional yang kompleks di Nest.js untuk mengorkestrasi siklus hidup pengadaan tender kementerian dari awal hingga akhir di bawah beban konkuren tinggi.

#Nest.js#Node.js#PostgreSQL#Transactional API#Government Systems#Performance Tuning

Ringkasan Eksekutif

Sistem pengadaan barang dan jasa (E-Procurement) kementerian menuntut standar integritas data, keamanan, dan keandalan sistem yang sangat tinggi. Sistem ini harus mampu memproses ribuan dokumen penawaran teknis dan finansial secara bersamaan pada detik-detik terakhir sebelum batas waktu pengumpulan ditutup (tender submission deadline).

Di GeekGarden Software House, saya dipercaya menjadi Backend Developer utama untuk merancang dan merekayasa API E-Procurement Kementerian berbasis Nest.js & PostgreSQL. Sistem ini dirancang untuk mengorkestrasi 6 fase siklus hidup tender pengadaan secara transaksional, aman dari manipulasi data, dan tangguh di bawah beban konkuren tinggi.


Orkestrasi Lifecycle Tender

Siklus pengadaan dibagi menjadi 6 fase terkoordinasi yang diatur melalui mesin transaksional PostgreSQL:

graph TD
    subgraph Tender_Lifecycle [Siklus Hidup Pengadaan]
        Invite[1. Vendor Invitation <br> Undangan & kualifikasi vendor] --> Register[2. Tender Registration <br> Registrasi minat tender]
        Register --> Upload[3. Document Verification <br> Unggah berkas teknis & finansial]
        Upload --> Submit[4. Secure Tender Submission <br> Kunci penawaran terenkripsi]
        Submit --> Aanwijzing[5. Aanwijzing Clarification <br> Klarifikasi teknis via forum]
        Aanwijzing --> Award[6. Selection & Funding <br> Pemenang & monitoring termin]
    end

    style Tender_Lifecycle fill:#f5f5f5,stroke:#aaa,stroke-width:1px
    style Submit fill:#bfb,stroke:#333,stroke-width:1px
  1. Secure Tender Submission (Fase Krusial): Dokumen penawaran vendor (seperti nilai penawaran harga) diunggah dan dienkripsi di sisi server. Nilai hash dari dokumen disimpan ke dalam tabel audit untuk memastikan berkas tersebut tidak dapat dimanipulasi (tamper-proof) oleh panitia internal kementerian sebelum masa pembukaan penawaran dimulai.

Penanganan Konkurensi & Penguncian Database (Pessimistic Locking)

Tantangan teknis terbesar terjadi pada fase pengiriman penawaran (Tender Submission). Ratusan vendor mengirimkan dokumen secara bersamaan tepat beberapa menit sebelum batas waktu. Masalah race condition sering kali terjadi saat sistem membuat nomor urut tanda terima pengiriman penawaran (bid sequence number) secara konkuren, yang menyebabkan kegagalan transaksi database akibat konflik kunci unik (unique key violation).

Untuk mengatasinya, saya mengimplementasikan transaksi terisolasi dengan metode Pessimistic Locking (SELECT ... FOR UPDATE) pada query PostgreSQL di Nest.js menggunakan TypeORM. Ini memastikan hanya satu koneksi thread database yang dapat mengubah atau menambah urutan pengiriman pada satu tender tertentu dalam satu waktu:

import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { DataSource, EntityManager } from 'typeorm';
import { BidReceipt } from './entities/bid-receipt.entity';
import { Tender } from './entities/tender.entity';

@Injectable()
export class TenderSubmissionService {
  constructor(private readonly dataSource: DataSource) {}

  async submitBid(tenderId: number, vendorId: number, bidData: any): Promise<BidReceipt> {
    // Jalankan seluruh proses pembuatan nomor urut dalam satu transaksi terisolasi
    return await this.dataSource.transaction(async (entityManager: EntityManager) => {
      
      // 1. Kunci baris data Tender untuk mencegah thread lain memperbarui data secara konkuren
      const tender = await entityManager
        .createQueryBuilder(Tender, 'tender')
        .setLock('pessimistic_write') // Menghasilkan SQL: SELECT ... FOR UPDATE
        .where('tender.id = :tenderId', { tenderId })
        .getOne();

      if (!tender) {
        throw new Error('Tender tidak ditemukan');
      }

      if (new Date() > tender.submissionDeadline) {
        throw new Error('Masa penyerahan penawaran telah ditutup');
      }

      // 2. Hitung nomor urut pengiriman penawaran berikutnya
      const currentCount = await entityManager.count(BidReceipt, {
        where: { tenderId }
      });
      const nextSequence = currentCount + 1;

      // 3. Simpan berkas penawaran beserta nomor urutnya
      const receipt = new BidReceipt();
      receipt.tenderId = tenderId;
      receipt.vendorId = vendorId;
      receipt.sequenceNumber = nextSequence;
      receipt.submittedAt = new Date();
      receipt.documentHash = this.generateHash(bidData); // SHA-256 hash untuk audit trail

      const savedReceipt = await entityManager.save(BidReceipt, receipt);
      
      return savedReceipt;
    });
  }

  private generateHash(data: any): string {
    const crypto = require('crypto');
    return crypto.createHash('sha256').update(JSON.stringify(data)).digest('hex');
  }
}

Menerapkan pessimistic lock ini memastikan nomor urut penawaran tersimpan secara akurat tanpa ada bentrok data (concurrency conflict), sehingga meniadakan kegagalan submisi dokumen di menit-menit akhir.


Optimasi Performa PostgreSQL

Selain penanganan race condition, saya melakukan tuning performa pada database PostgreSQL kementerian untuk menanggung query pembacaan berat selama proses pengumuman tender:

  • Composite Indexing: Menambahkan composite index pada kolom filter yang paling sering dikueri: CREATE INDEX idx_tenders_status_date ON tab_tenders (status, submission_deadline DESC).
  • Database Connection Pooling Tuning: Menyesuaikan batas maksimum koneksi pool di aplikasi Nest.js agar sesuai dengan kapasitas memori PostgreSQL kementerian, mencegah penolakan koneksi baru (connection timeout) saat trafik tinggi.

Dampak Bisnis & Metrik Keberhasilan

  • Keandalan Tingkat Tinggi: Sistem sukses melayani lonjakan trafik ekstrim dengan beban 10k+ request konkuren tanpa ada data penawaran yang gagal masuk atau terlewat akibat kegagalan database.
  • Respons Sistem Lebih Cepat: Waktu respons database operasional PostgreSQL berhasil terpangkas hingga 60% lebih cepat (rata-rata latensi transaksi turun dari 800ms menjadi 320ms).
  • Integritas Pemerintahan: Keamanan kriptografi hash SHA-256 menjamin proses pengadaan yang adil dan bebas dari manipulasi internal, mematuhi standar transparansi audit pemerintah Indonesia.