# Documents

A document is something your app renders for people to keep, such as an
invoice as a PDF. The `documents` capability renders a typed template to
HTML or PDF, exactly as email renders a message. A document is a
`type X = Document { ... }` whose fields are the values its template
uses. It lives in its domain's `documents/` folder, beside its `.html`
template. The template follows the strict
[template rules](email.md#what-a-template-may-not-do), reads `translations.` in
the locale it is given, and is wrapped in the optional
`shared/documents/layout.html`.

Here an invoice is rendered to a PDF by a subscriber, through Gotenberg,
and kept as a file:

```jadpo
// domains/billing/documents/invoice_document.jadpo
/// An invoice as the customer receives it.
type InvoiceDocument = Document {
    number: InvoiceNumber
    customer_name: PersonName
    total: PresentationText
}

// app.jadpo
application {
    connections: {
        pdfs: {
            package: Gotenberg.v8
            domains: [billing]
        }
    }
    documents: {
        connection: pdfs
    }
}

// domains/billing/actions/render_invoice.jadpo
var pdf: Bytes = attempt documents.pdf(InvoiceDocument { ... }, locale: customer.locale)
var file: File = attempt invoices.put(pdf, FileType.pdf)
```

- `documents.pdf(document, locale:)` returns the PDF's `Bytes`.
  `documents.html(document, locale:)` returns the rendered HTML, for
  previews.
- `documents: { layout: ... }` names the shared document layout file.
  Leave it out and `shared/documents/layout.html` is used if it exists,
  and Jadpo's plain layout otherwise.
- The connection turns HTML into a PDF. It is Gotenberg as a container
  package, which `jadpo dev` starts in development
  ([Services](what-package-code-may-do.md#services)), or a hosted API's package,
  such as DocRaptor or PDFShift. `documents:` with no connection that
  provides `documents` is a compile error.
- Rendering is heavy work, so it runs in subscribers, never in a route,
  and no more renders run at once than the provider's `max_concurrent:`
  allows ([How polls and `max_concurrent:` run](how-polls-and-max-concurrent-run.md)).
  A `documents.pdf` call reached from a route is a compile error naming
  the subscriber shape.
- In tests the fake returns a placeholder PDF, and a test can read the
  rendered HTML
  ([Provider calls and capabilities in tests](fakes-for-integrations.md#provider-calls-and-capabilities-in-tests)).
