Implement typed template library and rendering

This commit is contained in:
2026-08-02 12:38:38 +02:00
parent 142c3a26f1
commit b65b905b6e
28 changed files with 4385 additions and 104 deletions
+32
View File
@@ -0,0 +1,32 @@
# Templates Administrator Guide
## Permissions
- `templates:template:read` reads definitions and evidence.
- `templates:template:write` creates immutable revisions.
- `templates:template:publish` selects the revision allowed for final output.
- `templates:template:render` validates and renders supplied snapshots.
- `templates:template:admin` manages every visible tenant/group/user definition.
The managed `template_manager` role contains read, write, publish, and render.
## Scope And Publication
Definitions can be tenant-, group-, or user-scoped. Non-administrators may only
write their own user templates and templates belonging to one of their groups.
Published output remains pinned even when a later draft revision is created.
## Output Storage
Files is optional. When `files.artifact_store` is present and the actor has
`files:file:upload`, managed output is written below `Generated/Templates` with
template, input, and output hashes. Otherwise Templates stores a bounded
database payload. Review database and Files retention together before deleting
render evidence.
## Operations
Apply the module Alembic migration before startup. Monitor rejected renders for
contract drift, output limits, missing Files permission, and reused idempotency
keys. HTML is designed for browser/OS printing; do not treat it as a signed PDF
or proof of physical printer delivery.
+43 -101
View File
@@ -1,113 +1,55 @@
# Template Module Boundary
`govoplan-templates` owns reusable renderable templates, not the data selection
or persistence semantics around the generated output.
`govoplan-templates` owns reusable render definitions and immutable render
evidence. Callers own data selection, approval, delivery, and lifecycle state.
The core boundary decision register is in
`/mnt/DATA/git/govoplan-core/docs/MODULE_ARCHITECTURE.md`.
## Owned Concepts
## Ownership
- scoped template definitions and immutable revisions;
- template type, usage, locale, required-field contracts, output profiles, and
page/media hints;
- safe HTML/text bodies and deterministic token substitution;
- draft preview and published final rendering;
- template, input, renderer, and output hashes plus item/page counts and
diagnostics; and
- bounded fallback payloads when no artifact store is available.
Templates owns:
The implemented printable types are `label`, `label_sheet`, `envelope`,
`serial_letter`, `form_letter`, and `list_layout`. `email` and `generic` use the
same contract while preserving their explicit usage.
- template definitions for letters, decisions, permits, emails, forms, reports,
certificates, notices, and workflow messages
- template versions, draft/published lifecycle, localization, and merge-field
declarations
- render profiles such as output format, page/layout hints, fallback language,
and safe preview mode
- render-context schema declarations so callers know which fields are required
- reusable template fragments inside configuration packages
- rendering capability contracts exposed to mail, campaign, reporting, forms,
workflow, cases, DMS, and files
## Consumer Boundary
## Boundaries
Templates never imports Addresses, Distribution Lists, Campaign, Files, Mail,
Reporting, Forms, or Workflow internals. Consumers discover
`templates.catalog` and `templates.renderer` through Core and submit plain
provider-neutral DTOs. The supplied `input_snapshot` records a stable source
reference; Templates does not fetch or silently refresh that source.
Templates does not own:
Files optionally implements `files.artifact_store`. A final render can request
managed persistence through that contract. If Files is absent, incompatible,
or unauthorized, the result carries a warning and remains available through a
5 MiB bounded Templates download. Managed output is not duplicated in the
Templates payload column.
- report data selection, aggregation, dashboards, scheduled exports, or BI
semantics; those belong to `govoplan-reporting`
- document lifecycle, collaborative editing, locks, approvals, legal hold, or
records management; those belong to `govoplan-dms` and `govoplan-records`
- file/blob storage and file permissions; those belong to `govoplan-files`
- mail sending, mailbox behavior, and mail profile policy; those belong to
`govoplan-mail`
- form submissions, drafts, receipts, and public submission state; those belong
to `govoplan-forms-runtime` when implemented
- workflow transitions, tasks, and case lifecycle
## Safety And Determinism
## Initial Template Types
- backend sanitization removes scripts, styles, active embeds, unsafe links,
event handlers, and undeclared attributes;
- substituted values are HTML escaped;
- output is limited to 5,000 items and 5 MiB;
- final output requires a published revision and idempotency key;
- reusing an idempotency key with changed input is rejected;
- every render pins the immutable definition hash and canonical input hash;
- final artifacts contain hashes and references, not credentials or plaintext
secrets in provenance; and
- browser/OS printing from deterministic HTML is the baseline. PDF conversion
and managed printer delivery belong to future connector adapters.
- `letter`
- `decision_document`
- `permit`
- `email`
- `form`
- `report`
- `certificate`
- `notice`
- `workflow_message`
## Recovery
Template types can share a render engine but should keep type-specific metadata
explicit, especially when retention, signature, accessibility, or delivery
rules differ.
## Render Context Contract
Candidate render request:
```json
{
"template_id": "permit-decision",
"template_version_id": "v1",
"template_type": "permit",
"locale": "de-DE",
"output_format": "pdf",
"context": {
"case_id": "case-1",
"recipient": {"display_name": "Example Person"},
"decision": {"approved": true}
},
"trace": {"correlation_id": "request-1"}
}
```
Candidate render response:
```json
{
"render_id": "render-1",
"template_id": "permit-decision",
"template_version_id": "v1",
"output_format": "pdf",
"artifact": {
"content_type": "application/pdf",
"storage_ref": "files://generated/render-1.pdf",
"checksum": "sha256:..."
},
"warnings": []
}
```
Generated artifact storage can be delegated to files/DMS through capabilities.
Templates should not import those modules directly.
## Candidate Capabilities
- `templates.catalog`
- `templates.renderer`
- `templates.preview`
- `templates.schema`
- `templates.packageFragments`
Consumers should request these through core-mediated capability lookup. The
template module should not import consumer modules.
## First Implementation Slice
1. Define manifest metadata, permissions, and capability names.
2. Add template definition/version DTOs.
3. Add render-context schema validation for one safe text/PDF preview path.
4. Add package fragment format for reusable templates.
5. Add tests that mail/campaign/reporting/forms can detect template capability
presence without importing template internals.
Template definitions, revisions, render evidence, and bounded output are in the
shared database and therefore follow platform backup and restore. Managed Files
artifacts follow Files recovery. Retiring the module is destructive only after
the installer captures a database snapshot; consumers retain pinned hashes and
must diagnose the now-unavailable provider.
+20
View File
@@ -0,0 +1,20 @@
# Templates User Guide
Open **Templates** to create or select a reusable definition.
1. Choose the template type and the contexts in which it may be used, such as
`campaign.postal`.
2. Declare every required input path and its type. Use the same paths as tokens
in the body, for example `{{name}}` or `{{postal.address}}`.
3. Configure page size and, for label sheets, rows, columns, and spacing.
4. Save to create a new immutable revision. Publish the revision before using
it for final output.
5. In **Preview**, supply a representative JSON item. Compatibility validation
explains missing fields, wrong types, unsupported usages, and output-format
mismatches before output is produced.
6. Preview a draft or render final output. Store it in Files when that module is
available and you have upload permission; otherwise use the bounded download.
Render evidence shows the exact revision and abbreviated template, input, and
output hashes. A consumer such as Campaign can submit many frozen recipients;
the UI sample intentionally validates one representative item.