> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://cla-demo.postmansolutions.com/platform/services/document-splitter-service/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://cla-demo.postmansolutions.com/_mcp/server. # Document Splitter Service ## Overview The **document-splitter** is a service that listens for file classification events from Azure Service Bus and automatically splits multi-form PDF documents into individual files based on the classified page ranges. For each split, it delegates file storage to the **file-intake** service and publishes downstream events so other services can process each form independently. It is designed to run as a background worker with no HTTP intake; all work is driven by messaging events. When a **FileClassified** event is received from the Service Bus, the document-splitter service downloads the original PDF and its classification result, splits the PDF into separate files per classified form, uploads each split via the file-intake service, saves a manifest to blob storage, and publishes a **FileSplitFileEvent** per output file and a single **FileSplitFileResultEvent** for the full manifest. ## Flow ```text Service Bus (FileClassified message) ClassifiedFileHandler   1. Validate event fields (applicationId, clientApplicationId, clientApplicationClassifierId, internalUrl, classifiedOutputUrl, fileId)   2. Create job record in DB (status: Started)   3. Download classification JSON from blob (classifiedOutputUrl)   4. Download original PDF from blob (internalUrl)   5. Validate PDF page count matches classification num_pages   6. Branch on is_multi_form:      - false -> handleSingleForm (upload original buffer as single split)      - true  -> handleMultiForm (split PDF by page_ranges or page_start/page_end per form)   7. POST each split file to file-intake        - Endpoint: v1/upload/?parentFileId=...&clientApplicationClassifierId=...        - file-intake stores child file and returns file metadata   8. Publish FileSplitFileEvent per split file -> split-file topic   9. Upload manifest JSON to blob        - splits//splitResults//   10. Publish FileSplitFileResultEvent -> split-file-result topic   11. Update job record in DB (status: Completed, splitManifestBlobUrl) ``` --- ## Events ### Input message - FileClassifiedEvent ```ts {   clientApplicationId: string;   clientApplicationClassifierId: string;   applicationId: string;   internalUrl: string;   classifiedOutputUrl: string;   fileId: string;   timestamp: Date; } ``` ### Output message - FileSplitFileEvent (one per split file) ```ts {   clientApplicationId: string;   internalUrl: string;   fileLocationUrl: string;   timestamp: Date; } ``` ### Output message - FileSplitFileResultEvent (one per job) ```ts {   clientApplicationId: string;   fileId: string;   parentFileBlobUrl: string;   classificationUrl: string;   totalSplitFiles: number;   splitFiles: SplitFileItem[];   timestamp: Date; } ``` ### Error - ProblemEvent Published when processing fails. * 400 for invalid input fields or invalid page range/page count mismatch * 404 if blob content is not found * 500 for all other processing errors ## Blob Storage Layout Only the manifest is written directly by document-splitter. Split PDFs are stored by file-intake. ```text splits/   /     splitResults/       /         __splitResult.json ``` ## Manifest Schema ```json {   "clientApplicationId": "...",   "fileId": "...",   "parentFileBlobUrl": "...",   "classificationUrl": "...",   "timestamp": "...",   "totalSplitFiles": 3,   "splitFiles": [     {       "fileName": "...",       "formType": "...",       "formIndex": 0,       "pageStart": 1,       "pageEnd": 3,       "blobUrl": "..."     }   ] } ``` ## Job Tracking A SQL job record is upserted for each request lifecycle in splitter.Job. * Started: after event validation, before processing * Completed: after manifest upload and event publishing * Failed: when any unhandled processing error occurs On completion, splitManifestBlobUrl is stored in the job record. ## file-intake Integration * Endpoint: POST v1/upload/\?parentFileId=\\&clientApplicationClassifierId=\ * Request: multipart/form-data with split PDF file content * Response: array with fileId, filePath, filename, hashValue * One request per split file, awaited before downstream publish * Returned filePath is used for: \- FileSplitFileEvent.internalUrl \- FileSplitFileEvent.fileLocationUrl \- manifest splitFiles\[].blobUrl If file-intake upload fails or returns an invalid shape, a ProblemEvent is published and the error is rethrown. ## Split Filename Convention ```text __pg-_. ``` Example: ```text 20260722173629176_2B4C733C-9CD4-42C0-95C9-8A157AE63B57_pg7-8_Form-1040.pdf ``` * timestamp is derived from current ISO time with separators removed * form type is sanitized to alphanumeric, underscore, and hyphen ## Edge Cases * No forms in classification: throws bad request, publishes ProblemEvent * Form with no valid page range in multi-form mode: skipped with warning * is\_multi\_form = false: uploads original PDF buffer as a single split * PDF page count mismatch: validation error (400) * Any processing error: publishes ProblemEvent, marks job failed, rethrows for dead-letter handling ## Limitations * File type supported: PDF only ## Docs - [Overview](https://cla-demo.postmansolutions.com/platform/services/document-splitter-service/overview.md) - [Scope](https://cla-demo.postmansolutions.com/platform/services/document-splitter-service/scope.md) - [Process Flow](https://cla-demo.postmansolutions.com/platform/services/document-splitter-service/process-flow.md) - [Step by Step Walkthrough](https://cla-demo.postmansolutions.com/platform/services/document-splitter-service/process-flow/step-by-step-walkthrough.md)