Files
Isuru Bimsara 81d0e65686 first commit
2026-08-14 22:46:02 +05:30

16 KiB

Document API Documentation

Overview

The Document API allows authenticated users to generate documents asynchronously (PDF, Excel, etc.) from provided data. The system uses a queue-based architecture for reliable, scalable document generation.

Key Features:

  • ✅ Non-blocking requests (returns immediately with jobId)
  • ✅ Job status polling to track progress
  • ✅ Automatic retries with exponential backoff
  • ✅ Support for multiple document types and formats
  • ✅ Concurrent document generation
  • ✅ Case-insensitive document names with whitespace and punctuation normalization

Architecture

Client Request → Queue Job → Return jobId (202)
                    ↓
                  Worker processes
                    ↓
            Client polls status
                    ↓
         Job complete → Download file

Endpoints

1. Generate Document

Endpoint: POST /api/document/generate

URL: http://localhost:3070/api/document/generate

Authentication: Required ✓

Authorization: Required - User must have one of the following roles:

  • admin
  • management
  • team_head
  • user

HTTP Status: 202 Accepted

Request Headers

Content-Type: application/json
Authorization: Bearer <JWT_TOKEN>

Request Body

Field Type Required Description
document string Yes Type of document (e.g., "INVOICE", "DISPATCHNOTE", "DELIVERYNOTE")
documentType string Yes Output format (e.g., "pdf", "excel")
documentData object Yes Data object for the document

Response (202 Accepted)

{
  "success": true,
  "message": "Document generation started",
  "jobId": "1"
}

Error Responses

400 Bad Request:

{
  "success": false,
  "message": "document, documentType, and documentData are required"
}

500 Server Error:


{
    "success": false,
  "message": "Error message describing the issue"
}

Supported Document Values

You can send the document name in any case. Spaces, underscores, and hyphens are ignored by the generator.

  • PRECOST
  • INVOICE
  • DISPATCHNOTE
  • DELIVERYNOTE
  • CUSTOMDOCUMENT
  • CREDITNOTE
  • PO

Sample Request Bodies

All examples below are for POST /api/document/generate with documentType: "pdf".

PreCost

{
  "document": "PRECOST",
  "documentType": "pdf",
  "documentData": {
    "vessel_name": "MV OCEAN STAR",
    "supplyPort": "DUBAI",
    "clientRfqNum": "RFQ-2026-001",
    "omsRfqNum": "OMS-RFQ-0001",
    "date": "08/07/2026",
    "items": [
      {
        "name": "Marine Rope",
        "description": "High strength rope",
        "qty": 10,
        "unitPrice": 12.5
      },
      {
        "name": "Safety Gloves",
        "description": "Blue gloves",
        "qty": 5,
        "unitPrice": 8
      }
    ],
    "sub_total": 125,
    "discount": 0,
    "additionalCharges": 0,
    "total_cost": 125
  }
}

Invoice

{
  "document": "INVOICE",
  "documentType": "pdf",
  "documentData": {
    "jobReference": "JOB-2026-001",
    "poNumber": "PO-20254161",
    "date": "08/07/2026",
    "pageLabel": "Page 01 of 02",
    "billToName": "SUNRICH SHIP CHANDLERS L.L.C",
    "billToAddress": "BUSINESS BAY - ASPECT TOWER, 22ND FLOOR, OFFICE NO. 2201, P.O. BOX NO 39976, DUBAI",
    "vesselName": "MV OCEAN STAR",
    "purposeOfCall": "SUPPLY OF PROVISIONS",
    "supplyDate": "08/07/2026",
    "grt": "12345",
    "imoNumber": "9876543",
    "portCountry": "DUBAI / UAE",
    "items": [
      {
        "description": "Marine rope",
        "remarks": "Delivered as requested",
        "quantity": 10,
        "unit_price": 12.5
      },
      {
        "description": "Safety gloves",
        "remarks": "Blue color",
        "quantity": 5,
        "unit_price": 8
      }
    ],
    "subtotal": 165,
    "tax": 0,
    "discount": 0,
    "total": 165,
    "paymentTerms": "Payment due within 30 days",
    "notes": "Please verify quantities upon delivery."
  }
}

Dispatch Note

