Files
govoplan-organizations/src/govoplan_organizations/backend/manifest.py
T

404 lines
16 KiB
Python

from __future__ import annotations
from pathlib import Path
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 (
DocumentationLink,
DocumentationTopic,
FrontendModule,
FrontendRoute,
MigrationSpec,
ModuleContext,
ModuleInterfaceProvider,
ModuleManifest,
NavItem,
PermissionDefinition,
ProductAreaContribution,
RoleTemplate,
)
from govoplan_core.core.provider_governance import declared_module_architecture
from govoplan_core.core.organizations import (
CAPABILITY_ORGANIZATION_DIRECTORY,
CAPABILITY_ORGANIZATION_HIERARCHY_DIRECTORY,
)
from govoplan_core.core.views import ViewSurface
from govoplan_core.db.base import Base
from govoplan_organizations.backend.db import models as organization_models # noqa: F401 - populate metadata
ORGANIZATIONS_READ_SCOPES = (
"organizations:model:read",
"organizations:unit:read",
"organizations:function:read",
"admin:settings:read",
)
def _permission(scope: str, label: str, description: str) -> PermissionDefinition:
module_id, resource, action = scope.split(":", 2)
return PermissionDefinition(
scope=scope,
label=label,
description=description,
category="Organizations",
level="tenant",
module_id=module_id,
resource=resource,
action=action,
)
PERMISSIONS = (
_permission(
"organizations:model:read",
"View organization model",
"Read organization meta-model definitions such as unit types, structures, and relation types.",
),
_permission(
"organizations:model:write",
"Manage organization model",
"Create and edit organization meta-model definitions.",
),
_permission(
"organizations:settings:read",
"View organization settings",
"Read organization governance, audit, and retention settings.",
),
_permission(
"organizations:settings:write",
"Manage organization settings",
"Edit organization governance, audit, and retention settings.",
),
_permission(
"organizations:unit:read",
"View organization units",
"Read concrete organization units and relations.",
),
_permission(
"organizations:unit:write",
"Manage organization units",
"Create and edit concrete organization units and relations.",
),
_permission(
"organizations:function:read",
"View organization functions",
"Read function definitions.",
),
_permission(
"organizations:function:write",
"Manage organization functions",
"Create and edit function definitions.",
),
)
ROLE_TEMPLATES = (
RoleTemplate(
slug="organization_modeler",
name="Organization modeler",
description="Manage organization meta-model, concrete units, structures, and functions.",
permissions=tuple(permission.scope for permission in PERMISSIONS),
),
RoleTemplate(
slug="organization_viewer",
name="Organization viewer",
description="Read organization model, organization units, and functions.",
permissions=(
"organizations:model:read",
"organizations:settings:read",
"organizations:unit:read",
"organizations:function:read",
),
),
)
def _route_factory(context: ModuleContext):
del context
from govoplan_organizations.backend.api.v1.routes import router
return router
def _organization_directory(context: ModuleContext) -> object:
del context
from govoplan_organizations.backend.directory import SqlOrganizationDirectory
return SqlOrganizationDirectory()
manifest = ModuleManifest(
id="organizations",
name="Organizations",
version="0.1.18",
required_capabilities=(
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
),
optional_dependencies=("tenancy", "access", "audit", "policy"),
provides_interfaces=(
ModuleInterfaceProvider(
name="organizations.directory",
version="0.1.0",
),
ModuleInterfaceProvider(
name="organizations.hierarchy_directory",
version="0.1.0",
),
),
permissions=PERMISSIONS,
role_templates=ROLE_TEMPLATES,
route_factory=_route_factory,
nav_items=(
NavItem(
path="/organizations",
label="Organizations",
icon="building-2",
required_any=ORGANIZATIONS_READ_SCOPES,
order=70,
),
),
frontend=FrontendModule(
module_id="organizations",
package_name="@govoplan/organizations-webui",
routes=(
FrontendRoute(
path="/organizations",
component="OrganizationsPage",
required_any=ORGANIZATIONS_READ_SCOPES,
order=70,
),
),
nav_items=(
NavItem(
path="/organizations",
label="Organizations",
icon="building-2",
required_any=ORGANIZATIONS_READ_SCOPES,
order=70,
),
),
product_areas=(
ProductAreaContribution(
id="people-responsibility",
module_id="organizations",
label="i18n:govoplan-core.product_area.people_responsibility",
icon="users",
description="i18n:govoplan-core.product_area.people_responsibility_description",
surface_ids=("organizations.nav.organizations", "organizations.route.organizations"),
order=70,
),
),
view_surfaces=(
ViewSurface(
id="organizations.admin.tenant",
module_id="organizations",
kind="section",
label="Organizations administration",
order=85,
),
ViewSurface(
id="organizations.admin.template-upgrades",
module_id="organizations",
kind="section",
label="Organization template upgrades",
parent_id="organizations.admin.tenant",
order=86,
),
),
),
migration_spec=MigrationSpec(
module_id="organizations",
metadata=Base.metadata,
script_location=str(Path(__file__).with_name("migrations") / "versions"),
),
uninstall_guard_providers=(
persistent_table_uninstall_guard(
organization_models.OrganizationUnitType,
organization_models.OrganizationTenantSettings,
organization_models.OrganizationModelTemplate,
organization_models.OrganizationModelTemplateVersion,
organization_models.OrganizationModelInstantiation,
organization_models.OrganizationModelUpgrade,
organization_models.OrganizationStructure,
organization_models.OrganizationRelationType,
organization_models.OrganizationRelation,
organization_models.OrganizationUnit,
organization_models.OrganizationFunctionType,
organization_models.OrganizationFunction,
label="Organizations",
),
),
capability_factories={
CAPABILITY_ORGANIZATION_DIRECTORY: _organization_directory,
CAPABILITY_ORGANIZATION_HIERARCHY_DIRECTORY: (_organization_directory),
},
documentation=(
DocumentationTopic(
id="organizations.template-upgrades",
title="Upgrade a tenant organization model",
summary=(
"Compare an immutable system template version with the current "
"tenant-owned model before explicitly applying an upgrade."
),
body=(
"Open Organizations administration and create a preview for a newer "
"published version of the template used by the tenant. The persisted "
"three-way comparison separates compatible additions, compatible "
"changes, tenant-only divergence, destructive remapping, and invalid "
"references. Tenant-only changes are preserved. Conflicting or "
"destructive entries require an explicit keep, replace, or bounded "
"mapping decision. Applying the reviewed preview creates a new "
"tenant-owned instantiation and supersedes the previous provenance; "
"it never creates live inheritance. A stale preview is rejected if the "
"tenant model or either template version changed. Cancelling retains "
"the review record without modifying organization data."
),
layer="configured",
documentation_types=("admin",),
audience=("tenant_admin", "operator"),
related_modules=("policy", "audit", "idm", "access"),
links=(
DocumentationLink(
label="Organizations administration",
href="/admin?section=tenant-organization-settings",
kind="runtime",
),
DocumentationLink(
label="Organization upgrade API",
href="/api/v1/organizations/model-upgrades",
kind="api",
),
),
metadata={
"kind": "guide",
"help_contexts": [
"organizations.admin.template-upgrades",
"organizations.template-upgrade.preview",
"organizations.template-upgrade.decision",
"organizations.template-upgrade.apply",
],
},
order=27,
),
DocumentationTopic(
id="organizations.model",
title="Organization model",
summary="Organizations owns units, hierarchy, and functions. IDM links identities to functions, and Access maps accepted facts to roles and rights.",
body=(
"Use organization unit types, structures, and relation types to model how the institution describes itself. "
"A concrete organization unit can participate in several structures at the same time, such as an employer hierarchy and an academic structure. "
"Functions describe responsibilities in organization units. IDM links identities to those functions, and Access maps accepted facts to roles and rights. "
"A function does not itself prove mandate, jurisdiction, decision authority, or signature authority; those effective institutional facts belong to a separate provider contract."
),
layer="configured",
documentation_types=("admin", "user"),
audience=("tenant_admin", "access_admin", "operator"),
related_modules=("tenancy", "access", "idm", "policy", "audit"),
links=(
DocumentationLink(
label="Organizations workspace",
href="/organizations",
kind="runtime",
),
DocumentationLink(
label="Organization model API",
href="/api/v1/organizations/model",
kind="api",
),
),
metadata={
"kind": "guide",
"help_contexts": [
"organizations.workspace",
"organizations.model",
"organizations.units",
"organizations.relations",
"organizations.functions",
"organizations.admin.tenant",
"organizations.blocked",
],
},
order=25,
),
DocumentationTopic(
id="organizations.reference.fields-and-consequences",
title="Organization model fields and consequences",
summary=(
"Distinguish tenant-owned model definitions, concrete units, "
"relations, functions, governance references, and lifecycle state."
),
body=(
"Unit types, structures, relation types, and function types define "
"the tenant-owned model. Units, relations, and functions are concrete "
"institutional facts within that model. Slugs are stable references for "
"integrations; parent and relation changes affect hierarchy traversal and "
"downstream routing. Deactivation retains the record and evidence but "
"removes it from active selection. Delegation and act-in-place flags only "
"describe permitted organizational semantics; Access and governed workflows "
"still decide effective authority. When configured, a recorded change-request "
"ID is required before model mutations. Organization settings are tenant-owned "
"and do not inherit a live global hierarchy."
),
layer="configured",
documentation_types=("admin",),
audience=("tenant_admin", "access_admin", "operator"),
related_modules=("tenancy", "access", "idm", "policy", "audit"),
links=(
DocumentationLink(
label="Organizations workspace",
href="/organizations",
kind="runtime",
),
DocumentationLink(
label="Organization settings API",
href="/api/v1/organizations/settings",
kind="api",
),
),
metadata={
"kind": "reference",
"help_contexts": [
"organizations.field.name",
"organizations.field.slug",
"organizations.field.parent",
"organizations.field.relation",
"organizations.field.function",
"organizations.field.change-request",
"organizations.field.audit-retention",
"organizations.action.deactivate",
],
"consequence_classes": {
"model_change": "Changes the valid vocabulary and constraints for tenant-owned organization facts.",
"hierarchy_change": "Changes traversal, routing, and inherited institutional context for downstream modules.",
"deactivate": "Retains the fact and evidence while removing it from active selection.",
"settings": "Changes tenant-owned governance, audit detail, and retention behavior.",
},
},
order=26,
),
),
architecture=declared_module_architecture(
layer="institutional_foundation",
kind="foundation",
maturity="vertical_slice",
documentation_ref="docs/ORGANIZATION_MODEL.md",
test_ref="tests/test_model_templates.py",
known_limits=(
"Downstream modules must reconcile organization-reference changes from the emitted upgrade event; cross-module records are not rewritten directly.",
),
owned_concepts=("organization unit", "organization structure", "organization relation", "organization function"),
non_owned_concepts=("function incumbency", "identity", "application role", "mandate"),
recovery_docs=("docs/ORGANIZATION_MODEL.md",),
security_docs=("docs/ORGANIZATION_MODEL.md",),
),
)
def get_manifest() -> ModuleManifest:
return manifest