580 lines
26 KiB
Python
580 lines
26 KiB
Python
from __future__ import annotations
|
|
|
|
from govoplan_core.core.modules import with_documentation_structured_translations
|
|
from govoplan_templates.backend.german_structured_documentation import GERMAN_STRUCTURED_TRANSLATIONS
|
|
|
|
from pathlib import Path
|
|
|
|
from govoplan_core.core.files import CAPABILITY_FILES_ARTIFACT_STORE
|
|
from govoplan_core.core.module_guards import (
|
|
drop_table_retirement_provider,
|
|
persistent_table_uninstall_guard,
|
|
)
|
|
from govoplan_core.core.modules import (
|
|
CapabilityDocumentation,
|
|
DocumentationCondition,
|
|
DocumentationTopic,
|
|
FrontendModule,
|
|
FrontendRoute,
|
|
MigrationSpec,
|
|
ModuleContext,
|
|
ModuleInterfaceProvider,
|
|
ModuleInterfaceRequirement,
|
|
ModuleManifest,
|
|
NavItem,
|
|
PermissionDefinition,
|
|
ProductAreaContribution,
|
|
RoleTemplate,
|
|
)
|
|
from govoplan_core.core.provider_governance import declared_module_architecture
|
|
from govoplan_core.core.templates import (
|
|
CAPABILITY_TEMPLATE_CATALOG,
|
|
CAPABILITY_TEMPLATE_CONTENT_LIBRARY,
|
|
CAPABILITY_TEMPLATE_RENDERER,
|
|
)
|
|
from govoplan_core.core.views import ViewSurface
|
|
from govoplan_core.db.base import Base
|
|
from govoplan_templates.backend.db import models as template_models
|
|
from govoplan_templates.backend.dsar_provider import (
|
|
TEMPLATES_DSAR_CAPABILITY,
|
|
TemplatesDsarProvider,
|
|
)
|
|
|
|
|
|
MODULE_ID = "templates"
|
|
MODULE_NAME = "Templates"
|
|
MODULE_VERSION = "0.1.22"
|
|
|
|
READ_SCOPE = "templates:template:read"
|
|
WRITE_SCOPE = "templates:template:write"
|
|
PUBLISH_SCOPE = "templates:template:publish"
|
|
RENDER_SCOPE = "templates:template:render"
|
|
ADMIN_SCOPE = "templates:template:admin"
|
|
|
|
|
|
def _permission(scope: str, label: str, description: str) -> PermissionDefinition:
|
|
module_id, resource, action = scope.split(":", 2)
|
|
return PermissionDefinition(
|
|
scope=scope,
|
|
label=label,
|
|
description=description,
|
|
category=MODULE_NAME,
|
|
level="tenant",
|
|
module_id=module_id,
|
|
resource=resource,
|
|
action=action,
|
|
)
|
|
|
|
|
|
PERMISSIONS = (
|
|
_permission(
|
|
READ_SCOPE,
|
|
"View templates",
|
|
"Read template definitions, revisions, and render evidence.",
|
|
),
|
|
_permission(
|
|
WRITE_SCOPE, "Manage templates", "Create and revise reusable templates."
|
|
),
|
|
_permission(
|
|
PUBLISH_SCOPE,
|
|
"Publish templates",
|
|
"Publish immutable template revisions for final output.",
|
|
),
|
|
_permission(
|
|
RENDER_SCOPE,
|
|
"Render templates",
|
|
"Preview and render governed output from supplied snapshots.",
|
|
),
|
|
_permission(
|
|
ADMIN_SCOPE,
|
|
"Administer templates",
|
|
"Manage all tenant, group, and user templates.",
|
|
),
|
|
)
|
|
|
|
ROLE_TEMPLATES = (
|
|
RoleTemplate(
|
|
slug="template_manager",
|
|
name="Template manager",
|
|
description="Create, publish, and render reusable typed templates.",
|
|
permissions=(READ_SCOPE, WRITE_SCOPE, PUBLISH_SCOPE, RENDER_SCOPE),
|
|
),
|
|
)
|
|
|
|
DOCUMENTATION = (
|
|
DocumentationTopic(
|
|
id="templates.workspace-layout",
|
|
title="Templates workspace actions",
|
|
summary="Find collection-wide commands in their consistent workspace position.",
|
|
body="Reload and Add template use the persistent full-width workspace header at the upper right; Reload sits immediately before creation. Selecting a record, changing filters, or opening an editor does not move these collection-wide commands into the left pane. Template editing, saving, publishing, and rendering remain scoped to the selected template. Existing permissions, disabled-state rules, and unsaved-change guards still apply. Administrators configure authority through the existing permission system; no new permission or automatic operation is introduced.",
|
|
layer="static",
|
|
documentation_types=("user", "admin"),
|
|
audience=("user", "module_admin", "operator"),
|
|
order=5,
|
|
translations={"de": {
|
|
"title": "Vorlagen: Aktionen im Arbeitsbereich",
|
|
"summary": "Sammlungsweite Aktionen an ihrer einheitlichen Position im Arbeitsbereich finden.",
|
|
"body": "Neu laden und Vorlage hinzufügen stehen oben rechts in der dauerhaft sichtbaren, arbeitsbereichsweiten Leiste; Neu laden steht unmittelbar vor dem Anlegen. Auswahl, Filterwechsel und Bearbeitung verschieben diese sammlungsweiten Aktionen nicht in den linken Bereich. Bearbeiten, Speichern, Veröffentlichen und Rendern bleiben der ausgewählten Vorlage zugeordnet. Bestehende Berechtigungen, Deaktivierungsregeln und der Schutz ungespeicherter Änderungen gelten weiterhin. Administratoren konfigurieren Rechte im bestehenden Berechtigungssystem; es entstehen weder neue Rechte noch automatische Vorgänge.",
|
|
}},
|
|
),
|
|
DocumentationTopic(
|
|
id="templates.library",
|
|
title="Template library",
|
|
summary="Create versioned templates with explicit usages and required data fields.",
|
|
body=(
|
|
"Templates are reusable, scoped definitions. Every edit creates an immutable revision. "
|
|
"Publish the revision that consumers may use for final output. A compatibility check explains "
|
|
"missing fields, unsupported usages, and unavailable output formats before rendering. "
|
|
"The Add template dialog uses the shared responsive form layout: name, type, and footer actions remain inside the dialog on narrow screens without horizontal form scrolling."
|
|
),
|
|
layer="available",
|
|
documentation_types=("admin", "user"),
|
|
audience=("operator", "module_admin", "product_owner"),
|
|
conditions=(
|
|
DocumentationCondition(
|
|
required_modules=("templates",),
|
|
any_scopes=(READ_SCOPE, WRITE_SCOPE, PUBLISH_SCOPE, ADMIN_SCOPE),
|
|
),
|
|
),
|
|
translations={
|
|
"de": {
|
|
"title": "Vorlagenbibliothek verwalten",
|
|
"summary": "Versionierte Vorlagen mit ausdrücklichen Verwendungen und erforderlichen Datenfeldern erstellen.",
|
|
"body": (
|
|
"Vorlagen sind wiederverwendbare, bereichsgebundene Definitionen. Jede Bearbeitung erzeugt eine unveränderliche Revision. "
|
|
"Veröffentlichen Sie die Revision, die Verbraucher für endgültige Ausgaben verwenden dürfen. Vor dem Rendern erläutert eine "
|
|
"Kompatibilitätsprüfung fehlende Felder, nicht unterstützte Verwendungen und nicht verfügbare Ausgabeformate. "
|
|
"Der Dialog zum Hinzufügen einer Vorlage verwendet das gemeinsame responsive Formularlayout: Name, Typ und Fußzeilenaktionen bleiben auch auf schmalen Bildschirmen ohne horizontales Formularscrollen im Dialog."
|
|
),
|
|
}
|
|
},
|
|
metadata={
|
|
"kind": "workflow",
|
|
"seed": True,
|
|
"help_contexts": [
|
|
"templates.page",
|
|
"templates.library",
|
|
"templates.editor",
|
|
"templates.state.read-only",
|
|
],
|
|
},
|
|
),
|
|
DocumentationTopic(
|
|
id="templates.reusable-content",
|
|
title="Reusable content fragments and campaign parts",
|
|
summary="Create scoped, versioned content that authorized consumers can insert without copying a private library.",
|
|
body=(
|
|
"Content fragments retain text and HTML variants, usage constraints, locale, scope, revision, and publication state in Templates. "
|
|
"Campaign can load a fragment or complete email part through the optional content-library capability. Saving from Campaign creates "
|
|
"a draft with its declared required-field contract and never publishes it automatically. Consumers show missing required fields before "
|
|
"applying content. Inserting content changes only the current Campaign draft; existing Campaign versions "
|
|
"and Template revisions remain unchanged."
|
|
),
|
|
layer="available",
|
|
documentation_types=("admin", "user"),
|
|
audience=("operator", "module_admin", "campaign_author"),
|
|
related_modules=("campaigns",),
|
|
translations={
|
|
"de": {
|
|
"title": "Wiederverwendbare Inhaltsbausteine und Kampagnenteile",
|
|
"summary": "Bereichsbezogene, versionierte Inhalte erstellen und in berechtigten Modulen verwenden.",
|
|
"body": (
|
|
"Inhaltsbausteine speichern Text- und HTML-Fassungen, Verwendungszwecke, Sprache, Geltungsbereich, Revision und "
|
|
"Veröffentlichungsstatus in Templates. Campaign kann Bausteine oder vollständige E-Mail-Teile über die optionale "
|
|
"Inhaltsbibliothek laden. Das Speichern aus Campaign legt einen Entwurf mit dem deklarierten Pflichtfeldvertrag an und "
|
|
"veröffentlicht ihn niemals automatisch. Fehlende Pflichtfelder werden vor dem Anwenden angezeigt. "
|
|
"Das Einfügen ändert nur den aktuellen Kampagnenentwurf; bestehende Kampagnenversionen und Template-Revisionen bleiben unverändert."
|
|
),
|
|
}
|
|
},
|
|
metadata={
|
|
"seed": True,
|
|
"help_contexts": [
|
|
"templates.field.type",
|
|
"templates.field.usages",
|
|
"campaign.template.content-library",
|
|
],
|
|
},
|
|
),
|
|
DocumentationTopic(
|
|
id="templates.printable-output",
|
|
title="Printable template output",
|
|
summary="Render labels, envelopes, letters, and list layouts from frozen input snapshots.",
|
|
body=(
|
|
"Preview output may use a draft revision. Final output requires a published revision and an "
|
|
"idempotency key. Results pin the template hash, input hash, renderer version, item/page counts, "
|
|
"diagnostics, and output digest. Files stores artifacts when available and authorized; otherwise "
|
|
"Templates provides a bounded download. The existing 5 MiB output ceiling is enforced while substituting tokens and composing items, "
|
|
"including UTF-8 bytes, escaping, separators, and the final HTML wrapper. Oversized expansion stops before the whole bundle is allocated "
|
|
"or any output is persisted; reduce the selected items or template content and retry. Browser printing is the supported baseline output path."
|
|
),
|
|
layer="available",
|
|
documentation_types=("admin", "user"),
|
|
audience=("operator", "module_admin", "product_owner"),
|
|
related_modules=("files", "dist_lists", "campaigns", "audit"),
|
|
translations={
|
|
"de": {
|
|
"title": "Druckfähige Vorlagenausgabe",
|
|
"summary": "Etiketten, Umschläge, Briefe und Listenlayouts aus eingefrorenen Eingabe-Snapshots rendern.",
|
|
"body": (
|
|
"Eine Vorschau darf eine Entwurfsrevision verwenden. Endgültige Ausgabe verlangt eine veröffentlichte Revision und einen "
|
|
"Idempotenzschlüssel. Ergebnisse legen Vorlagenhash, Eingabehash, Renderer-Version, Element-/Seitenanzahl, Diagnosen und "
|
|
"Ausgabe-Digest fest. Files speichert Artefakte, wenn die Fähigkeit verfügbar und berechtigt ist; andernfalls stellt Templates "
|
|
"einen begrenzten Download bereit. Die bestehende Ausgabegrenze von 5 MiB wird bereits beim Ersetzen von Platzhaltern und Zusammenstellen "
|
|
"der Elemente durchgesetzt, einschließlich UTF-8-Bytes, Maskierung, Trennzeichen und abschließender HTML-Hülle. Übermäßige Erweiterung "
|
|
"stoppt vor dem vollständigen Speicheraufbau oder Speichern einer Ausgabe; reduzieren Sie die ausgewählten Elemente oder den Vorlageninhalt "
|
|
"und versuchen Sie es erneut. Drucken im Browser ist der unterstützte grundlegende Ausgabepfad."
|
|
),
|
|
}
|
|
},
|
|
metadata={
|
|
"seed": True,
|
|
"help_contexts": [
|
|
"templates.preview",
|
|
"templates.action.validate-preview",
|
|
"templates.action.render-final",
|
|
"templates.evidence.render",
|
|
],
|
|
},
|
|
),
|
|
DocumentationTopic(
|
|
id="templates.reference.fields-and-consequences",
|
|
title="Template fields and lifecycle consequences",
|
|
summary="Scope, usage, data contract, publication, rendering, and deletion semantics for reusable Templates.",
|
|
body=(
|
|
"Visibility determines which tenant, group, or user scope may discover the Template; inherited Templates may be read-only. "
|
|
"Usages are capability contexts that constrain where a Template may be selected. Required fields form the compatibility "
|
|
"contract checked against supplied data before rendering. Saving creates a new immutable revision. Publishing marks one "
|
|
"revision as available for final output without rewriting older revisions or evidence. Preview validates and renders bounded "
|
|
"sample output; final rendering requires the published revision and records template, input, and output hashes plus renderer "
|
|
"evidence. Files may retain the artifact when its optional capability is available. Deletion removes the Template from future "
|
|
"selection but does not rewrite retained render evidence."
|
|
),
|
|
layer="available",
|
|
documentation_types=("admin", "user"),
|
|
audience=("operator", "module_admin", "product_owner"),
|
|
related_modules=("files", "dist_lists", "campaigns", "audit", "policy"),
|
|
translations={
|
|
"de": {
|
|
"title": "Vorlagenfelder und Folgen des Lebenszyklus",
|
|
"summary": (
|
|
"Semantik von Geltungsbereich, Verwendung, Datenvertrag, Veröffentlichung, Rendering und Löschung wiederverwendbarer Vorlagen."
|
|
),
|
|
"body": (
|
|
"Die Sichtbarkeit bestimmt, in welchem Mandanten-, Gruppen- oder Benutzerbereich eine Vorlage auffindbar ist; geerbte "
|
|
"Vorlagen können schreibgeschützt sein. Verwendungen sind Fähigkeitskontexte, die begrenzen, wo eine Vorlage ausgewählt werden "
|
|
"darf. Pflichtfelder bilden den Kompatibilitätsvertrag, der vor dem Rendern gegen bereitgestellte Daten geprüft wird. Speichern "
|
|
"erzeugt eine neue unveränderliche Revision. Veröffentlichen markiert eine Revision für endgültige Ausgabe, ohne ältere "
|
|
"Revisionen oder Nachweise umzuschreiben. Die Vorschau validiert und rendert begrenzte Beispielausgabe; endgültiges Rendering "
|
|
"verlangt die veröffentlichte Revision und zeichnet Vorlagen-, Eingabe- und Ausgabehash sowie Renderer-Nachweise auf. Files "
|
|
"darf das Artefakt aufbewahren, wenn die optionale Fähigkeit verfügbar ist. Löschen entfernt die Vorlage aus zukünftiger "
|
|
"Auswahl, schreibt aber aufbewahrte Rendering-Nachweise nicht um."
|
|
),
|
|
}
|
|
},
|
|
metadata={
|
|
"kind": "reference",
|
|
"seed": True,
|
|
"help_contexts": [
|
|
"templates.field.type",
|
|
"templates.field.locale",
|
|
"templates.field.visibility",
|
|
"templates.field.usages",
|
|
"templates.field.required-data",
|
|
"templates.action.publish",
|
|
"templates.action.delete",
|
|
],
|
|
"consequence_classes": {
|
|
"save_revision": "Creates a new immutable Template revision.",
|
|
"publish_revision": "Makes the selected immutable revision eligible for final consumer output.",
|
|
"render_final": "Creates retained render evidence and may persist an artifact through Files.",
|
|
"delete_template": "Prevents future selection without rewriting retained revisions or render evidence.",
|
|
},
|
|
},
|
|
),
|
|
)
|
|
|
|
|
|
def _router(_context: ModuleContext):
|
|
from govoplan_templates.backend.router import router
|
|
|
|
return router
|
|
|
|
|
|
def _catalog(context: ModuleContext):
|
|
from govoplan_templates.backend.capabilities import catalog_capability
|
|
|
|
return catalog_capability(context)
|
|
|
|
|
|
def _renderer(context: ModuleContext):
|
|
from govoplan_templates.backend.capabilities import renderer_capability
|
|
|
|
return renderer_capability(context)
|
|
|
|
|
|
def _content_library(context: ModuleContext):
|
|
from govoplan_templates.backend.capabilities import content_library_capability
|
|
|
|
return content_library_capability(context)
|
|
|
|
|
|
def _dsar_provider(_context: ModuleContext) -> TemplatesDsarProvider:
|
|
return TemplatesDsarProvider()
|
|
|
|
|
|
def _tenant_summary(session, tenant_id: str) -> dict[str, int]:
|
|
return {
|
|
"templates": session.query(template_models.TemplateDefinition)
|
|
.filter(
|
|
template_models.TemplateDefinition.tenant_id == tenant_id,
|
|
template_models.TemplateDefinition.deleted_at.is_(None),
|
|
)
|
|
.count(),
|
|
"template_renders": session.query(template_models.TemplateRender)
|
|
.filter(
|
|
template_models.TemplateRender.tenant_id == tenant_id,
|
|
)
|
|
.count(),
|
|
}
|
|
|
|
|
|
manifest = ModuleManifest(
|
|
id=MODULE_ID,
|
|
name=MODULE_NAME,
|
|
version=MODULE_VERSION,
|
|
dependencies=(),
|
|
optional_dependencies=("files", "dist_lists", "campaigns", "audit"),
|
|
optional_capabilities=(CAPABILITY_FILES_ARTIFACT_STORE,),
|
|
provides_interfaces=(
|
|
ModuleInterfaceProvider(
|
|
name=CAPABILITY_TEMPLATE_CATALOG, version=MODULE_VERSION
|
|
),
|
|
ModuleInterfaceProvider(
|
|
name=CAPABILITY_TEMPLATE_CONTENT_LIBRARY,
|
|
version=MODULE_VERSION,
|
|
),
|
|
ModuleInterfaceProvider(
|
|
name=CAPABILITY_TEMPLATE_RENDERER, version=MODULE_VERSION
|
|
),
|
|
ModuleInterfaceProvider(name=TEMPLATES_DSAR_CAPABILITY, version="0.1.0"),
|
|
),
|
|
requires_interfaces=(
|
|
ModuleInterfaceRequirement(
|
|
name=CAPABILITY_FILES_ARTIFACT_STORE,
|
|
version_min="0.1.14",
|
|
version_max_exclusive="0.2.0",
|
|
optional=True,
|
|
),
|
|
),
|
|
permissions=PERMISSIONS,
|
|
role_templates=ROLE_TEMPLATES,
|
|
nav_items=(
|
|
NavItem(
|
|
path="/templates",
|
|
label=MODULE_NAME,
|
|
icon="layout-template",
|
|
required_any=(
|
|
READ_SCOPE,
|
|
WRITE_SCOPE,
|
|
PUBLISH_SCOPE,
|
|
RENDER_SCOPE,
|
|
ADMIN_SCOPE,
|
|
),
|
|
order=75,
|
|
),
|
|
),
|
|
frontend=FrontendModule(
|
|
module_id=MODULE_ID,
|
|
package_name="@govoplan/templates-webui",
|
|
routes=(
|
|
FrontendRoute(
|
|
path="/templates",
|
|
component="TemplatesPage",
|
|
required_any=(
|
|
READ_SCOPE,
|
|
WRITE_SCOPE,
|
|
PUBLISH_SCOPE,
|
|
RENDER_SCOPE,
|
|
ADMIN_SCOPE,
|
|
),
|
|
order=75,
|
|
),
|
|
),
|
|
nav_items=(
|
|
NavItem(
|
|
path="/templates",
|
|
label=MODULE_NAME,
|
|
icon="layout-template",
|
|
required_any=(
|
|
READ_SCOPE,
|
|
WRITE_SCOPE,
|
|
PUBLISH_SCOPE,
|
|
RENDER_SCOPE,
|
|
ADMIN_SCOPE,
|
|
),
|
|
order=75,
|
|
),
|
|
),
|
|
product_areas=(
|
|
ProductAreaContribution(
|
|
id="records-documents",
|
|
module_id=MODULE_ID,
|
|
label="i18n:govoplan-core.product_area.records_documents",
|
|
icon="folder",
|
|
description="i18n:govoplan-core.product_area.records_documents_description",
|
|
surface_ids=("templates.nav.templates", "templates.route.templates"),
|
|
order=30,
|
|
),
|
|
),
|
|
view_surfaces=(
|
|
ViewSurface(
|
|
id="templates.page",
|
|
module_id=MODULE_ID,
|
|
kind="route",
|
|
label="Templates",
|
|
order=75,
|
|
),
|
|
ViewSurface(
|
|
id="templates.library",
|
|
module_id=MODULE_ID,
|
|
kind="section",
|
|
label="Template library",
|
|
order=10,
|
|
),
|
|
ViewSurface(
|
|
id="templates.editor",
|
|
module_id=MODULE_ID,
|
|
kind="section",
|
|
label="Template editor",
|
|
order=20,
|
|
),
|
|
ViewSurface(
|
|
id="templates.preview",
|
|
module_id=MODULE_ID,
|
|
kind="section",
|
|
label="Template preview and output",
|
|
order=30,
|
|
),
|
|
),
|
|
),
|
|
route_factory=_router,
|
|
capability_factories={
|
|
CAPABILITY_TEMPLATE_CATALOG: _catalog,
|
|
CAPABILITY_TEMPLATE_CONTENT_LIBRARY: _content_library,
|
|
CAPABILITY_TEMPLATE_RENDERER: _renderer,
|
|
TEMPLATES_DSAR_CAPABILITY: _dsar_provider,
|
|
},
|
|
capability_documentation={
|
|
TEMPLATES_DSAR_CAPABILITY: CapabilityDocumentation(
|
|
label="Templates data-subject request provider",
|
|
summary=(
|
|
"Exports minimized template-author and render attribution without "
|
|
"template, input, or output payloads."
|
|
),
|
|
contract_version="0.1.0",
|
|
),
|
|
},
|
|
tenant_summary_providers=(_tenant_summary,),
|
|
migration_spec=MigrationSpec(
|
|
module_id=MODULE_ID,
|
|
metadata=Base.metadata,
|
|
script_location=str(Path(__file__).with_name("migrations") / "versions"),
|
|
retirement_supported=True,
|
|
retirement_provider=drop_table_retirement_provider(
|
|
template_models.TemplateRender,
|
|
template_models.TemplateRevision,
|
|
template_models.TemplateDefinition,
|
|
label=MODULE_NAME,
|
|
),
|
|
retirement_notes=(
|
|
"Destructive retirement removes template definitions, immutable revisions, bounded outputs, "
|
|
"and render evidence after the installer captures a database snapshot."
|
|
),
|
|
),
|
|
uninstall_guard_providers=(
|
|
persistent_table_uninstall_guard(
|
|
template_models.TemplateDefinition,
|
|
template_models.TemplateRevision,
|
|
template_models.TemplateRender,
|
|
label=MODULE_NAME,
|
|
),
|
|
),
|
|
documentation=(
|
|
DocumentationTopic(
|
|
id="templates.data-subject-requests",
|
|
title="Template data-subject requests",
|
|
summary=(
|
|
"Export template-author and render activity without content or supplied data."
|
|
),
|
|
body=(
|
|
"Templates correlates only an exact tenant account identifier and can "
|
|
"narrow an already verified search to one template, revision, or render. "
|
|
"It returns minimized definition, publication, and render lifecycle "
|
|
"metadata. Template text and HTML, required fields, layouts, metadata, "
|
|
"render input snapshots, filenames, diagnostics, artifact references, "
|
|
"output bytes, hashes, and idempotency keys are excluded. Rendered "
|
|
"business data belongs to the supplying module and is not inferred from "
|
|
"opaque Template payloads. Attribution remains retained with immutable "
|
|
"definition and render evidence."
|
|
),
|
|
layer="configured",
|
|
documentation_types=("admin", "user"),
|
|
audience=("user", "operator", "module_admin", "auditor"),
|
|
related_modules=("core", "files", "campaigns", "audit"),
|
|
order=90,
|
|
translations={
|
|
"de": {
|
|
"title": "Betroffenenanfragen für Vorlagen",
|
|
"summary": "Aktivität von Vorlagenautoren und Renderläufen ohne Inhalt oder bereitgestellte Daten exportieren.",
|
|
"body": (
|
|
"Templates gleicht nur eine exakte mandantenbezogene Kontokennung ab und kann eine bereits verifizierte Suche auf eine "
|
|
"Vorlage, Revision oder einen Renderlauf begrenzen. Ausgegeben werden minimierte Lebenszyklusmetadaten für Definition, "
|
|
"Veröffentlichung und Rendering. Vorlagentext und -HTML, Pflichtfelder, Layouts, Metadaten, Eingabe-Snapshots, Dateinamen, "
|
|
"Diagnosen, Artefaktverweise, Ausgabebytes, Hashes und Idempotenzschlüssel sind ausgeschlossen. Gerenderte Fachdaten gehören "
|
|
"dem bereitstellenden Modul und werden nicht aus undurchsichtigen Vorlagennutzdaten abgeleitet. Die Zuordnung bleibt mit "
|
|
"unveränderlichen Definitions- und Rendering-Nachweisen erhalten."
|
|
),
|
|
}
|
|
},
|
|
metadata={
|
|
"help_contexts": ["templates.page", "privacy.data-subject-requests"],
|
|
"consequence_classes": {
|
|
"export_template_attribution": "Returns minimized author, publication, and render activity.",
|
|
"exclude_template_payloads": "Does not return template content or render inputs and outputs.",
|
|
},
|
|
},
|
|
),
|
|
*DOCUMENTATION,
|
|
),
|
|
architecture=declared_module_architecture(
|
|
layer="content_records_evidence",
|
|
kind="domain",
|
|
maturity="vertical_slice",
|
|
documentation_ref="docs/TEMPLATE_BOUNDARY.md",
|
|
test_ref="tests/test_templates.py",
|
|
known_limits=(
|
|
"The baseline emits safe deterministic HTML/text for browser or OS printing; PDF and printer delivery remain connector concerns.",
|
|
),
|
|
supported_authority_modes=("native_authoritative",),
|
|
owned_concepts=(
|
|
"template definition",
|
|
"template revision",
|
|
"template render evidence",
|
|
),
|
|
non_owned_concepts=("recipient", "campaign", "file asset", "printer endpoint"),
|
|
recovery_docs=("docs/TEMPLATE_BOUNDARY.md",),
|
|
security_docs=("docs/TEMPLATE_BOUNDARY.md",),
|
|
operations_docs=("README.md",),
|
|
),
|
|
)
|
|
|
|
|
|
manifest = with_documentation_structured_translations(
|
|
manifest, locale="de", translations=GERMAN_STRUCTURED_TRANSLATIONS
|
|
)
|
|
|
|
|
|
def get_manifest() -> ModuleManifest:
|
|
return manifest
|