{
  "document": "DISPATCHNOTE",
  "documentType": "pdf",
  "documentData": {
    "referenceNumber": "DN/2026/001",
    "date": "08/07/2026",
    "vessel": "MV OCEAN STAR",
    "captain": "CAPT. JOHN DOE",
    "cook": "SAMUEL",
    "agent": "OCEANIC AGENT LTD",
    "details": "Delivery of provisions and stores",
    "placeOfDelivery": "DUBAI PORT",
    "eta": "08/07/2026 08:00",
    "etd": "08/07/2026 18:00",
    "numberOfCrew": 18,
    "nextMainOrderIn": "24 HRS",
    "port": "DUBAI",
    "company": "OCEANIC SHIP CHANDLERS (PVT) LTD",
    "fileNo": "FILE-2026-04",
    "items": [
      {
        "product": "Rice",
        "qty": 10,
        "unit": "BAGS",
        "supp": "OMS",
        "poNo": "PO-001",
        "receivedQty": 10,
        "issuedQty": 10,
        "expDate": "12/07/2026",
        "receivedTime": "09:15",
        "date": "08/07/2026",
        "rejects": "",
        "fatCon": "",
        "remark": "Delivered"
      }
    ],
    "showSignatures": true,
    "preparedBy": "Admin User",
    "approvedBy": "Manager User"
  }
}

Delivery Note

{
  "document": "DELIVERYNOTE",
  "documentType": "pdf",
  "documentData": {
    "referenceNumber": "DN/OSC/2602/01",
    "date": "08/07/2026",
    "billToName": "SUNRICH SHIP CHANDLERS L.L.C",
    "billToAddress": "BUSINESS BAY - ASPECT TOWER, 22ND FLOOR, OFFICE NO. 2201, P.O. BOX NO 39976, DUBAI",
    "supplyDate": "08/07/2026",
    "poNumber": "PO-20254161",
    "items": [
      {
        "description": "Marine rope",
        "remarks": "Delivered as requested",
        "unit": "PCS",
        "quantity": 10
      },
      {
        "description": "Safety gloves",
        "remarks": "Blue color",
        "unit": "BOX",
        "quantity": 5
      }
    ]
  }
}

Custom Document

{
  "document": "CUSTOMDOCUMENT",
  "documentType": "pdf",
  "documentData": {
    "title": "CUSTOM DOCUMENT",
    "date": "08/07/2026",
    "telePhone": "+94 112 083 206",
    "emailAddress": "shipsupply@oceanicmsol.com",
    "officeAddressLine1": "Level 5D, Valiant Towers, Nawala Mawatha",
    "officeAddressLine2": "Colombo 02",
    "officeAddressLine3": "SRI LANKA",
    "directorOfCustoms": "The Director of Customs",
    "vehicleNo": "WPLO 9767",
    "permitNo": "MV20231214006001 / Permit No. MP20240717017006",
    "chiefSecurityOfficer": "Chief Security Officer",
    "exportGate": "Export Gate",
    "slpa": "SLPA",
    "gateNo": "Gate No. 03",
    "permissionText": "Please grant permission to pass these Customs entry papers to supply goods to the vessel",
    "companyName": "Oceanic Maritime Solutions (Pvt) Ltd",
    "subtitle": "LICENSED SHIPCHANDLERS",
    "sectionCode": "SC/FORM/06",
    "items": [
      {
        "quantity": 10,
        "unit": "PCS",
        "description": "Marine rope",
        "rate": 12.5,
        "total": 125,
        "confirmOrderRate": ""
      },
      {
        "quantity": 5,
        "unit": "PCS",
        "description": "Safety gloves",
        "rate": 8,
        "total": 40,
        "confirmOrderRate": ""
      }
    ]
  }
}

Credit Note

