PdfGeneration

Info

Architectural truth for PdfGeneration in the Documents feature. This leaf module handles the asynchronous and manual generation, storage, and retrieval of PDF files.

Overview

PDF Generation is a critical export feature of MILTON. A completed document (consisting of sections and generated blocks) must be converted into a shareable PDF. This process happens automatically at the end of the DocumentProcessingSaga or can be triggered manually by a user.

Because rendering an entire document to HTML and converting it via an external service (Gotenberg) can be slow, PDF generation is handled as a background message.

Business Logic Intent

The core intent is to cleanly separate the heavy lifting of PDF rendering from the API’s HTTP request-response cycle.

  1. Rendering: The IDocumentRenderService takes the document entity and renders it into a complete HTML string (with embedded assets/styling).
  2. Conversion: The HTML is sent to the Gotenberg container via IPdfStorageService (or similar infrastructure) which returns a PDF file.
  3. Storage: The PDF binary is uploaded to an S3-compatible blob store.
  4. Linking: The S3 object key (PdfStorageKey) is saved to the Document record in milton-db.

Endpoints & Flow

  • GeneratePdfEndpoint: Manual trigger. Enqueues a GeneratePdfCommand to Wolverine and returns a 200 OK to the client immediately.
  • DownloadPdfEndpoint: Synchronous fetch. Given a DocumentId, it retrieves the PdfStorageKey from the database, fetches the binary from S3, and streams it back to the client as an application/pdf download.

Wolverine Handlers

  • GeneratePdfOnCompletionHandler: Consumes GeneratePdfCommand (emitted manually or by the document saga). Orchestrates the render convert store process and then updates the Document entity. Finally, it publishes PdfGeneratedEvent so SignalR can notify the client that the PDF is ready.

Sequence: PDF Generation Pipeline

sequenceDiagram
    participant Client
    participant API as API / Saga
    participant Bus as Wolverine
    participant Handler as GeneratePdfHandler
    participant DB as milton-db
    participant Gotenberg as Gotenberg (PDF)
    participant S3 as S3 Storage

    alt Manual Trigger
        Client->>API: POST /documents/{id}/pdf
    else Saga Trigger
        API->>API: DocumentGenerationCompleted
    end
    
    API->>Bus: Publish(GeneratePdfCommand)
    Bus->>Handler: Consume(GeneratePdfCommand)
    
    Handler->>DB: Fetch Document & Blocks
    Handler->>Handler: Render to HTML
    Handler->>Gotenberg: Convert HTML to PDF
    Gotenberg-->>Handler: PDF binary stream
    Handler->>S3: Upload PDF stream
    S3-->>Handler: Return StorageKey
    
    Handler->>DB: Update Document.PdfStorageKey
    Handler->>Bus: Publish(PdfGeneratedEvent)
    Bus-->>Client: (SignalR) PDF Ready Notification

Domain Models

  • Commands/Events: GeneratePdfCommand, PdfGeneratedEvent, PdfGenerationFailedEvent
  • Request Models: DownloadPdfRequest, GeneratePdfRequest

0 items under this folder.