Functional Requirements

FR-001: Batch File Upload

Priority: HIGH
Related BR: BR-003

Description

Users shall upload batch invoice files through RESTful API with automatic vendor format detection, file validation, and storage in organization-specific blob containers.

API Specification

Endpoint: POST /v1/organizations/{organizationId}/batches

Request:

POST /v1/organizations/123e4567-e89b-12d3-a456-426614174000/batches
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbG...
Content-Type: multipart/form-data

file: [XML binary]
metadata: {
  "batchName": "Invoice_November_2025",
  "priority": "normal"
}

Response (201 Created):

{
  "success": true,
  "data": {
    "batchId": "550e8400-e29b-41d4-a716-446655440000",
    "status": "uploaded",
    "uploadedAt": "2025-11-21T10:30:00Z",
    "fileInfo": {
      "fileName": "invoices_nov.xml",
      "fileSize": 15728640,
      "detectedFormat": "GASEL"
    },
    "blobPath": "acme-batches-2025/11/21/550e8400.../source.xml"
  }
}

Validation Rules

FieldRuleError CodeMessage
fileRequiredVALIDATION_ERRORFile is required
file.size1KB ≤ size ≤ 100MBFILE_TOO_LARGEFile must be 1KB-100MB
file.contentTypeapplication/xml or text/xmlINVALID_CONTENT_TYPEFile must be XML
file.contentWell-formed XMLINVALID_XMLXML not well-formed. Line {line}, Column {column}
metadata.batchName1-255 chars, no / \VALIDATION_ERRORBatch name: 1-255 chars, no path separators
metadata.priority"normal" or "high"VALIDATION_ERRORPriority must be 'normal' or 'high'

Processing Steps

  1. Validate authentication (OAuth 2.0 JWT token)
  2. Verify user has BatchOperator role
  3. Validate file size (1KB - 100MB)
  4. Validate content type (XML)
  5. Quick parse: Check XML well-formedness
  6. Detect vendor format (namespace analysis)
  7. Generate UUID batch ID
  8. Store XML in blob: {org}-batches-{year}/{month}/{day}/{id}/source.xml
  9. Calculate SHA-256 checksum
  10. Create batch metadata JSON
  11. Return 201 Created with batch details

Acceptance Criteria

#CriterionTestExpected Result
1Accepts XML up to 100MBUpload 100MB file201 Created
2Validates well-formed XMLUpload malformed XML400 INVALID_XML
3Stores in org-specific containerVerify blob path{org}/2025/11/21/{id}/source.xml
4Returns UUID batch IDCheck formatValid UUID v4
5Detects GASEL formatUpload GASEL sampledetectedFormat: "GASEL"
6Detects XELLENT formatUpload XELLENT sampledetectedFormat: "XELLENT"
7Detects ZYNERGY formatUpload ZYNERGY sampledetectedFormat: "ZYNERGY"
8Calculates SHA-256 checksumVerify checksumMatches file
9Requires BatchOperator roleUpload without role403 ACCESS_DENIED
10Rate limited (10/hour/org)Upload 11 files11th returns 429

FR-002: Batch Processing Initiation

Priority: HIGH
Related BR: BR-003

Description

Users shall initiate batch processing through API, which enqueues the batch to batch-upload-queue for asynchronous processing by ParserService.

API Specification

Endpoint: POST /v1/organizations/{orgId}/batches/{batchId}/start

Request:

{
  "validationMode": "strict"
}

Response (202 Accepted):

{
  "success": true,
  "data": {
    "batchId": "550e8400-e29b-41d4-a716-446655440000",
    "status": "queued",
    "queuedAt": "2025-11-21T10:35:00Z",
    "estimatedProcessingTime": "15-30 minutes",
    "queuePosition": 2
  }
}

Processing Flow

  1. Validate batch exists and status is "uploaded"
  2. Create message in batch-upload-queue
  3. Update batch status to "queued"
  4. Return 202 Accepted with queue position
  5. ParserService picks up asynchronously

Validation Rules

CheckRuleError CodeHTTPAction
Batch existsMust exist in blobRESOURCE_NOT_FOUND404Return error
Batch ownershipMust belong to orgACCESS_DENIED403Return error
Batch statusMust be "uploaded"PROCESSING_ERROR422Return current status
Organization activeisActive = trueORGANIZATION_INACTIVE422Return error
Queue capacityDepth < 10,000SERVICE_UNAVAILABLE503Return retry-after
User permissionBatchOperator+ roleACCESS_DENIED403Return error

