from __future__ import annotations from govoplan_admin.backend.db import models as admin_models # noqa: F401 - populate Admin ORM metadata from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER from govoplan_core.core.module_guards import persistent_table_uninstall_guard from govoplan_core.core.modules import ( DocumentationCondition, DocumentationTopic, FrontendModule, MigrationSpec, ModuleContext, ModuleManifest, PermissionDefinition, RoleTemplate, ) from govoplan_core.core.provider_governance import declared_module_architecture from govoplan_core.core.views import ViewSurface from govoplan_core.db.base import Base def _route_factory(context: ModuleContext): del context from govoplan_admin.backend.api.v1.routes import router return router ADMIN_PERMISSIONS = ( PermissionDefinition( scope="admin:module:read", module_id="admin", resource="module", action="read", label="View tenant modules", description="Inspect module availability, requirements, and effective state for the active tenant.", category="Administration", level="tenant", ), PermissionDefinition( scope="admin:module:write", module_id="admin", resource="module", action="write", label="Manage tenant modules", description="Enable or disable modules for the active tenant within system policy.", category="Administration", level="tenant", ), ) ADMIN_ROLE_TEMPLATES = ( RoleTemplate( slug="module_admin", name="Module administrator", description="Manage the active tenant's module selection within system policy.", permissions=("admin:module:read", "admin:module:write"), level="tenant", managed=True, protected=False, ), ) manifest = ModuleManifest( id="admin", name="Admin", version="0.1.18", permissions=ADMIN_PERMISSIONS, role_templates=ADMIN_ROLE_TEMPLATES, required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR), route_factory=_route_factory, documentation=( DocumentationTopic( id="admin.workspace", title="Use the administration workspace", summary="The administration workspace shows only the sections supplied by enabled modules and allowed by the current account's permissions.", 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"), metadata={ "kind": "reference", "help_contexts": [ "admin.workspace", "admin.overview", "admin.section-navigation", ], }, ), DocumentationTopic( id="admin.tenant-module-entitlements", title="Govern modules per tenant", summary="System administrators set each tenant's module ceiling and forced modules; tenant module administrators choose within that ceiling.", body=( "Deployment activation installs and loads module code for the whole instance. Tenant module governance is a separate entitlement layer: system administrators mark modules unavailable, available, or forced for a tenant and may also change that tenant's selection. A tenant module administrator can only enable or disable available modules; forced modules and required dependencies remain effective. Module entitlement never grants permissions, and malformed policy fails closed to protected administration modules. Disabling a module stops new API, capability, schedule, and worker admission for that tenant; accepted durable work remains queued and requires an operator decision rather than being executed or discarded. Enabling a capability module such as Encryption only makes its services available; data encryption remains an explicit owning-module policy or migration decision." ), layer="configured", documentation_types=("admin",), audience=("system_admin", "module_admin", "tenant_admin"), related_modules=("access", "policy", "views", "encryption"), metadata={ "kind": "workflow", "help_contexts": [ "admin.system-tenant-modules", "admin.tenant-modules", ], }, ), DocumentationTopic( id="admin.governance-and-module-lifecycle", title="Govern configuration and module lifecycle", summary="Admin owns reusable governance templates, configuration packages, and the operator-facing module lifecycle queue.", body="Configuration packages import or export module-owned configuration; they do not install software. Module catalog actions create reviewed install, update, activation, deactivation, or retirement requests for the trusted installer process. Governance templates materialize approved role and group structures through the owning Access contracts.", documentation_types=("admin",), audience=("system_admin", "operator", "module_admin"), related_modules=("access", "audit", "ops"), metadata={ "kind": "reference", "help_contexts": [ "admin.system-settings", "admin.configuration-changes", "admin.configuration-packages", "admin.governance-templates", ], }, ), DocumentationTopic( id="admin.language-reference-and-packages", title="Manage reference language and language packages", summary="German is the reference and new-installation default while configured tenant and user language choices remain effective.", body=( "German is the first-class product acceptance language and the default for a new system or tenant. English remains installed as the source-code fallback. The dedicated Language packages administration surface separates package installation, activation, deactivation, uninstall eligibility, and the default for newly created tenants from general system settings. Its compatibility matrix derives each package state from the installed module ID, exact module version, and available runtime translation catalog; a missing catalog is shown as incompatible rather than treated as translated. German, English, and the active default cannot be uninstalled. System administrators control available and enabled language packages and the system default; tenant and user choices can select only languages allowed above them. Existing explicit preferences are preserved when this baseline is introduced. Disabling a language must not discard translated content or silently rewrite a stored preference." ), documentation_types=("admin",), audience=("system_admin", "tenant_admin"), related_modules=("tenancy", "access", "docs"), metadata={ "kind": "reference", "route": "/admin?section=system-language-packages", "screen": "Language packages", "help_contexts": [ "admin.system-language-packages", "admin.system-language-packages.compatibility", ], }, ), DocumentationTopic( id="admin.system-navigation", title="Set the system navigation baseline", summary="System administrators define the instance-wide side-rail order, visibility baseline, and entries that lower scopes must keep visible.", body=( "The system navigation setting starts from module-declared defaults. Tenant settings take precedence over the system order and visibility, and personal settings take precedence over both. A system lock prevents tenant and user preferences from hiding an entry but does not prevent them from moving it. Removing the system preference restores module defaults. Navigation policy changes presentation only: module entitlement, View policy, and permissions still decide whether a surface is accessible." ), documentation_types=("admin",), audience=("system_admin",), related_modules=("tenancy", "access", "views"), metadata={ "kind": "reference", "help_contexts": ["admin.system-settings"], }, ), DocumentationTopic( id="admin.module-lifecycle-workflow", title="Plan and supervise module lifecycle changes", summary="Move a reviewed module package plan through preflight, maintenance-gated queueing, daemon execution, and durable run evidence.", body=( "The Modules administration surface projects one operator workflow: save a package plan, resolve preflight findings, enter maintenance mode with the required authority, queue a supervised installer request, and inspect the matching run record. " "When no deployment-specific catalog is configured, the package directory discovers the signed public GovOPlaN stable catalog. Operators can search and filter available, installed, update, blocked, and withdrawn entries; each row exposes the signed source revision, artifact digest, release notes, configuration requirements, and manifest-declared permission scopes supplied by the catalog. Permission disclosure supports review but never grants a scope. Missing dependencies, incompatible named interfaces, unsupported update windows, and withdrawn releases block plan creation. Selecting an eligible entry copies its exact signed registry identities into the plan; artifact download and digest verification happen only in the trusted installer. " "The stage indicator is derived from the saved plan timestamp, the latest matching request, and its run; an older request is never presented as evidence for a newer plan. " "Disabled queue actions name the earliest blocker, the person who can resolve it, and the plan surface where work continues. Package mutation remains outside the FastAPI process and recovery evidence remains durable in the installer ledger. Shared deployments require an immutable image rollout rather than node-local mutation. Tenant entitlement and user/View visibility remain policy settings, not package lifecycle operations." ), layer="configured", documentation_types=("admin",), audience=("system_admin", "operator", "module_admin"), related_modules=("ops", "audit"), metadata={ "kind": "workflow", "context_ids": [ "admin.module-lifecycle", "admin.module-lifecycle.queue-blocker", ], "help_contexts": [ "admin.module-lifecycle", "admin.module-lifecycle.queue-blocker", "admin.module-lifecycle.plan", "admin.module-lifecycle.catalog", "admin.module-lifecycle.evidence", ], }, ), DocumentationTopic( id="admin.data-subject-request-workspace", title="Review data-subject requests", summary="The privacy workspace makes provider coverage, exports, retained evidence, and selected erasure actions explicit.", body=( "The data-subject request section is visible only with the Access privacy read permission. Create and search operations require privacy management authority; exports and erasure execution have separate permissions. Subject selectors support account, membership, identity, email, and namespaced source-system references. The workspace never treats a module without a provider as searched. It lists provider coverage and failures next to collected records. An erasure plan separates executable provider actions from retained or manual-review items. Destructive execution uses the current resource revision, selected actions, and an exact confirmation phrase." ), layer="configured", documentation_types=("admin", "user"), audience=("privacy_officer", "tenant_owner", "operator"), related_modules=("access", "audit", "policy"), conditions=( DocumentationCondition( required_modules=("admin", "access"), any_scopes=( "access:privacy:read", "access:privacy:manage", "access:privacy:export", "access:privacy:erase", ), ), ), translations={ "de": { "title": "Betroffenenanfragen prüfen", "summary": "Der Datenschutz-Arbeitsbereich weist Anbieterabdeckung, Exporte, aufbewahrte Nachweise und ausgewählte Löschaktionen explizit aus.", "body": "Der Bereich ist nur mit dem Leserecht für Datenschutzanfragen sichtbar. Anlage und Suche, Export sowie Löschausführung besitzen getrennte Rechte. Betroffene Personen können über Konto, Mitgliedschaft, Identität, E-Mail-Adresse und namensraumgebundene Quellsystemreferenzen gesucht werden. Module ohne Anbieter werden nicht als durchsucht dargestellt. Ein Löschplan trennt ausführbare Aktionen von aufzubewahrenden oder manuell zu prüfenden Einträgen. Die Ausführung verlangt die aktuelle Revision, eine Aktionsauswahl und eine exakte Bestätigung.", } }, metadata={ "kind": "workflow", "help_contexts": ["admin.privacy.data-subject-requests"], "route": "/admin?section=tenant-data-subject-requests", "api_path": "/api/v1/admin/privacy/data-subject-requests", }, ), ), frontend=FrontendModule( module_id="admin", package_name="@govoplan/admin-webui", view_surfaces=( ViewSurface(id="admin.section.overview", module_id="admin", kind="section", label="Administration overview", order=0), ViewSurface(id="admin.section.system-settings", module_id="admin", kind="section", label="System settings", order=10), ViewSurface(id="admin.section.system-language-packages", module_id="admin", kind="section", label="Language packages", order=15), ViewSurface(id="admin.section.system-configuration-changes", module_id="admin", kind="section", label="Configuration changes", order=20), ViewSurface(id="admin.section.system-configuration-packages", module_id="admin", kind="section", label="Configuration packages", order=30), ViewSurface(id="admin.section.system-role-templates", module_id="admin", kind="section", label="Role templates", order=40), ViewSurface(id="admin.section.system-groups", module_id="admin", kind="section", label="Group templates", order=50), ViewSurface(id="admin.section.system-modules", module_id="admin", kind="section", label="Modules", order=85), ViewSurface(id="admin.section.system-tenant-modules", module_id="admin", kind="section", label="Tenant modules", order=86), ViewSurface(id="admin.section.tenant-data-subject-requests", module_id="admin", kind="section", label="Data-subject requests", order=55), ViewSurface(id="admin.section.tenant-modules", module_id="admin", kind="section", label="Modules", order=60), ), ), migration_spec=MigrationSpec(module_id="admin", metadata=Base.metadata), uninstall_guard_providers=( persistent_table_uninstall_guard( admin_models.GovernanceTemplate, admin_models.GovernanceTemplateAssignment, label="Admin", ), ), architecture=declared_module_architecture( layer="runtime_meta", kind="presentation", maturity="vertical_slice", documentation_ref="README.md", test_ref="tests/test_catalog_plan.py", known_limits=("Some module-specific administration surfaces still own their own navigation and release evidence.",), owned_concepts=("administration workspace", "configuration package workflow", "module lifecycle request"), non_owned_concepts=("module installation effect", "access policy", "module-owned settings"), operations_docs=("README.md",), ), ) def get_manifest() -> ModuleManifest: return manifest