diff --git a/pyproject.toml b/pyproject.toml index 27ded07..c4af413 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-dist-lists" -version = "0.1.18" +version = "0.1.19" description = "GovOPlaN operational distribution lists and governed audience expansion." readme = "README.md" requires-python = ">=3.12" diff --git a/src/govoplan_dist_lists/__init__.py b/src/govoplan_dist_lists/__init__.py index a09cb1e..b61b4c6 100644 --- a/src/govoplan_dist_lists/__init__.py +++ b/src/govoplan_dist_lists/__init__.py @@ -2,4 +2,4 @@ __all__ = ["__version__"] -__version__ = "0.1.18" +__version__ = "0.1.19" diff --git a/src/govoplan_dist_lists/backend/manifest.py b/src/govoplan_dist_lists/backend/manifest.py index 8fc9506..c81bfd9 100644 --- a/src/govoplan_dist_lists/backend/manifest.py +++ b/src/govoplan_dist_lists/backend/manifest.py @@ -31,6 +31,7 @@ from govoplan_core.core.module_guards import ( ) from govoplan_core.core.modules import ( CapabilityDocumentation, + DocumentationCondition, DocumentationTopic, FrontendModule, FrontendRoute, @@ -56,7 +57,7 @@ from govoplan_dist_lists.backend.dsar_provider import ( MODULE_ID = "dist_lists" MODULE_NAME = "Distribution Lists" -MODULE_VERSION = "0.1.18" +MODULE_VERSION = "0.1.19" READ_SCOPE = "dist_lists:list:read" WRITE_SCOPE = "dist_lists:list:write" @@ -127,6 +128,7 @@ DOCUMENTATION = ( related_modules=("core", "addresses", "identity", "campaigns", "audit"), order=90, metadata={ + "kind": "reference", "seed": True, "help_contexts": [ "dist_lists.page", @@ -139,6 +141,33 @@ DOCUMENTATION = ( "retain_frozen_snapshot": "Preserves immutable expansion and execution evidence.", }, }, + translations={ + "de": { + "title": "Datenschutzanfragen zu Verteilerlisten", + "summary": "Exakte Empfängerprojektionen ausgeben, ohne die übrige Zielgruppe offenzulegen.", + "body": ( + "Distribution Lists gleicht exakte Konto-, Identitäts-, Kontakt- und normalisierte E-Mail-Selektoren " + "mit gespeicherten Empfängereinträgen und eingefrorenen Erweiterungsschnappschüssen ab. Ein Listen-, " + "Schnappschuss- oder Eintragsverweis darf einen verifizierten Personenabgleich nur einschränken und " + "begründet niemals selbst die Identität. Jedes Ergebnis eines eingefrorenen Schnappschusses enthält nur " + "den passenden Empfänger und minimierte Kanalfakten, niemals andere Empfänger, Anfrageparameter, Diagnosen, " + "Anbieternachweise, Provenienz oder Erweiterungsprüfsummen. Exakte Kontozuordnungen für Listenerstellung, " + "Revisionen und Schnappschusserstellung werden getrennt ausgegeben. Eingefrorene Schnappschüsse, gespeicherte " + "Revisionen und Lebenszykluszuordnungen bleiben Nachweise. Das Entfernen eines aktuellen Empfängereintrags " + "oder einer personenbezogenen Liste erfordert eine neue Revision und die Prüfung nachgelagerter Verbraucher." + ), + } + }, + structured_translation_version="1", + structured_translations={ + "de": { + "consequence_classes": { + "export_subject_recipient": "Gibt nur die exakt übereinstimmende Empfängerprojektion zurück.", + "review_recipient_removal": "Erfordert eine neue Revision und die Prüfung der Auswirkungen auf Verbraucher.", + "retain_frozen_snapshot": "Bewahrt unveränderliche Erweiterungs- und Ausführungsnachweise.", + } + } + }, ), DocumentationTopic( id=f"{MODULE_ID}.boundary", @@ -152,6 +181,7 @@ DOCUMENTATION = ( layer="available", documentation_types=("admin", "user"), audience=("operator", "module_admin", "product_owner"), + conditions=(DocumentationCondition(required_scopes=(READ_SCOPE,)),), related_modules=( "addresses", "campaigns", @@ -164,6 +194,7 @@ DOCUMENTATION = ( "tasks", ), metadata={ + "kind": "workflow", "seed": True, "help_contexts": [ "dist_lists.page", @@ -172,6 +203,19 @@ DOCUMENTATION = ( "dist_lists.picker", ], }, + translations={ + "de": { + "title": "Abgrenzung von Verteilerlisten", + "summary": ( + "Distribution Lists bildet operative Verteiler getrennt von Adressbuchlisten und der Workflow-Ausführung von Umläufen ab." + ), + "body": ( + "Distribution Lists führt wiederverwendbare gemischte Empfängerdefinitionen und Erweiterungsschnappschüsse. " + "Adresslisten verbleiben im Modul Addresses und bilden ausschließlich Gruppierungen des Adressbereichs ab. " + "Workflow und Tasks führen Ausführungszustand, Reihenfolge, Fristen, Eskalation und Abschluss von Umläufen." + ), + } + }, ), DocumentationTopic( id=f"{MODULE_ID}.address-contact-resolution", @@ -190,6 +234,20 @@ DOCUMENTATION = ( audience=("operator", "module_admin", "product_owner"), related_modules=("addresses", "campaigns", "policy"), metadata={"seed": True}, + translations={ + "de": { + "title": "Kontaktpunktauflösung aus Addresses", + "summary": "Adresskontakte und -listen in zweckbezogene E-Mail- und Postkandidaten auflösen.", + "body": ( + "Wenn Addresses aktiviert ist, verwendet Distribution Lists dessen versionierten Kontaktpunktvertrag, um " + "Kommunikationszweck, angeforderte Kanäle, Adresszweck, Rückfall, Sprache, Qualität, Präferenz, Einwilligung " + "und Unterdrückung aufzulösen. Erweiterungsvorschauen erklären abgelehnte Kontaktpunkte. Eingefrorene " + "Verteilerschnappschüsse bewahren das exakt gerenderte E-Mail- oder Postziel, die Kontaktpunktkennung, " + "Quellrevision und den Fingerabdruck sowie die Entscheidungsprovenienz. Ist der neue Vertrag nicht verfügbar, " + "bleiben ältere Nachschlage- und E-Mail-Quellfähigkeiten von Addresses als Kompatibilitätsrückfall bestehen." + ), + } + }, ), DocumentationTopic( id=f"{MODULE_ID}.idm-group-resolution", @@ -208,6 +266,19 @@ DOCUMENTATION = ( audience=("operator", "module_admin", "product_owner"), related_modules=("identity", "idm"), metadata={"seed": True}, + translations={ + "de": { + "title": "Wirksame IDM-Gruppenzielgruppen", + "summary": "Typisierte IDM-Gruppen in erklärbare, zeitbezogen wirksame Identitätsempfänger erweitern.", + "body": ( + "Wenn IDM aktiviert ist, wird ein IDM-Gruppeneintrag zum Wirksamkeitszeitpunkt der Erweiterung über die " + "Fähigkeit idm.relationships aufgelöst. Wirksame Identitäten mit verknüpften Konten werden Kandidaten für " + "interne Nachrichten. Zukünftige, abgelaufene, widerrufene, inaktive und kontolose Beziehungen verbleiben " + "mit Quellrevisionen und Provenienz im Ausschlussnachweis. Ohne IDM wird der Anbieter als nicht verfügbar " + "gemeldet; lokale oder andere anbietergestützte Listen funktionieren weiter." + ), + } + }, ), DocumentationTopic( id=f"{MODULE_ID}.reference.fields-and-consequences", @@ -235,6 +306,7 @@ DOCUMENTATION = ( "workflow_engine", ), metadata={ + "kind": "reference", "seed": True, "help_contexts": [ "dist_lists.field.definition-kind", @@ -253,6 +325,37 @@ DOCUMENTATION = ( "delete_definition": "Retires the reusable definition without rewriting retained frozen snapshots.", }, }, + translations={ + "de": { + "title": "Felder und Folgen von Verteilerlisten", + "summary": ( + "Definitionsarten, Zielgruppenmodi, Wirksamkeitszeiten, Kanalanforderungen, Erweiterung und Folgen eingefrorener Schnappschüsse." + ), + "body": ( + "Statische Definitionen enthalten ausdrückliche Einträge; parametrisierte und dynamische Definitionen " + "verwenden typisierte Werte oder Anbieterresultate. Vorlagen sind wiederverwendbare Definitionen, die nicht " + "eigenständig ausgeführt werden können. Einschlusszeilen fügen Zielgruppen hinzu, Ausschlüsse entfernen sie, " + "und manuelle Übersteuerungen erfordern einen prüfbaren Grund. Wirksamkeitszeiten begrenzen die Teilnahme " + "eines Eintrags. Angeforderte Kanäle schränken Zustellmöglichkeiten ein, umgehen aber weder Policy noch " + "Einwilligung, Unterdrückung oder Anbieterentscheidungen. Speichern erzeugt eine unveränderliche Revision. " + "Die Vorschau erklärt aktuelle Empfänger und Ausschlüsse, ohne Nachweise aufzubewahren. Einfrieren hält " + "exakte Revision, Parameter, Anbieterrevisionen, Empfänger, Ausschlüsse, Provenienz und Erweiterungsprüfsumme " + "als unveränderlichen Verbrauchernachweis fest. Das Löschen einer Definition schreibt die nach ihrer Regel " + "aufbewahrten Schnappschüsse nicht um." + ), + } + }, + structured_translation_version="1", + structured_translations={ + "de": { + "consequence_classes": { + "save_revision": "Erzeugt eine neue unveränderliche Revision und bewahrt frühere Revisionen für bestehende Nachweise.", + "expand_preview": "Löst die gespeicherte Revision auf, ohne dauerhafte Zustellnachweise zu erzeugen.", + "freeze_snapshot": "Speichert exakte Erweiterungseingaben, Entscheidungen, Empfänger, Ausschlüsse, Provenienz und Prüfsumme.", + "delete_definition": "Setzt die wiederverwendbare Definition außer Betrieb, ohne aufbewahrte Schnappschüsse umzuschreiben.", + } + } + }, ), ) diff --git a/tests/test_interface_documentation_contract.py b/tests/test_interface_documentation_contract.py index 2c2ad26..7f9fa09 100644 --- a/tests/test_interface_documentation_contract.py +++ b/tests/test_interface_documentation_contract.py @@ -2,6 +2,10 @@ from __future__ import annotations import unittest +from govoplan_core.core.modules import ( + documentation_structured_translation_issues, + localizable_documentation_metadata_keys, +) from govoplan_dist_lists.backend.manifest import manifest @@ -42,6 +46,25 @@ class DistributionListsInterfaceDocumentationContractTests(unittest.TestCase): reference.metadata["consequence_classes"], ) + def test_german_reference_documentation_is_complete(self) -> None: + topics = manifest.documentation + self.assertEqual(5, len(topics)) + for topic in topics: + translation = topic.translations.get("de", {}) + self.assertTrue(translation.get("title"), topic.id) + self.assertTrue(translation.get("summary"), topic.id) + self.assertTrue(translation.get("body"), topic.id) + if localizable_documentation_metadata_keys(topic): + self.assertEqual("1", topic.structured_translation_version, topic.id) + self.assertIn("de", topic.structured_translations, topic.id) + self.assertEqual((), documentation_structured_translation_issues(topic)) + + kinds = {topic.metadata.get("kind") for topic in topics} + self.assertIn("workflow", kinds) + self.assertIn("reference", kinds) + workflow = next(topic for topic in topics if topic.metadata.get("kind") == "workflow") + self.assertTrue(workflow.conditions) + if __name__ == "__main__": unittest.main() diff --git a/webui/package.json b/webui/package.json index 00e5c95..11c539f 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/dist-lists-webui", - "version": "0.1.18", + "version": "0.1.19", "private": true, "type": "module", "main": "src/index.ts",