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