Acceptance Criteria

#CriterionTestExpected Result
1Only "uploaded" batches startStart processing batch409 if already processing
2Creates queue messageVerify messagePresent in batch-upload-queue
3Updates status to "queued"Check metadatastatus: "queued"
4Returns estimated timeEmpty vs full queueTime varies
5Idempotent (safe duplicates)Call /start twiceBoth return 202, process once
6Returns queue positionVerify accuracyMatches queue depth
7Requires BatchOperator roleCall without role403 ACCESS_DENIED
8Supports validation modesSet lenient modeMode in queue message
9Queue full returns 503Depth >10,000503 with retry-after

FR-003: Parser Service (XML → JSON)

Priority: CRITICAL
Related BR: BR-002, BR-003

Description

ParserService listens to batch-upload-queue, downloads XML, detects vendor format, validates against XSD, parses to canonical JSON, and enqueues 32-item batches to batch-items-queue.

Processing Steps

  1. Dequeue message from batch-upload-queue
  2. Download XML: {org}-batches-{year}/{month}/{day}/{id}/source.xml
  3. Detect vendor format (namespace + structure analysis)
  4. Load vendor-specific schema mapping
  5. Validate XML against vendor XSD schema
  6. Parse XML using XPath expressions
  7. Transform each invoice to canonical JSON
  8. Store JSON: {org}-invoices-{year}/{month}/{day}/{invoice-id}.json
  9. Group invoices into 32-item batches
  10. Enqueue to batch-items-queue
  11. Update batch metadata (totalItems, vendorCode, status="processing")
  12. Delete message from batch-upload-queue

Canonical JSON Schema

{
  "invoiceId": "uuid",
  "invoiceNumber": "2025-11-001",
  "invoiceDate": "2025-11-06",
  "dueDate": "2025-11-20",
  "currency": "SEK",
  "periodStart": "2025-10-01",
  "periodEnd": "2025-10-31",
  
  "customer": {
    "customerId": "020624-2380",
    "fullName": "Medeni Schröder",
    "email": "muntaser.af@zavann.net",
    "phone": "09193538799",
    "address": {
      "street": "Strandbo 63B",
      "city": "Växjö",
      "postalCode": "352 58",
      "country": "SE"
    }
  },
  
  "invoiceDetails": {
    "subTotal": 599.42,
    "taxAmount": 149.86,
    "totalAmount": 749.28,
    "lineItems": [...]
  },
  
  "delivery": {
    "meteringPointId": "735999756427205424",
    "gridArea": "SE4",
    "gridOwner": "Växjö Energi Elnät AB",
    "consumption": 420
  },
  
  "sourceMetadata": {
    "vendorCode": "GASEL",
    "vendorVersion": "1.0",
    "parsedAt": "2025-11-21T10:35:45Z"
  }
}

Acceptance Criteria

#CriterionTestExpected Result
1Listens to batch-upload-queueSend messageDequeued within 30s
2Downloads batch XMLVerify download loggedFile downloaded
3Detects GASEL (100% accuracy)50 GASEL samplesAll detected
4Detects XELLENT (100% accuracy)50 XELLENT samplesAll detected
5Detects ZYNERGY (100% accuracy)50 ZYNERGY samplesAll detected
6Loads correct schema mappingVerify mapping fileCorrect vendor mapping
7Validates XML against XSDInvalid XMLValidation errors logged
8Parses GASEL via XPathParse sampleAll fields extracted
9Transforms to canonical JSONVerify schemaAll fields present
10Stores JSON in correct pathCheck blob{org}/invoices/2025/11/21/{id}.json
11Groups into 32-item batches100 invoices4 messages (32+32+32+4)
12Enqueues to batch-items-queueVerify messagesMessages present
13Updates batch metadataCheck metadatatotalItems, vendorCode set
14Deletes from batch-upload-queueVerify removalMessage gone
15Retries 3× on errorsForce blob error3 retries logged
16Moves to poison queue (3 fails)Force permanent errorIn poison queue
17Performance: 10K in <2 minPerformance test≤ 120 seconds