> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://cla-demo.postmansolutions.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://cla-demo.postmansolutions.com/_mcp/server.

# Current Implementation and To Be

## Overview

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 to blob storage, saves a manifest, and publishes a **FileSplitFile** event per output file for downstream processing.

---

## Flow

```
Service Bus (FileClassified)
        │
        ▼
ClassifiedFileHandler
  1. Download classification JSON from blob (classifiedOutputUrl)
  2. Download original PDF from blob (internalUrl)
  3. For each form in classification → split PDF by page range(s)
  4. Upload each split PDF to blob storage (splits/<clientAppId>/splitFiles/)
  5. Save manifest JSON to blob (splits/<clientAppId>/splitResults/)
  6. Publish FileSplitFileEvent per split file → Service Bus
```

---

## Key Components

| File                                              | Responsibility                                                                       |
| ------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `src/messaging/handlers/classifiedFileHandler.ts` | Orchestrates the full split workflow                                                 |
| `src/internal/pdf/pdfSplitter.ts`                 | Splits a PDF buffer by 1-based page ranges using `pdf-lib`                           |
| `src/internal/storage/blobStorageService.ts`      | Download/upload blob buffers; ensure container exists                                |
| `src/internal/storage/parseBlobUrl.ts`            | Parses Azure blob URLs into container/path/filename parts                            |
| `src/types/messaging.ts`                          | Event type definitions (`FileClassifiedEvent`, `FileSplitFileEvent`, `ProblemEvent`) |
| `src/types/classification.ts`                     | Classification result shape (`ClassificationResult`, `ClassificationForm`)           |

---

## Events

### Input – `FileClassifiedEvent`

```ts
{
  clientApplicationId: string;
  internalUrl: string;           // blob URL of the original PDF
  classifiedOutputUrl: string;   // blob URL of the classification JSON
  fileId: string;
  timestamp: Date;
}
```

### Output – `FileSplitFileEvent` (one per split file)

```ts
{
  clientApplicationId: string;
  internalUrl: string;           // blob URL of the split PDF
  fileLocationUrl: string;
  timestamp: Date;
}
```

### Error – `ProblemEvent`

Published when processing fails. Returns `404` if the blob is not found, `500` for all other errors.

---

## Blob Storage Layout

```
splits/
  <clientApplicationId>/
    splitFiles/
      <timestamp>_<baseName>_pg<start>-<end>_<formType>.pdf
    splitResults/
      <timestamp>_<baseName>_splitResult.json   ← manifest
```

---

## Manifest Schema

```json
{
  "clientApplicationId": "...",
  "fileId": "...",
  "parentFileBlobUrl": "...",
  "classificationUrl": "...",
  "timestamp": "...",
  "totalSplitFiles": 3,
  "splitFiles": [
    { "fileName": "...", "formType": "...", "formIndex": 0, "pageStart": 1, "pageEnd": 3, "blobUrl": "..." }
  ]
}
```

---

## Edge Cases

* **No forms in classification** → skipped with a warning, no split produced.
* **Form with no valid page range** → skipped with a warning.
* **Multiple page ranges per form** → one split file produced per range (concurrent upload).
* **Any processing error** → `ProblemEvent` published; error is rethrown for Service Bus dead-lettering.

## Limitations

* **File Type Supported** only PDF.

# TO-BE: Future Changes

### Overview

The direct blob upload from document-splitter will be replaced by delegating file storage to the **file-intake** service. Document-splitter will call file-intake's upload endpoint for each split file, and file-intake is responsible for storing the blob and generating a `FileId`. Document-splitter then publishes the split file event (including the `FileId`) to the Service Bus.

---

### Updated Flow

```
Service Bus (FileClassified)
        │
        ▼
Document-Splitter (ClassifiedFileHandler)
  1. Download classification JSON from blob (classifiedOutputUrl)
  2. Download original PDF from blob (internalUrl)
  3. For each form in classification → split PDF by page range(s)
  4. POST each split file to file-intake upload endpoint
       └─ file-intake stores the child blob + creates FileId
       └─ file-intake returns { fileId, internalUrl, hashValue }
  5. Save manifest JSON to blob (splits/<clientAppId>/splitResults/)
  6. Publish FileSplitFileEvent per split file → split-file topic
       └─ message includes FileId returned from file-intake
```

---

### Current Implementation and To-Be

| Area                     | Current                                            | TO-BE                                                   |
| ------------------------ | -------------------------------------------------- | ------------------------------------------------------- |
| Split file storage       | Document-splitter uploads directly to blob storage | Document-splitter calls file-intake upload endpoint     |
| FileId generation        | Not included in split events                       | file-intake creates and returns `FileId` per split file |
| `internalUrl` source     | Generated locally from blob upload                 | Returned by file-intake after upload                    |
| Split file event payload | No `FileId`                                        | Includes `FileId` from file-intake response             |
| Service Bus topic        | `split-file` topic                                 | `split-file` topic (unchanged)                          |

---

### Updated Output Event – `FileSplitFileEvent`

#### Current

```ts
{
  clientApplicationId: string;
  internalUrl: string;
  fileLocationUrl: string;
  timestamp: Date;
}
```

#### To-Be

```ts
{
  clientApplicationId: string;
  fileId: string;                // returned by file-intake after upload
  internalUrl: string;
  fileLocationUrl: string;
  timestamp: Date;
}
```

---

### file-intake Integration

* **Endpoint:** `POST /files/child/upload` (file-intake service, NEW Endpoint)
* **Request:** multipart or binary body containing the split PDF buffer
* **Response:** `{ fileId: string, internalUrl: string, hashValue: string }`
* One HTTP call is made per split file; document-splitter awaits the response before publishing the event.
* If the file-intake call fails, a `ProblemEvent` is published and the error is rethrown (same error handling as today).