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:
| Model | Role |
|---|---|
DocumentTemplate | The reusable template spec: namespace, department, category, body, variables, and default output format. |
DocumentGeneration | One 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:
| Field | Meaning |
|---|---|
name | Required Handlebars key. |
type | string, number, boolean, date, object, or array. |
required | Whether missing values fail generation. |
source | user, rag, or contractor_api. |
description | Human-readable explanation for forms and reviewers. |
query | Optional RAG query template. Can reference earlier variables. |
default / fallback | Optional 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:
- load the template inside the caller's department scope;
- create a
DocumentGenerationrow with statuspending; - parse and validate variables;
- fill direct user values from
input; - resolve missing defaults, RAG variables, and contractor API variables;
- coerce values to declared types;
- render
templateBodywith Handlebars; - export the output as Markdown, HTML, or DOCX metadata/content;
- optionally save non-preview output to a knowledge base document;
- mark the generation
readyor store the error and mark itfailed.
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.
| Format | Behavior |
|---|---|
md | Returns rendered Markdown inline with text/markdown metadata. |
html | Returns rendered HTML inline with text/html metadata. |
docx | Builds a DOCX from rendered text blocks and returns base64 export data. |
pdf | Reserved 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
ragvariables for evidence-backed clauses rather than pasting large policy blocks into the template. - Use
preview: truefor draft review. Usepreview: falseonly when the result should become part of knowledge history. - Emit a
document_readynotification when a non-preview generation produces a file a user needs to download.