diff --git a/package.json b/package.json index 0cbdb66..eccebb3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/admin-webui", - "version": "0.1.19", + "version": "0.1.20", "private": true, "type": "module", "main": "webui/src/index.ts", diff --git a/pyproject.toml b/pyproject.toml index 681c29e..cc6269b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-admin" -version = "0.1.19" +version = "0.1.20" description = "GovOPlaN generic administration module." readme = "README.md" requires-python = ">=3.12" diff --git a/src/govoplan_admin/backend/manifest.py b/src/govoplan_admin/backend/manifest.py index 89e62cf..aab3f6f 100644 --- a/src/govoplan_admin/backend/manifest.py +++ b/src/govoplan_admin/backend/manifest.py @@ -78,7 +78,7 @@ ADMIN_ROLE_TEMPLATES = ( manifest = ModuleManifest( id="admin", name="Admin", - version="0.1.19", + version="0.1.20", permissions=ADMIN_PERMISSIONS, role_templates=ADMIN_ROLE_TEMPLATES, required_capabilities=( @@ -123,6 +123,24 @@ manifest = ModuleManifest( documentation_types=("admin", "user"), audience=("privacy_officer", "system_admin", "auditor"), related_modules=("core", "access", "audit", "ops"), + translations={ + "de": { + "title": "Abdeckung von Betroffenenanfragen in der Administration", + "summary": ( + "Die von Admin verwalteten Governance-Vorlagen enthalten keine Felder mit Betroffenen- oder " + "Betriebsidentitäten." + ), + "body": ( + "Das Admin-Modul speichert wiederverwendbare Definitionen von Governance-Vorlagen und deren Verfügbarkeit für " + "Mandanten. Diese Tabellen enthalten Berechtigungen, Vorlagenbezeichnungen und Mandantenkennungen, aber keine " + "Konten, Mitgliedschaften, Identitäten, E-Mail-Adressen, Autorinnen, Freigebenden oder andere Betroffenenverweise. " + "Admin stellt deshalb einen ausdrücklichen Provider mit leerem Ergebnis bereit, damit der Datenschutz-Arbeitsbereich " + "eine geprüfte Nichtanwendbarkeit von einer ungeklärten Abdeckungslücke unterscheiden kann. Akteursnachweise zu " + "Modul-Lebenszyklus und Konfigurationsänderungen gehören weiterhin Core, Audit, Access oder Ops und werden von deren " + "Providern geliefert." + ), + } + }, metadata={ "help_contexts": ["admin.privacy.data-subject-requests"], "coverage_classification": "reviewed_no_subject_data", @@ -135,6 +153,27 @@ manifest = ModuleManifest( body="System and tenant administration share one workspace. Available sections can include settings, configuration changes and packages, governance templates, groups, and module lifecycle controls. A missing section normally means that its owning module is disabled or the current account lacks the required authority. System appearance settings select a validated palette default. Changing the separate palette lock additionally requires policy-write authority; a system lock suppresses tenant and personal palette choices, while an unlocked default remains inheritable and overridable. The separate advanced-override policy is disabled by default and also requires policy-write authority. Enabling it permits tenants to inherit or narrow access to Core's versioned, accessibility-validated personal accent, surface, and status editor; palette locks continue to win.", documentation_types=("admin", "user"), audience=("tenant_admin", "system_admin", "operator"), + translations={ + "de": { + "title": "Administrationsarbeitsbereich verwenden", + "summary": ( + "Der Administrationsarbeitsbereich zeigt nur Bereiche, die aktivierte Module bereitstellen und für die das aktuelle " + "Konto berechtigt ist." + ), + "body": ( + "System- und Mandantenadministration teilen sich einen Arbeitsbereich. Verfügbare Bereiche können Einstellungen, " + "Konfigurationsänderungen und -pakete, Governance-Vorlagen, Gruppen und die Steuerung des Modul-Lebenszyklus umfassen. " + "Fehlt ein Bereich, ist normalerweise sein zuständiges Modul deaktiviert oder das aktuelle Konto besitzt nicht die " + "erforderliche Berechtigung. Die Systemeinstellungen für das Erscheinungsbild wählen eine validierte Standardpalette. " + "Das Ändern der getrennten Palettensperre erfordert zusätzlich die Berechtigung zum Schreiben von Richtlinien; eine " + "Systemsperre unterdrückt Mandanten- und persönliche Paletten, ein ungesperrter Standard bleibt vererbbar und " + "überschreibbar. Die getrennte Richtlinie für erweiterte Anpassungen ist standardmäßig deaktiviert und verlangt ebenfalls " + "die Richtlinienschreibberechtigung. Wird sie aktiviert, können Mandanten den Zugriff auf Cores versionierten und auf " + "Barrierefreiheit geprüften Editor für persönliche Akzent-, Flächen- und Statusfarben erben oder einschränken; " + "Palettensperren behalten Vorrang." + ), + } + }, metadata={ "kind": "reference", "help_contexts": [ @@ -155,6 +194,27 @@ manifest = ModuleManifest( documentation_types=("admin",), audience=("system_admin", "module_admin", "tenant_admin"), related_modules=("access", "policy", "views", "encryption"), + translations={ + "de": { + "title": "Module je Mandant steuern", + "summary": ( + "Systemadministrierende legen Modulobergrenzen und erzwungene Module je Mandant fest; " + "Mandanten-Moduladministrierende wählen innerhalb dieser Grenzen." + ), + "body": ( + "Die Aktivierung im Deployment installiert und lädt Modulcode für die gesamte Instanz. Die Modulsteuerung pro Mandant " + "ist eine getrennte Berechtigungsebene: Systemadministrierende markieren Module für einen Mandanten als nicht verfügbar, " + "verfügbar oder erzwungen und können auch dessen Auswahl ändern. Mandanten-Moduladministrierende dürfen nur verfügbare " + "Module aktivieren oder deaktivieren; erzwungene Module und erforderliche Abhängigkeiten bleiben wirksam. Eine " + "Modulberechtigung gewährt niemals Zugriffsrechte, und fehlerhafte Richtlinien schließen geschützte Administrationsmodule " + "sicher aus. Das Deaktivieren eines Moduls stoppt neue API-, Fähigkeits-, Zeitplan- und Worker-Aufnahmen für den Mandanten. " + "Bereits angenommene dauerhafte Arbeit bleibt in der Warteschlange und erfordert eine Betriebsentscheidung, statt " + "ausgeführt oder verworfen zu werden. Die Aktivierung eines Fähigkeitsmoduls wie Encryption stellt nur dessen Dienste " + "bereit; die Verschlüsselung von Daten bleibt eine ausdrückliche Richtlinien- oder Migrationsentscheidung des " + "zuständigen Moduls." + ), + } + }, metadata={ "kind": "workflow", "help_contexts": [ @@ -228,6 +288,27 @@ manifest = ModuleManifest( documentation_types=("admin",), audience=("system_admin", "tenant_admin"), related_modules=("tenancy", "access", "docs"), + translations={ + "de": { + "title": "Referenzsprache und Sprachpakete verwalten", + "summary": ( + "Deutsch ist Referenzsprache und Standard für Neuinstallationen, während konfigurierte Sprachwahlen von Mandanten und " + "Benutzenden wirksam bleiben." + ), + "body": ( + "Deutsch ist die maßgebliche Sprache für die Produktabnahme und Standard für ein neues System oder einen neuen Mandanten. " + "Englisch bleibt als Rückfall für den Quellcode installiert. Der eigene Administrationsbereich für Sprachpakete trennt " + "Installation, Aktivierung, Deaktivierung, Deinstallierbarkeit und den Standard für neu angelegte Mandanten von den " + "allgemeinen Systemeinstellungen. Die Kompatibilitätsmatrix leitet den Zustand jedes Pakets aus installierter Modulkennung, " + "exakter Modulversion und vorhandenem Laufzeit-Übersetzungskatalog ab; ein fehlender Katalog wird als inkompatibel angezeigt " + "und nicht als übersetzt behandelt. Deutsch, Englisch und der aktive Standard können nicht deinstalliert werden. " + "Systemadministrierende steuern verfügbare und aktivierte Sprachpakete sowie den Systemstandard; Mandanten und Benutzende " + "können nur Sprachen wählen, die von den übergeordneten Ebenen erlaubt sind. Bereits ausdrücklich gespeicherte Präferenzen " + "bleiben bei Einführung dieses Standards erhalten. Das Deaktivieren einer Sprache darf weder übersetzte Inhalte verwerfen " + "noch eine gespeicherte Präferenz stillschweigend umschreiben." + ), + } + }, metadata={ "kind": "reference", "route": "/admin?section=system-language-packages", @@ -248,6 +329,23 @@ manifest = ModuleManifest( documentation_types=("admin",), audience=("system_admin",), related_modules=("tenancy", "access", "views"), + translations={ + "de": { + "title": "Systemweite Navigationsgrundlage festlegen", + "summary": ( + "Systemadministrierende definieren die instanzweite Reihenfolge und Sichtbarkeitsgrundlage der Seitenleiste sowie " + "Einträge, die untergeordnete Ebenen sichtbar halten müssen." + ), + "body": ( + "Die systemweite Navigation beginnt mit den von den Modulen deklarierten Standardwerten. Mandanteneinstellungen haben " + "bei Reihenfolge und Sichtbarkeit Vorrang vor dem System, persönliche Einstellungen vor beiden. Eine Systemsperre " + "verhindert, dass Mandanten- oder Benutzereinstellungen einen Eintrag ausblenden, erlaubt aber weiterhin dessen " + "Verschiebung. Das Entfernen der Systempräferenz stellt die Modulstandardwerte wieder her. Navigationsrichtlinien ändern " + "nur die Darstellung; Modulberechtigung, View-Richtlinie und Zugriffsrechte bestimmen weiterhin, ob eine Oberfläche " + "erreichbar ist." + ), + } + }, metadata={ "kind": "reference", "help_contexts": ["admin.system-settings"], @@ -267,6 +365,33 @@ manifest = ModuleManifest( documentation_types=("admin",), audience=("system_admin", "operator", "module_admin"), related_modules=("ops", "audit"), + translations={ + "de": { + "title": "Änderungen am Modul-Lebenszyklus planen und überwachen", + "summary": ( + "Einen geprüften Modulpaketplan durch Vorprüfung, wartungsgeschützte Einreihung, Daemon-Ausführung und dauerhafte " + "Laufnachweise führen." + ), + "body": ( + "Der Administrationsbereich Module bildet einen Betriebsablauf ab: Paketplan speichern, Befunde der Vorprüfung beheben, " + "mit der erforderlichen Berechtigung in den Wartungsmodus wechseln, einen überwachten Installer-Auftrag einreihen und " + "den zugehörigen Laufdatensatz prüfen. Ist kein deploymentspezifischer Katalog konfiguriert, ermittelt das " + "Paketverzeichnis den signierten öffentlichen stabilen GovOPlaN-Katalog. Verfügbare, installierte, aktualisierbare, " + "blockierte und zurückgezogene Einträge lassen sich suchen und filtern. Jede Zeile zeigt signierte Quellrevision, " + "Artefakt-Digest, Versionshinweise, Konfigurationsanforderungen und die vom Manifest deklarierten Berechtigungen des " + "Katalogs. Diese Offenlegung unterstützt die Prüfung, gewährt aber keine Berechtigung. Fehlende Abhängigkeiten, " + "inkompatible benannte Schnittstellen, nicht unterstützte Aktualisierungsfenster und zurückgezogene Releases blockieren " + "die Planerstellung. Die Auswahl eines geeigneten Eintrags kopiert seine exakten signierten Registry-Kennungen in den Plan; " + "Download und Digest-Prüfung erfolgen ausschließlich im vertrauenswürdigen Installer. Die Stufenanzeige wird aus " + "Speicherzeitpunkt des Plans, neuestem passendem Auftrag und dessen Lauf abgeleitet; ein älterer Auftrag gilt nie als " + "Nachweis für einen neueren Plan. Deaktivierte Einreihungsaktionen nennen den frühesten Blocker, die zuständige Person und " + "die Planoberfläche für die Fortsetzung. Paketänderungen bleiben außerhalb des FastAPI-Prozesses, " + "Wiederherstellungsnachweise dauerhaft im Installer-Ledger. Gemeinsame Deployments benötigen ein unveränderliches " + "Image-Rollout statt lokaler Änderungen je Knoten. Mandantenberechtigung und Benutzer-/View-Sichtbarkeit bleiben " + "Richtlinieneinstellungen und sind keine Paket-Lebenszyklusaktionen." + ), + } + }, metadata={ "kind": "workflow", "context_ids": [ diff --git a/tests/test_interface_documentation_contract.py b/tests/test_interface_documentation_contract.py index 8f5a40e..c714e24 100644 --- a/tests/test_interface_documentation_contract.py +++ b/tests/test_interface_documentation_contract.py @@ -6,6 +6,18 @@ from govoplan_admin.backend.manifest import manifest class InterfaceDocumentationContractTests(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_admin_topics_publish_stable_help_contexts(self) -> None: topics = {topic.id: topic for topic in manifest.documentation} expected = { @@ -40,9 +52,7 @@ class InterfaceDocumentationContractTests(unittest.TestCase): ) def test_admin_contributed_surfaces_remain_declared(self) -> None: - surface_ids = { - surface.id for surface in manifest.frontend.view_surfaces - } + surface_ids = {surface.id for surface in manifest.frontend.view_surfaces} self.assertEqual( surface_ids, { @@ -86,10 +96,14 @@ class InterfaceDocumentationContractTests(unittest.TestCase): def test_module_administrator_has_only_tenant_module_permissions(self) -> None: permissions = {item.scope for item in manifest.permissions} - template = next(item for item in manifest.role_templates if item.slug == "module_admin") + template = next( + item for item in manifest.role_templates if item.slug == "module_admin" + ) self.assertEqual({"admin:module:read", "admin:module:write"}, permissions) - self.assertEqual(tuple(sorted(permissions)), tuple(sorted(template.permissions))) + self.assertEqual( + tuple(sorted(permissions)), tuple(sorted(template.permissions)) + ) if __name__ == "__main__": diff --git a/webui/package.json b/webui/package.json index d5372c8..07f2bbc 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/admin-webui", - "version": "0.1.19", + "version": "0.1.20", "private": true, "type": "module", "main": "src/index.ts",