diff --git a/pyproject.toml b/pyproject.toml index 4b54874..0e2fe78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-datasources" -version = "0.1.21" +version = "0.1.22" description = "Governed datasource catalogue, staging, and materialization lifecycle for GovOPlaN." readme = "README.md" requires-python = ">=3.12" diff --git a/src/govoplan_datasources/__init__.py b/src/govoplan_datasources/__init__.py index d4cbee8..2b1b51f 100644 --- a/src/govoplan_datasources/__init__.py +++ b/src/govoplan_datasources/__init__.py @@ -1,3 +1,3 @@ """GovOPlaN Datasources module.""" -__version__ = "0.1.21" +__version__ = "0.1.22" diff --git a/src/govoplan_datasources/backend/manifest.py b/src/govoplan_datasources/backend/manifest.py index 33fdac3..8cc74f5 100644 --- a/src/govoplan_datasources/backend/manifest.py +++ b/src/govoplan_datasources/backend/manifest.py @@ -65,7 +65,7 @@ from govoplan_datasources.backend.payloads import ExternalArtifactPayloadBackend MODULE_ID = "datasources" MODULE_NAME = "Datasources" -MODULE_VERSION = "0.1.21" +MODULE_VERSION = "0.1.22" DATASOURCE_INTERFACE_VERSION = "0.2.0" ARCHITECTURE = ModuleArchitectureDeclaration( @@ -252,8 +252,7 @@ def _tenant_summary(session, tenant_id: str) -> dict[str, int]: session.query(datasource_models.DatasourceStageRecord) .filter( datasource_models.DatasourceStageRecord.tenant_id == tenant_id, - datasource_models.DatasourceStageRecord.state - == "awaiting_approval", + datasource_models.DatasourceStageRecord.state == "awaiting_approval", ) .count() ), @@ -498,6 +497,27 @@ manifest = ModuleManifest( audience=("user", "operator", "module_admin", "data_steward", "auditor"), related_modules=("core", "connectors", "dataflow", "reporting"), order=69, + translations={ + "de": { + "title": "Betroffenenanfragen für Datenquellen", + "summary": ( + "Gesteuerte Datenquellenkopien identifizieren und dabei Grenzen für Zugangsdaten, Nutzdaten und unveränderliche " + "Nachweise wahren." + ), + "body": ( + "Datasources gleicht exakte mandantenbezogene Kennungen für Katalog, Governance-Verweis, Materialisierung, Nutzdaten, " + "Stufe, Veröffentlichung und Lebenszyklusnachweis sowie minimierte Betriebszuordnungen zu Konto, Identität oder " + "Mitgliedschaft ab. DSAR-Ergebnisse kopieren niemals Connector-/Providerverweise, Speicherorte, Zugangsdaten, beliebige " + "Zeilen, Schemata, Validierungsstichproben, Metadaten, Herkunftstexte, Checkpoints, Idempotenzmaterial oder Hashes. " + "Beliebige tabellarische Nutzdaten werden nicht nach Kennungen durchsucht, weil dies unvollständig und schemaabhängig wäre " + "und Daten unbeteiligter Personen offenlegen könnte; das maßgebliche Quellmodul muss Betroffenenmerkmale finden und " + "korrigieren. Eine nicht hochgestufte Stufe oder nicht referenzierte Nutzdaten können idempotent gelöscht werden. " + "Veröffentlichter Katalogzustand, hochgestufte Stufen, referenzierte Nutzdaten, unveränderliche Materialisierungen, " + "Governance-Verweise, Veröffentlichungen, Sperren und Betriebszuordnungen erfordern die Prüfung durch Data Stewards und " + "eine Korrektur an der Quelle. Nach der Korrektur müssen nachgelagerte Dataflow- und Reporting-Ausgaben aktualisiert werden." + ), + } + }, metadata={ "seed": True, "help_contexts": [ @@ -543,6 +563,28 @@ manifest = ModuleManifest( "search", ), order=70, + translations={ + "de": { + "title": "Lebenszyklus einer Datenquelle", + "summary": ( + "Gesteuerte Live-, Cache- und statische Daten-/Registereinträge mit Staging, eingefrorenen Zuständen, Herkunft und " + "institutionellem Eigentumskontext." + ), + "body": ( + "Datasources ist der providerneutrale Katalog für Dataflow, Workflow, Reporting und richtlinienbewusste Module. Statische " + "Daten werden vor der Hochstufung bereitgestellt. Cache-Daten aktualisieren Connector-Ursprünge in unveränderliche " + "Materialisierungen. Live-Daten werden über einen Connector gelesen und können für reproduzierbare Nachweise eingefroren " + "werden. Connectors besitzt Protokolle und Zugangsdaten; Datasources besitzt Datenidentität, Herkunft, Lebenszyklus, " + "Lesesemantik und den typisierten Governance-Katalog für Hoheit, Zweck, Qualität, Aktualität, Klassifikation, Korrektur " + "sowie abhängige Services, Flows, Berichte, Kontrollen und Entscheidungen. Für Live-Vorschauen bewahrt es Quellmodus, " + "strukturierten Gesundheitszustand, deklarierte Pushdown-Unterstützung und wirksame Zeilen-, Byte- und Zeitgrenzen. " + "Sichtbarkeit von Governance-Metadaten gewährt keinen Zugriff auf geschützte Zeilen. Ist Search aktiviert, indiziert das " + "Modul nur begrenzte Katalogbezeichnungen und governance-sichere Facetten und prüft vor einem Treffer die aktuelle " + "Katalogberechtigung erneut. Zeilen, Schemata, Connector-Verweise, Zugangsdaten, beliebige Metadaten und Herkunft werden " + "niemals in den Suchindex kopiert." + ), + } + }, metadata={ "seed": True, "help_contexts": [ @@ -582,6 +624,30 @@ manifest = ModuleManifest( "risk_compliance", ), order=71, + translations={ + "de": { + "title": "Datenhoheit und Governance einer Datenquelle", + "summary": ( + "Erläutern, wer Datenbedeutung, Hoheit, Korrektur, Datenschutz, Qualität, Aktualität, Aufbewahrung und abhängige " + "Verwendungen verantwortet." + ), + "body": ( + "Der Hoheitsmodus gibt an, ob GovOPlaN, ein externes System, eine synchronisierte Projektion, ein Overlay oder ein " + "verknüpfter Verweis die Daten steuert. Maßgebliche Quelle, Eigentum, Data Steward, verantwortliche Organisation/Funktion, " + "Schemaeigentum, Datenschutzprofil, Aufbewahrungsrichtlinie, Übermittlungsvereinbarung, Rechtsgrundlage, Sperren, " + "Korrekturverfahren, Zwecke, amtliche Schlüssel und bekannte Grenzen bilden den auffindbaren institutionellen Kontext. " + "Ein Aufbewahrungsrichtlinienverweis bezeichnet eine externe Regel im Eigentum von Policy; der lokale versionierte " + "Aufbewahrungsvertrag steuert die vorschaufähige Behandlung von Stufen und Nutzdaten. Aufbewahrung überstimmt niemals " + "gesetzliche Sperren, die aktuelle Materialisierung oder Veröffentlichungsnachweise. Ein Verweis auf eine " + "Übermittlungsvereinbarung dokumentiert die gesteuerte Vereinbarung für externen Austausch; er gewährt weder " + "Connector-Zugangsdaten noch Empfängerzugriff oder Befugnis zum Export klassifizierter Zeilen. Aktualitäts- und " + "Qualitätsrichtlinien sind typisierte JSON-Verträge, die mit Materialisierungsnachweisen aufbewahrt werden. Datasources " + "setzt die deklarierten begrenzten Regeln für tabellarische Stufen und die Schemarichtlinie durch; ursprungs- oder " + "verbraucherspezifische Kontrollen verbleiben beim Provider oder der nutzenden Kontrolle, die Unterstützung erklärt. " + "Metadatensichtbarkeit gewährt niemals Zeilenzugriff." + ), + } + }, metadata={ "seed": True, "help_contexts": [ @@ -614,6 +680,30 @@ manifest = ModuleManifest( audience=("operator", "module_admin", "data_steward", "auditor"), related_modules=("policy", "access", "audit", "connectors"), order=72, + translations={ + "de": { + "title": "Sichtbarkeit von Datenquellen und Feldern", + "summary": ( + "Kontrollen für Quelle, Materialisierung, Feld und Zeile anwenden, bevor geschützte Zeilen Datasources verlassen." + ), + "body": ( + "Eine lokale Sichtbarkeitsrichtlinie kann Auffinden und Lesen nach Konto, Mitgliedschaft, Identität, Gruppe, Rolle, " + "Dienstkonto oder Authentifizierungsmethode einschränken. Materialisierungs-ACLs schützen zusätzlich aktuelle und " + "eingefrorene Revisionen. Feldregeln klassifizieren ein Feld und ersetzen seinen Wert durch null oder lassen es weg, " + "sofern keine passende Erlaubnis-ACL vorliegt. Zeilenfilter vergleichen ein konfiguriertes Feld mit Konto-, " + "Mitgliedschafts-, Identitäts-, Dienstkonto-, Gruppen-, Rollen- oder Funktionszuweisungsmerkmalen der Hauptperson; alle " + "konfigurierten Filter und Richtlinienebenen müssen eine Zeile erlauben. Datasources wendet diese Kontrollen an, bevor " + "Zeilen die Providergrenze verlassen, und liefert einen undurchsichtigen Fingerabdruck der erlaubten Ansicht, gebunden an " + "Basisrevision, wirksame Richtlinien und relevante Hauptpersonenmerkmale. Verweigerte und gefilterte Lesevorgänge erzeugen " + "Auditnachweise mit Ergebnissen und Richtliniendiagnosen, niemals geschützten Werten, Provider-Speicherorten, beliebigen " + "Metadaten oder Herkunftstexten. Ein optionaler Zugriffsrichtlinienverweis delegiert hierarchische Ebenen an Policy, das " + "lokales Verhalten nur verschärfen kann. Eine nicht auflösbare Referenz, ein nicht verfügbarer konfigurierter Provider oder " + "eine fehlerhafte Richtlinie schließt sicher. Ohne Policy und ohne Referenz bleibt die lokale Richtlinie vollständig " + "nutzbar. Eingefrorene Lesevorgänge setzen die aktuelle lokale Richtlinie gemeinsam mit einer getrennten einschränkenden " + "Richtlinie aus dem eingefrorenen Governance-Snapshot durch." + ), + } + }, metadata={ "seed": True, "help_contexts": [ @@ -661,6 +751,31 @@ manifest = ModuleManifest( "workflow_engine", ), order=73, + translations={ + "de": { + "title": "Bereitgestellte und erzeugte Datenquellenrevisionen validieren", + "summary": ( + "Deterministische Qualitätsregeln und Schemerichtlinien anwenden, bevor bereitgestellte oder erzeugte Daten nutzbar werden." + ), + "body": ( + "Tabellarische Stufen prüfen konfigurierte Zeilenanzahl, Pflichtfelder, Feldform, Nullbarkeit, Eindeutigkeit, Zahlenbereiche " + "und begrenzte Referenzmengen. Fehler halten die Stufe prüfbar, blockieren aber die Hochstufung; Warnungen bleiben sichtbar " + "und erlauben eine ausdrückliche Hochstufung. Aktualisierungen vergleichen das erkannte Schema mit dem aktuellen Ziel und " + "klassifizieren jede Änderung als kompatibel, Warnung oder brechend. Diagnosen zeigen Anzahlen und begrenzte Zeilennummern, " + "niemals Feldwerte. Richtlinienversion und -hash, Diagnosen und Schemadifferenz werden bei erfolgreicher Hochstufung in die " + "unveränderliche Materialisierungsherkunft kopiert. Eine Provider-Veröffentlichung wendet dasselbe Gate vor jeder " + "Katalogwirkung an, bewahrt Validierungsnachweise an der unveränderlichen Ausgaberevision, serialisiert die " + "Veröffentlichungsidentität über PostgreSQL-Worker und sendet ein transaktionales Abschlussereignis. Große Ausgaben können " + "stattdessen einen dauerhaften providerneutralen Artefaktverweis mit festgelegtem Speicherort, SHA-256-Prüfsumme, Schema, " + "Fingerabdruck und Größe liefern. Das konfigurierte Nutzdaten-Backend prüft das Artefakt und stellt begrenzte Lesevorgänge " + "bereit. Inhaltsregeln verlangen prüfsummen- und richtliniengebundene Provider-Nachweise; fehlen sie, entsteht eine " + "unveränderliche prüfpflichtige Materialisierung, ohne den aktuellen Zustand der Datenquelle zu verändern. Warnungen und " + "Prüfpflicht bleiben für Workflow-Übergaben erhalten. Eine versionierte Freigaberichtlinie kann ein zurechenbares, " + "getrenntes Quorum verlangen, bevor eine Stufe oder Aktualisierung aktuell wird; Aufbewahrung verwendet vor jeder " + "ausdrücklichen administrativen Anwendung eine frische gehashte Vorschau." + ), + } + }, metadata={ "seed": True, "help_contexts": [ @@ -701,7 +816,24 @@ manifest = ModuleManifest( "audit", ), order=74, + translations={ + "de": { + "title": "Datenquellenfelder und Folgen des Lebenszyklus", + "summary": "Semantik von Live-, Cache- und statischem Modus, Staging, Hochstufung, Aktualisierung, Einfrieren und Stilllegung.", + "body": ( + "Der Schlüssel einer Datenquelle ist ihre stabile Katalogidentität für Verbraucher. Live-Modus liest über einen " + "verfügbaren Ursprung, Cache-Modus aktualisiert einen Ursprung in unveränderliche Revisionen und statischer Modus stuft " + "hochgeladene Inhalte aus dem Staging hoch. Stufen sind begrenzt, prüfbar und vor der Hochstufung nicht nutzbar. Die " + "Hochstufung legt eine gesteuerte Datenquelle an oder aktualisiert sie und ergänzt eine unveränderliche Materialisierung. " + "Ist eine Freigabe konfiguriert, erzeugt eine Aktualisierung zunächst eine nicht nutzbare Stufe; nur ein bestätigtes Quorum " + "erlaubt die Hochstufung. Einfrieren kennzeichnet einen unveränderlichen adressierbaren Zustand für reproduzierbare " + "Ausführung. Eine Stilllegung entfernt die Datenquelle aus neuen Definitionen, während erhaltene Materialisierungsverweise " + "gesteuert bleiben. Fehlt Connectors, ist die Ursprungsregistrierung deaktiviert; lokaler Katalog und Staging bleiben nutzbar." + ), + } + }, metadata={ + "kind": "reference", "seed": True, "help_contexts": [ "datasources.field.origin", diff --git a/tests/test_interface_documentation_contract.py b/tests/test_interface_documentation_contract.py index 4d3d5ef..d6fac8e 100644 --- a/tests/test_interface_documentation_contract.py +++ b/tests/test_interface_documentation_contract.py @@ -6,6 +6,14 @@ from govoplan_datasources.backend.manifest import manifest class DatasourcesInterfaceDocumentationContractTests(unittest.TestCase): + def test_all_static_topics_have_complete_german_content(self) -> None: + for topic in manifest.documentation: + german = (topic.translations or {}).get("de", {}) + self.assertEqual({"title", "summary", "body"}, set(german), topic.id) + self.assertTrue( + all(str(value).strip() for value in german.values()), topic.id + ) + def test_route_and_surfaces_remain_declared(self) -> None: frontend = manifest.frontend self.assertIsNotNone(frontend) @@ -34,8 +42,12 @@ class DatasourcesInterfaceDocumentationContractTests(unittest.TestCase): lifecycle_controls = topics["datasources.approval-and-retention"] self.assertIn("datasources.staging", lifecycle.metadata["help_contexts"]) - self.assertIn("datasources.field.authority-mode", governance.metadata["help_contexts"]) - self.assertIn("datasources.staging.validation", quality.metadata["help_contexts"]) + self.assertIn( + "datasources.field.authority-mode", governance.metadata["help_contexts"] + ) + self.assertIn( + "datasources.staging.validation", quality.metadata["help_contexts"] + ) self.assertIn( "datasources.field.visibility-policy", visibility.metadata["help_contexts"], @@ -46,7 +58,10 @@ class DatasourcesInterfaceDocumentationContractTests(unittest.TestCase): self.assertIn("datasources.action.promote", reference.metadata["help_contexts"]) self.assertIn("freeze", reference.metadata["consequence_classes"]) self.assertIn("retire", reference.metadata["consequence_classes"]) - self.assertIn("datasources.action.approve", lifecycle_controls.metadata["help_contexts"]) + self.assertEqual("reference", reference.metadata["kind"]) + self.assertIn( + "datasources.action.approve", lifecycle_controls.metadata["help_contexts"] + ) self.assertIn("hash-chained lifecycle evidence", lifecycle_controls.body) self.assertTrue(lifecycle_controls.translations["de"]["body"]) diff --git a/webui/package.json b/webui/package.json index c2b215d..60b74e1 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/datasources-webui", - "version": "0.1.21", + "version": "0.1.22", "private": true, "type": "module", "main": "src/index.ts", diff --git a/webui/src/module.ts b/webui/src/module.ts index 547bf1b..9cf2199 100644 --- a/webui/src/module.ts +++ b/webui/src/module.ts @@ -10,7 +10,7 @@ const readScopes = ["datasources:catalogue:read", "datasources:source:admin"]; export const datasourcesModule: PlatformWebModule = { id: "datasources", label: "i18n:govoplan-datasources.datasources", - version: "0.1.18", + version: "0.1.22", optionalDependencies: [ "access", "audit",