Skip to main content

Document Templates

Document templates render namespace-owned Handlebars templates into finished documents — proposals, letters, invoices, contracts, and custom forms that need data from users, RAG, or contractor systems.

Data Model

Two Prisma models drive the feature:

ModelRole
DocumentTemplateThe reusable template spec: namespace, department, category, body, variables, and default output format.
DocumentGenerationOne render attempt: user input, rendered output, status, error, and optional saved output file.

Templates belong to a Namespace. departmentId on the template row is optional, but when it's set, namespace validation keeps it aligned with the namespace's department.

Template Body

templateBody is rendered with Handlebars:

# Proposal for {{clientName}}

Scope:
{{scopeSummary}}

Total: {{amount}}

HTML output uses Handlebars escaping. Markdown and DOCX output use noEscape so legal text, bullets, and preformatted clauses remain intact.

Variables

Variables are stored as JSON in variables. Each variable can define:

FieldMeaning
nameRequired Handlebars key.
typestring, number, boolean, date, object, or array.
requiredWhether missing values fail generation.
sourceuser, rag, or contractor_api.
descriptionHuman-readable explanation for forms and reviewers.
queryOptional RAG query template. Can reference earlier variables.
default / fallbackOptional value used before source resolution fails.

Example:

[
{
"name": "clientName",
"type": "string",
"required": true,
"source": "user",
"description": "Legal client name"
},
{
"name": "scopeSummary",
"type": "string",
"required": true,
"source": "rag",
"query": "Summarize active contract scope for {{clientName}}"
},
{
"name": "edrpou",
"type": "string",
"source": "contractor_api",
"fallback": "unknown"
}
]

Variable Sources

user variables come from the generation input payload.

rag variables run the variable's query, description, or name against department-scoped knowledge. The default resolver uses PostgreSQL full-text search over ready chunks and returns top matching snippets. Inject a custom resolver for tests or richer RAG.

contractor_api variables go through an optional contractor API resolver. If the resolver is missing and the variable is required, generation fails with VariableSourceUnavailableError. If it's optional, the value is an empty string unless default or fallback is set.

Generate Workflow

The endpoint is:

POST /api/v1/document-templates/:id/generate

Request body:

{
"input": {
"clientName": "Acme Corp",
"amount": 120000
},
"preview": false,
"outputFormat": "docx",
"saveToKnowledgeBaseId": "clx..."
}

The flow is:

  1. load the template inside the caller's department scope;
  2. create a DocumentGeneration row with status pending;
  3. parse and validate variables;
  4. fill direct user values from input;
  5. resolve missing defaults, RAG variables, and contractor API variables;
  6. coerce values to declared types;
  7. render templateBody with Handlebars;
  8. export the output as Markdown, HTML, or DOCX metadata/content;
  9. optionally save non-preview output to a knowledge base document;
  10. mark the generation ready or store the error and mark it failed.

Missing required user variables fail the generation. Invalid numbers, booleans, dates, arrays, or objects fail before any output is returned.

Output Formats

Supported formats: md, html, docx, and pdf.

FormatBehavior
mdReturns rendered Markdown inline with text/markdown metadata.
htmlReturns rendered HTML inline with text/html metadata.
docxBuilds a DOCX from rendered text blocks and returns base64 export data.
pdfReserved in the enum, currently rejected with UnsupportedDocumentExportError.

When the request omits outputFormat, the template's outputFormat is used.

Storage and Download

Generation history is stored in document_generations and can be listed with:

GET /api/v1/document-generations
GET /api/v1/document-generations/:id

With preview: true, the output is not saved as a knowledge-base document and outputFileId stays null.

With preview: false and saveToKnowledgeBaseId set, the rendered output is saved as a Document in the target knowledge base. It uses the generated file name, MIME type, output format, and ready status, so normal knowledge document APIs handle download and future ingestion. The generation row stores the saved document id in outputFileId.

Permissions

Template CRUD requires template management permissions. Generation requires document generation permissions and department-scope access to the template's namespace. Non-global users can't generate from a template outside their effective department scope.

Operational Notes

  • Keep templates small enough to review. The API rejects bodies above 250,000 characters.
  • Use rag variables for evidence-backed clauses rather than pasting large policy blocks into the template.
  • Use preview: true for draft review. Use preview: false only when the result should become part of knowledge history.
  • Emit a document_ready notification when a non-preview generation produces a file a user needs to download.