diff --git a/pyproject.toml b/pyproject.toml index a205c5b..a72b7cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-reporting" -version = "0.1.18" +version = "0.1.19" description = "GovOPlaN governed reporting and semantic BI module." readme = "README.md" requires-python = ">=3.12" license = { text = "AGPL-3.0-or-later" } authors = [{ name = "GovOPlaN" }] dependencies = [ - "govoplan-core>=0.1.18", + "govoplan-core>=0.1.37", "govoplan-access>=0.1.18", ] diff --git a/src/govoplan_reporting/__init__.py b/src/govoplan_reporting/__init__.py index 3d2a374..925d2af 100644 --- a/src/govoplan_reporting/__init__.py +++ b/src/govoplan_reporting/__init__.py @@ -1,3 +1,3 @@ """GovOPlaN Reporting module.""" -__version__ = "0.1.18" +__version__ = "0.1.19" diff --git a/src/govoplan_reporting/backend/manifest.py b/src/govoplan_reporting/backend/manifest.py index dda87ed..0b0c574 100644 --- a/src/govoplan_reporting/backend/manifest.py +++ b/src/govoplan_reporting/backend/manifest.py @@ -15,6 +15,7 @@ from govoplan_core.core.module_guards import ( ) from govoplan_core.core.modules import ( CapabilityDocumentation, + DocumentationCondition, DocumentationLink, DocumentationTopic, FrontendModule, @@ -82,7 +83,7 @@ from govoplan_reporting.backend.search_source import create_reporting_search_sou MODULE_ID = "reporting" MODULE_NAME = "Reporting" -MODULE_VERSION = "0.1.18" +MODULE_VERSION = "0.1.19" def _permission(scope: str, label: str, description: str) -> PermissionDefinition: @@ -528,6 +529,59 @@ manifest = ModuleManifest( "reporting.data-subject-requests", "reporting.workspace", ], + "consequence_classes": { + "export_minimized_attribution": ( + "Returns ownership and lifecycle context without report rows, parameters, or payloads." + ), + "retain_governed_evidence": ( + "Shared definitions, schedules, quality evidence, and required staff attribution remain subject to authorized review and retention." + ), + "correct_authoritative_source": ( + "Source facts must be corrected in their owner module before reports are rerun or republished." + ), + }, + }, + translations={ + "de": { + "title": "Datenschutzanfragen im Reporting", + "summary": ( + "Persönliche Arbeitsbereichsdaten und abgeleitete Berichtskopien prüfen, " + "ohne sie mit Fakten aus führenden Quellsystemen zu verwechseln." + ), + "body": ( + "Reporting gleicht innerhalb des exakten Mandanten nur ausdrückliche " + "Artefaktverweise sowie die Zuordnung oder Urheberschaft von Konten, " + "Identitäten und Mitgliedschaften ab. Die Auskunft ist bewusst minimiert: " + "Berichtszeilen, Parameter, Filter, Zustellziele, Quellinhalte, Diagnosen, " + "Provenienzinhalte und Prüfsummen werden nicht in das Ergebnis kopiert. " + "Die Quellmodule bleiben dafür verantwortlich, personenbezogene Fakten zu " + "finden und zu berichtigen; Reporting darf Personen nicht durch das Durchsuchen " + "beliebiger Aggregatergebnisse ableiten. Private gespeicherte Ansichten und " + "kurzlebige Drilldown-Kontexte können gelöscht, personenbezogene Freigaben " + "entzogen und ausdrücklich bestimmte aufbewahrte Ausführungs- oder " + "Veröffentlichungsdetails idempotent minimiert werden, während Prüfsummen " + "erhalten bleiben. Gemeinsame Ansichten, Definitionen, Zeitpläne, Qualitäts- " + "und Importnachweise sowie dienstliche Zuschreibungen erfordern eine befugte " + "Prüfung oder Aufbewahrung. Die Quelle ist zu berichtigen, bevor ein Bericht " + "erneut ausgeführt oder veröffentlicht wird." + ), + } + }, + structured_translation_version="1", + structured_translations={ + "de": { + "consequence_classes": { + "export_minimized_attribution": ( + "Gibt Zuordnungs- und Lebenszykluskontext ohne Berichtszeilen, Parameter oder Inhalte zurück." + ), + "retain_governed_evidence": ( + "Gemeinsame Definitionen, Zeitpläne, Qualitätsnachweise und erforderliche dienstliche Zuschreibungen unterliegen weiterhin befugter Prüfung und Aufbewahrung." + ), + "correct_authoritative_source": ( + "Quellfakten müssen im führenden Modul berichtigt werden, bevor Berichte erneut ausgeführt oder veröffentlicht werden." + ), + } + } }, links=( DocumentationLink( @@ -555,6 +609,102 @@ manifest = ModuleManifest( layer="available", documentation_types=("admin", "user"), audience=("user", "operator", "module_admin", "product_owner"), + conditions=(DocumentationCondition(required_scopes=(READ_SCOPE,)),), + related_modules=("datasources", "dataflow", "policy", "files", "mail"), + metadata={ + "kind": "workflow", + "help_contexts": [ + "reporting.workspace", + "reporting.definitions", + "reporting.executions", + "reporting.publications", + ], + "purpose": ( + "Create and run a reproducible report over an authorized, revision-pinned dataset." + ), + "prerequisites": [ + "The actor can read Reporting and has the additional scope required for each offered action.", + "The selected dataset and every contributing row remain authorized by their owner providers.", + ], + "steps": [ + "Select or create a dataset definition and pin an immutable source revision.", + "Define safe dimensions, measures, filters, pivots, and a report revision.", + "Run the pinned revision and review quality, policy, provenance, and diagnostics evidence.", + "Inspect authorized rows or use a signed drill context that reauthorizes every contributor.", + "Export, schedule, or publish only when the corresponding action and target are authorized.", + ], + "limitations": [ + "Reporting never replaces source-module authorization or authoritative source correction.", + "XLSX and PDF output require an installed renderer provider; native browser export is CSV or JSON.", + ], + "operational_consequences": { + "run": "Creates immutable execution, provenance, quality, diagnostic, and output-hash evidence.", + "publish": "Creates idempotent target-delivery evidence and may cause an external effect.", + "schedule": "Allows future executions under the then-current authorization and policy state.", + }, + "verification": [ + "The execution names the pinned definition and source fingerprints.", + "Quality and policy results are visible before publication evidence is accepted.", + "Drilldown and publication access are reauthorized for the current principal.", + ], + }, + translations={ + "de": { + "title": "Gesteuertes Reporting und semantische BI", + "summary": ( + "Reproduzierbare Berichte auf anbietergeführten Datensätzen erstellen, " + "ohne Modul- oder Zeilenberechtigungen zu umgehen." + ), + "body": ( + "Reporting fixiert Revisionen von Datensätzen, semantischen Modellen und " + "Berichten. Ausführungen bewahren Definitionsprüfsummen, Quellfingerabdrücke, " + "Richtlinienherkunft, Qualitätsnachweise, berechtigte Ergebniszeilen, Diagnosen " + "und Ausgabeprüfsummen. Sichere Dimensionen, Aggregationen, typisierte Ausdrücke, " + "Filter, Pivotierungen, gespeicherte Ansichten, Diagrammmodelle, Zeitpläne, " + "Exporte und Veröffentlichungsanbieter ersetzen ungeprüftes SQL in der " + "Darstellungsschicht. PostgreSQL führt begrenzte semantische Pläne aus, sofern " + "verfügbar. Signierte Drilldown-Kontexte autorisieren beitragende Zeilen erneut; " + "Adapter für Dateien und Mail bewahren idempotente Nachweise. Ein Datensatz kann " + "genau eine erfolgreiche veröffentlichte Dataflow-Ausführung fixieren, die nach " + "erneuter Autorisierung beider Quellgrenzen aus ihrer exakten Datasource-" + "Materialisierung gelesen wird. Dataflow und die Lesemodelle der Module bleiben " + "führende Quellen." + ), + } + }, + structured_translation_version="1", + structured_translations={ + "de": { + "purpose": ( + "Einen reproduzierbaren Bericht über einen berechtigten, revisionsgenau fixierten Datensatz erstellen und ausführen." + ), + "prerequisites": [ + "Die handelnde Person darf Reporting lesen und besitzt für jede angebotene Aktion die zusätzlich erforderliche Berechtigung.", + "Der ausgewählte Datensatz und jede beitragende Zeile bleiben durch ihre führenden Anbieter autorisiert.", + ], + "steps": [ + "Eine Datensatzdefinition auswählen oder erstellen und eine unveränderliche Quellrevision fixieren.", + "Sichere Dimensionen, Kennzahlen, Filter, Pivotierungen und eine Berichtsrevision definieren.", + "Die fixierte Revision ausführen und Qualitäts-, Richtlinien-, Provenienz- und Diagnosenachweise prüfen.", + "Berechtigte Zeilen prüfen oder einen signierten Drilldown-Kontext verwenden, der jeden Beitrag erneut autorisiert.", + "Nur mit der jeweiligen Aktions- und Zielberechtigung exportieren, planen oder veröffentlichen.", + ], + "limitations": [ + "Reporting ersetzt weder die Autorisierung der Quellmodule noch die Berichtigung in der führenden Quelle.", + "XLSX- und PDF-Ausgaben erfordern einen installierten Renderer-Anbieter; der native Browserexport unterstützt CSV und JSON.", + ], + "operational_consequences": { + "run": "Erzeugt unveränderliche Nachweise zu Ausführung, Provenienz, Qualität, Diagnosen und Ausgabeprüfsumme.", + "publish": "Erzeugt idempotente Nachweise zur Zielzustellung und kann eine externe Wirkung auslösen.", + "schedule": "Erlaubt künftige Ausführungen unter dem dann gültigen Berechtigungs- und Richtlinienstand.", + }, + "verification": [ + "Die Ausführung nennt die fixierte Definition und die Quellfingerabdrücke.", + "Qualitäts- und Richtlinienergebnisse sind sichtbar, bevor ein Veröffentlichungsnachweis akzeptiert wird.", + "Drilldown- und Veröffentlichungszugriffe werden für die aktuelle Person erneut autorisiert.", + ], + } + }, links=( DocumentationLink( label="Reporting module boundary", diff --git a/tests/test_documentation.py b/tests/test_documentation.py new file mode 100644 index 0000000..809382c --- /dev/null +++ b/tests/test_documentation.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import unittest + +from govoplan_core.core.modules import ( + documentation_structured_translation_issues, + user_workflow_scope_condition_issues, +) +from govoplan_reporting.backend.manifest import manifest + + +class ReportingDocumentationTests(unittest.TestCase): + def test_public_topics_have_complete_german_reference_content(self) -> None: + self.assertEqual(2, len(manifest.documentation)) + for topic in manifest.documentation: + translation = topic.translations.get("de", {}) + self.assertTrue( + all(translation.get(key) for key in ("title", "summary", "body")) + ) + self.assertEqual((), documentation_structured_translation_issues(topic)) + + def test_documentation_has_scope_conditioned_workflow_and_reference(self) -> None: + kinds = {topic.metadata.get("kind") for topic in manifest.documentation} + self.assertIn("workflow", kinds) + self.assertIn("reference", kinds) + for topic in manifest.documentation: + self.assertEqual((), user_workflow_scope_condition_issues(topic)) + + +if __name__ == "__main__": + unittest.main() diff --git a/webui/package.json b/webui/package.json index c80d0ad..db496e0 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/reporting-webui", - "version": "0.1.18", + "version": "0.1.19", "private": true, "type": "module", "main": "src/index.ts",