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

741 lines
16 KiB
Markdown

# 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)
```json
{
"success": true,
"message": "Document generation started",
"jobId": "1"
}
```
#### Error Responses
**400 Bad Request:**
```json
{
"success": false,
"message": "document, documentType, and documentData are required"
}
```
**500 Server Error:**
```json
{
"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
```json
{
"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
```json
{
"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
```json
{
"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
```json
{
"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
```json
{
"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
```json
{
"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)
```json
{
"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)
```json
{
"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:**
```json
{
"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:**
```json
{
"success": false,
"message": "fileName is required"
}
```
**404 Not Found:**
```json
{
"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)
```json
{
"success": true,
"message": "Job cancelled successfully",
"jobId": "1"
}
```
#### Error Responses
**404 Not Found:**
```json
{
"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
```bash
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:**
```json
{
"success": true,
"message": "Document generation started",
"jobId": "1"
}
```
### 2. Check Job Status
```bash
curl http://localhost:3070/api/document/job/1/status \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
**Polling Response (Still Processing):**
```json
{
"success": true,
"jobId": "1",
"state": "active"
}
```
**Polling Response (Completed):**
```json
{
"success": true,
"jobId": "1",
"state": "completed",
"result": {
"fileName": "precost-1715339340000.pdf"
}
}
```
### 3. Download File
```bash
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
```javascript
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