Chapter 27 · Volume III — The Intelligence Layer

Templates & Documents

27.1 Overview

Business processes produce documents. Award notices, inspection certificates, denial letters, compliance attestations, invoices, shipping manifests. ADL templates declare these documents in YAML — the trigger that generates them, the data they contain, the template that formats them, and the storage that archives them.

Templates connect the existing ADL infrastructure: resources provide the data, history events provide the trigger, AEL provides the computation, notifications provide the delivery, and schedules provide the automation. The template adds the formatting and the file output.


27.2 Declaration

Templates are declared in the domain-level templates: block:

domain:
  name: awards
  version: "2.0.0"

  templates:
    awardNotice:
      description: "Official notice of award generated upon activation"
      trigger:
        resource: Award
        event: transition
        transition: activate

      format: pdf
      filename: "Award-Notice-{awardNumber}-{$date}.pdf"

      permissions:
        generate: [spoOfficer, admin]
        view: [authenticated]

      data:
        award: $record
        pi:
          source: Researcher
          filter: "id == $record.piId"
          single: true
        budgetCategories:
          source: BudgetCategory
          filter: "awardId == $record.id"
          sort: category asc
        institution:
          static:
            name: "${INSTITUTION_NAME}"
            address: "${INSTITUTION_ADDRESS}"

      layout:
        pageSize: letter
        margins: { top: 1in, right: 1in, bottom: 1in, left: 1in }
        header:
          logo: "${INSTITUTION_LOGO_PATH}"
          text: "Office of Sponsored Programs"
        footer:
          left: "Generated {$datetime}"
          center: "Page {$page} of {$pages}"
          right: "CONFIDENTIAL"

      body: |
        # Notice of Award

        **Award Number:** {award.awardNumber}
        **Date Issued:** {$date}

        ## Award Information

        | Field | Value |
        |-------|-------|
        | Title | {award.title} |
        | Sponsor | {award.sponsor} |

        ## Principal Investigator

        **Name:** {pi.firstName} {pi.lastName}
        **Department:** {pi.department}

        ## Budget Summary

        | Category | Budgeted |
        |----------|----------|
        {#each budgetCategories}
        | {category} | {budgetedAmount | money} |
        {/each}

        **Total Award:** {award.totalAmount | money}

      attachTo:
        resource: Award
        recordId: $record.id
        field: awardNoticeDocId

      notification:
        channels: [email]
        recipients:
          field: piId
        template:
          subject: "Award Notice — {award.awardNumber}"
          body: "Please find the attached notice of award."
        attachDocument: true

Template Properties

PropertyTypeRequiredDescription
descriptionstringnoHuman-readable description
triggerobject or "manual"yesEvent trigger or manual generation
conditionstringnoAEL expression — only generate when true
formatstringyesOutput format: pdf, docx, html, markdown
filenamestringyesOutput filename with {field} interpolation
permissions.generatestring[]yesRoles that can trigger generation
permissions.viewstring[]yesRoles that can view generated documents
parametersarrayif manualInput parameters for on-demand generation
dataobjectyesData context assembly
layoutobjectnoPage layout configuration (PDF/DOCX)
bodystringyesTemplate body with interpolation
attachToobject or "none"noAuto-attach to a resource record
notificationobjectnoSend notification with document attached

27.3 Trigger Types

Event-Driven

Generates automatically when a history event fires:

trigger:
  resource: Award
  event: transition
  transition: activate

The template subscribes to history events on the bus. When the matching event fires, the runtime assembles the data context, interpolates the template, renders the output, stores the document, and optionally sends a notification.

Manual

Generated on demand via API call:

trigger: manual
parameters:
  - name: assetId
    type: uuid
    required: true
    label: "Asset"
  - name: includeHistory
    type: boolean
    default: true
    label: "Include event history"

Manual templates are invoked through the API with parameter values:

POST /api/v1/{domain}/templates/assetPassport/generate
{ "assetId": "asset-001", "includeHistory": true }

Scheduled

Generated by a schedule definition (§24) using action: template:

schedules:
  monthlyComplianceReport:
    recurrence: monthly on 1st at 06:00
    action: template
    template: complianceMonthlyReport

Conditional

Any trigger can include a condition that gates generation:

trigger:
  resource: LoanApplication
  event: transition
  transition: deny
condition: "$record.denialReasonCode != 'withdrawn'"

The condition is evaluated after the event fires. If false, no document is generated.


27.4 Data Context Assembly

The data block defines what data is available to the template body. Each key becomes a variable accessible via {keyName.field} interpolation.

Data Source Types

$record — the triggering record:

data:
  award: $record

Resource query — fetch related records:

data:
  lineItems:
    source: OrderItem
    filter: "orderId == $record.id"
    sort: createdAt asc
  customer:
    source: Customer
    filter: "id == $record.customerId"
    single: true

When single: true, the query returns one record. Otherwise it returns an array for {#each}.

Static values — environment variables and constants:

data:
  institution:
    static:
      name: "${INSTITUTION_NAME}"
      address: "${INSTITUTION_ADDRESS}"

Computed values — AEL expressions:

data:
  totalExpended:
    computed: "sum(Expenditure, 'amount', awardId == $record.id && status == 'processed')"

History events — recent event timeline:

data:
  recentHistory:
    history: true
    resource: $record
    limit: 100

27.5 Template Body Syntax

The template body uses Markdown with interpolation expressions.

Field Interpolation

{award.awardNumber}
{pi.firstName} {pi.lastName}
{$date}

Format Pipes

{award.totalAmount | money}           → $500,000.00
{utilizationRate | percentage}        → 62.5%
{award.startDate | date}              → Mar 1, 2026

Format pipes use the same format system as reports (§26.5).

Iteration

{#each budgetCategories}
| {category} | {budgetedAmount | money} |
{/each}

Special variables inside iteration: {$index} (zero-based) and {$item} (raw value for simple arrays).

Conditionals

{if(award.costShareRequired, "Cost sharing required: " + (award.costShareAmount | money), "")}

Collection Functions

{inspections | count}             → 12
{lineItems | sum:amount}          → 1234.56
{lineItems | avg:unitPrice}       → 29.99

Special Variables

VariableDescription
{$date}Current date (locale-formatted)
{$datetime}Current date and time
{$actor.name}Person who triggered generation
{$actor.email}Actor’s email
{$page}Current page number (PDF only)
{$pages}Total page count (PDF only)
{$params.name}Parameter value (manual templates)

27.6 Output Formats

PDF

The primary format for official documents. The layout block controls page formatting:

layout:
  pageSize: letter
  orientation: portrait
  margins: { top: 1in, right: 1in, bottom: 1in, left: 1in }
  header:
    logo: "${INSTITUTION_LOGO_PATH}"
    text: "Office of Sponsored Programs"
  footer:
    left: "Generated {$datetime}"
    center: "Page {$page} of {$pages}"
    right: "CONFIDENTIAL"
  watermark:
    text: "DRAFT"
    opacity: 0.1
  font:
    family: "Helvetica"
    size: 10
  tableStyle:
    headerBackground: "#f1f5f9"
    borderColor: "#e2e8f0"
    alternateRowBackground: "#f8fafc"

The Markdown body converts to formatted PDF: headers become styled sections, tables become bordered tables, bold/italic render with font weight/style, horizontal rules become page-width lines.

The PDF generator is a Kalos plugin implementing IDocumentRenderer.

DOCX

Word document output for editable templates:

format: docx

HTML

HTML output for browser rendering and email embedding:

format: html

Markdown

Raw Markdown output (interpolated, no format conversion):

format: markdown

27.7 Document Storage

Auto-Attachment

attachTo:
  resource: Award
  recordId: $record.id
  field: awardNoticeDocId

On generation: store the file → create a documents table record → update the target record’s field with the document ID → record a history event.

Setting attachTo: none stores the document without linking it to a record.

Storage Backend

domain:
  documentStorage:
    provider: filesystem
    basePath: "${DOCUMENT_STORAGE_PATH}"
    structure: "{domain}/{resource}/{year}/{month}/"

For cloud storage:

  documentStorage:
    provider: s3
    bucket: "${S3_DOCUMENT_BUCKET}"
    region: "${AWS_REGION}"
    prefix: "documents/"

Documents Table

ColumnTypeDescription
iduuidDocument identifier
templateNamestringTemplate definition that generated this document
templateVersionstringDomain version at generation time
resourcestringSource resource name
recordIduuidSource record ID
filenamestringGenerated filename
formatstringOutput format
storagePathstringPath in storage backend
fileSizeintegerFile size in bytes
generatedByuuidUser who triggered generation
generatedAtdatetimeGeneration timestamp
metadatajsonParameters, data snapshot

Document Versioning

Generated documents record which domain version produced them. Template changes in version 2.1.0 do not affect documents generated under version 2.0.0. The version trail is in the documents table.


27.8 Document API

GET  /api/v1/{domain}/templates
     — list all template definitions

GET  /api/v1/{domain}/templates/{name}
     — get template definition

POST /api/v1/{domain}/templates/{name}/generate
     — manual generation with parameters (returns the document)

GET  /api/v1/{domain}/documents
     ?resource=Award&recordId={id}&template=awardNotice
     — list generated documents

GET  /api/v1/{domain}/documents/{id}
     — download generated document (binary)

GET  /api/v1/{domain}/documents/{id}/metadata
     — metadata without downloading

27.9 Notification with Document

notification:
  channels: [email]
  recipients:
    field: piId
    additional: [departmentChairId]
  template:
    subject: "Award Notice — {award.awardNumber}"
    body: "Please find the attached notice of award for {award.title}."
  attachDocument: true

When attachDocument: true, the generated file is attached to the notification email. This is how award letters, denial notices, and inspection certificates are stored on the record and delivered to the recipient in one declaration.


27.10 Integration Points

FeatureIntegration
History (§21)Event-triggered generation; document generation produces history events
Notifications (§23)Documents attached to notification emails via attachDocument
Schedules (§24)Scheduled generation via action: template
Reports (§26)Shared format system and data context assembly patterns
Workflows (§25)Workflow steps can trigger document generation

End of Chapter 27.

Next: Chapter 28 — Sheet Mode