{
  "document": "CREDITNOTE",
  "documentType": "pdf",
  "documentData": {
    "companyName": "GREEK-LANKA MARITIME SERVICES (PVT) LTD",
    "companyAddressLine1": "No. 56/2, Dharmapala Mw, Kotte",
    "companyAddressLine2": "Sri Jayewardenepura",
    "companyAddressLine3": "Sri Lanka",
    "companyPostal": "Postal Code : 10100",
    "companyContact": "Tel:+94 11 2083206 / Mobile (24/7) : +94 777 232 271",
    "companyBR": "BR No : PV 0022630",
    "companyLicense": "License No : SA00317-2024",
    "crnNo": "GLMS/COLOMBO/474/CRN01",
    "date": "26/07/2024",
    "billToName": "Master & Owner of MV TEAM VENTURES",
    "billToDetails": "VRIDHI MARITIME SHIP MANAGEMENT & OPERATION LLC\nOffice No: 2004, The Prism Tower, Dubai\n20th Floor, Business Bay,\nDubai - PO Box 29583.",
    "vesselName": "MV \"TEAM VENTURES\"",
    "grt": "25,543 MT",
    "port": "REPAIRS AT COLOMBO DOCK YARD",
    "imoNumber": "9339765",
    "nameOfAgent": "29/04/2024 AT 21:00 HRS.LT",
    "portCountry": "COLOMBO / SRI LANKA",
    "items": [
      {
        "description": "SIGN OFF C/E MR. DHANSINGH BHAURYAL AND M/S J/E MR. SENTHIL",
        "amount": 50
      },
      {
        "description": "VISA + Handling Charges - M/S M/S MR. SENTHIL",
        "amount": 100
      },
      {
        "description": "Transport from Airport to Dockyard",
        "amount": 70
      }
    ],
    "totalAmount": 220,
    "approvedBy": "GLMS Finance Dept.",
    "approvedByLabel": "Approved by GLMS Finance Dept.",
    "departmentLabel": "GLMS - Accounts Department"
  }
}

}


---

### 2. Get Job Status

**Endpoint:** `GET /api/document/job/:jobId/status`

**URL:** `http://localhost:3070/api/document/job/1/status`

**Authentication:** Required ✓

**Authorization:** Required

**HTTP Status:** `200 OK`

#### Request Headers

Authorization: Bearer <JWT_TOKEN>


#### Response (Waiting/Active)

