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
+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.