Backend Architecture

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

How I designed and engineered a complex transactional API in Nest.js to orchestrate ministry-level tender lifecycles from end to end under high concurrent loads.

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

Executive Summary

Ministry-level government procurement (E-Procurement) systems demand strict data integrity, tight security auditing, and resilience to process thousands of technical and financial bids simultaneously right before the submission deadline (tender submission deadline).

At GeekGarden Software House, I was the Lead Backend Developer responsible for designing and engineering the Ministry E-Procurement API using Nest.js & PostgreSQL. The system was designed to orchestrate 6 transactional phases of the tender lifecycle, ensuring data protection against manipulation and high performance under concurrent load.


Tender Lifecycle Orchestration

The procurement cycle is divided into 6 coordinated stages managed through a transactional PostgreSQL backend:

graph TD
    subgraph Tender_Lifecycle [Procurement Lifecycle]
        Invite[1. Vendor Invitation <br> Vendor onboarding & qualification] --> Register[2. Tender Registration <br> Registering interest in bid]
        Register --> Upload[3. Document Verification <br> Uploading technical & financial files]
        Upload --> Submit[4. Secure Tender Submission <br> Encrypted bid locking]
        Submit --> Aanwijzing[5. Aanwijzing Clarification <br> Q&A forum clarification]
        Aanwijzing --> Award[6. Selection & Funding <br> Winner award & milestone tracking]
    end

    style Tender_Lifecycle fill:#f5f5f5,stroke:#aaa,stroke-width:1px
    style Submit fill:#bfb,stroke:#333,stroke-width:1px
  1. Secure Tender Submission (Critical Phase): Vendor bids (including pricing sheets) are uploaded and encrypted on the server side. SHA-256 hashes of the files are recorded in an audit table to guarantee that documents cannot be altered (tamper-proof) by internal committees before the public opening date.

Concurrency Control & Database Locking (Pessimistic Locking)

The primary engineering challenge occurred during the Tender Submission phase. Hundreds of vendors uploaded files simultaneously within minutes of the deadline. This concurrent traffic created race conditions when generating sequential receipt numbers (bid sequence numbers), causing database transactions to abort due to unique key violations.

To solve this, I implemented isolated transactions with Pessimistic Locking (SELECT ... FOR UPDATE) on PostgreSQL queries using TypeORM in Nest.js. This ensured that only a single database thread could update or append the sequence count for a specific tender at a time:

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> {
    // Run the sequence generation within an isolated transaction block
    return await this.dataSource.transaction(async (entityManager: EntityManager) => {
      
      // 1. Lock the Tender row to prevent other concurrent threads from updating it
      const tender = await entityManager
        .createQueryBuilder(Tender, 'tender')
        .setLock('pessimistic_write') // Generates SQL: SELECT ... FOR UPDATE
        .where('tender.id = :tenderId', { tenderId })
        .getOne();

      if (!tender) {
        throw new Error('Tender not found');
      }

      if (new Date() > tender.submissionDeadline) {
        throw new Error('Tender submission window has closed');
      }

      // 2. Resolve the next bid receipt sequence number
      const currentCount = await entityManager.count(BidReceipt, {
        where: { tenderId }
      });
      const nextSequence = currentCount + 1;

      // 3. Save the bid receipt alongside its sequence number
      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 for 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');
  }
}

By enforcing this pessimistic lock, the application guarantees that sequence numbers are generated without database conflicts, eliminating transaction aborts during last-minute rushes.


PostgreSQL Performance Tuning

In addition to handling race conditions, I tuned the PostgreSQL database to withstand heavy read queries during the tender winner announcement stage:

  • Composite Indexing: Created indexes on highly queried filter fields: CREATE INDEX idx_tenders_status_date ON tab_tenders (status, submission_deadline DESC).
  • Database Connection Pooling: Configured connection pool limits in Nest.js to align with PostgreSQL RAM resources, preventing connection timeouts during traffic spikes.

Business Impact & Results

  • High Availability & Resilience: Successfully handled extreme traffic surges of 10k+ concurrent requests without any lost bids or aborted transactions.
  • Latency Reduction: Cut database operational response times by 60% (reducing average transaction latency from 800ms to 320ms).
  • Government Compliance: Enforced SHA-256 cryptographic hashing to ensure that all bid documents were immutable, meeting the transparency requirements of Indonesian government audit bodies.