```json
{
  "success": true,
  "jobId": "1",
  "state": "waiting",
  "result": null,
  "error": null,
  "attempts": 0,
  "stacktrace": []
}

Response (Completed)

{
  "success": true,
  "jobId": "83",
  "state": "completed",
  "result": {
    "fileName": "precost-1781614132061.pdf",
    "mimeType": "application/pdf",
    "size": 220008,
    "s3Key": "uploads/16adf29b-c0c2-45f9-8808-d6e15cd3d755.pdf",
    "documentId": "16adf29b-c0c2-45f9-8808-d6e15cd3d755"
  },
  "error": null,
  "attempts": 1,
  "stacktrace": []
}

Response (Failed)

{
  "success": true,
  "jobId": "1",
  "state": "failed",
  "result": null,
  "error": "Error message explaining the failure",
  "attempts": 3,
  "stacktrace": ["stack trace line 1", "stack trace line 2"]
}

Job States

State Meaning Next State
waiting Job queued, waiting for worker active
active Worker currently processing completed or failed
completed Job done, result available (final)
failed Job failed after 3 retries (final)
delayed Scheduled for later processing waiting

Error Responses

404 Not Found:

{
  "success": false,
  "message": "Job not found"
}

3. Download Document

Endpoint: GET /api/document/download/:uuid

URL: http://localhost:3070/api/document/download/16adf29b-c0c2-45f9-8808-d6e15cd3d755

Authentication: Required ✓

Authorization: Required

HTTP Status: 200 OK

Request Headers

Authorization: Bearer <JWT_TOKEN>

Response (Success)

Returns the binary file with appropriate headers:

Header Value
Content-Type application/pdf or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition attachment; filename="[fileName]"

Response Body: Binary file content

Error Responses

400 Bad Request:

{
  "success": false,
  "message": "fileName is required"
}

404 Not Found:

{
  "success": false,
  "message": "Document not found"
}

4. Cancel Job

Endpoint: DELETE /api/document/job/:jobId

URL: http://localhost:3070/api/document/job/1

Authentication: Required ✓

Authorization: Required

HTTP Status: 200 OK

Request Headers

Authorization: Bearer <JWT_TOKEN>

Response (Success)

{
  "success": true,
  "message": "Job cancelled successfully",
  "jobId": "1"
}

Error Responses

404 Not Found:

{
  "success": false,
  "message": "Job not found"
}

Document Data Notes

The generator is tolerant of different request shapes and common field aliases. For example, it accepts both documentData and nested data, and it normalizes document names by removing spaces, underscores, and hyphens.

If a document does not use every field in a sample payload, you can omit the unused keys.


Complete Workflow Example

1. Generate Document

curl -X POST http://localhost:3070/api/document/generate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "document": "precost",
    "documentType": "pdf",
    "documentData": {
      "customerName": "Acme Corp",
      "items": [
        {"name": "Item 1", "description": "Test", "qty": 2, "unitPrice": 100}
      ]
    }
  }'

Response:

{
  "success": true,
  "message": "Document generation started",
  "jobId": "1"
}

2. Check Job Status

curl http://localhost:3070/api/document/job/1/status \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Polling Response (Still Processing):

{
  "success": true,
  "jobId": "1",
  "state": "active"
}

Polling Response (Completed):

{
  "success": true,
  "jobId": "1",
  "state": "completed",
  "result": {
    "fileName": "precost-1715339340000.pdf"
  }
}

3. Download File

curl http://localhost:3070/api/document/download/16adf29b-c0c2-45f9-8808-d6e15cd3d755 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -o my-document.pdf

JavaScript/Fetch Example

async function generateAndDownloadDocument(token) {
  // Step 1: Generate document
  const generateRes = await fetch("/api/document/generate", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      document: "precost",
      documentType: "pdf",
      documentData: {
        customerName: "Acme Corp",
        items: [
          { name: "Item 1", description: "Test", qty: 2, unitPrice: 100 }
        ]
      }
    })
  });
  
  const { jobId } = await generateRes.json();
  console.log("Job queued:", jobId);
  
  // Step 2: Poll for completion
  let isComplete = false;
  let result = null;
  
  while (!isComplete) {
    const statusRes = await fetch(`/api/document/job/${jobId}/status`, {
      headers: { "Authorization": `Bearer ${token}` }
    });
    
    const status = await statusRes.json();
    console.log("Job state:", status.state);
    
    if (status.state === "completed") {
      result = status.result;
      isComplete = true;
    } else if (status.state === "failed") {
      throw new Error(`Job failed: ${status.error}`);
    } else {
      // Wait 2 seconds before polling again
      await new Promise(r => setTimeout(r, 2000));
    }
  }
  
  // Step 3: Download the file
  const downloadRes = await fetch(`/api/document/download/${result.fileName}`, {
    headers: { "Authorization": `Bearer ${token}` }
  });
  
  const blob = await downloadRes.blob();
  
  // Trigger browser download
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = result.fileName;
  a.click();
  window.URL.revokeObjectURL(url);
  
  console.log("Download complete!");
}

Important Notes

Authentication & Authorization

  • All endpoints require JWT token in Authorization: Bearer <token> header
  • User must have one of these roles: admin, management, team_head, user

Polling Strategy

  • Poll status every 2-5 seconds
  • Max recommended: 60 attempts (5 minutes timeout)
  • Move to download immediately when state is completed

Error Handling

  • Jobs automatically retry up to 3 times with exponential backoff
  • Failed jobs remain in queue for debugging
  • Check error and stacktrace fields for failure details

File Management

  • Generated files stored in /app/documents/
  • File names auto-generated: {document}-{timestamp}.{ext}
  • Always sanitize fileName in download requests

Supported Formats

  • PDF: documentType: "pdf"
  • Excel: documentType: "excel"

Performance

  • Worker concurrency: 2 concurrent jobs
  • Timeout per job: 5 minutes
  • Retry attempts: 3 with exponential backoff

Common Response Codes

Code Meaning
202 Accepted - Job queued successfully
200 OK - Successful operation
400 Bad Request - Invalid input
401 Unauthorized - Missing/invalid token
403 Forbidden - Insufficient permissions
404 Not Found - Job or file not found
500 Server Error - Internal error

Migration Notes

If upgrading from synchronous API:

Old (Synchronous):

  • Request returned file immediately
  • Long request timeout
  • Blocking operation

New (Asynchronous):

  • Request returns jobId immediately (202)
  • Poll /api/document/job/{jobId}/status for progress
  • Non-blocking, scalable architecture
  • Automatic retries built-in