from __future__ import annotations from govoplan_core.core.access import ( CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_TENANT_CONTEXT_SWITCHER, CAPABILITY_TENANCY_TENANT_RESOLVER, ) from govoplan_core.core.modules import DocumentationLink, DocumentationTopic, FrontendModule, ModuleContext, ModuleManifest from govoplan_core.core.provider_governance import declared_module_architecture from govoplan_core.core.views import ViewSurface def _tenant_resolver(context: ModuleContext): del context from govoplan_tenancy.backend.capabilities import SqlTenantResolver return SqlTenantResolver() def _route_factory(context: ModuleContext): del context from fastapi import APIRouter from govoplan_tenancy.backend.api.v1.routes import router, tenant_router aggregate = APIRouter() aggregate.include_router(router) aggregate.include_router(tenant_router) return aggregate manifest = ModuleManifest( id="tenancy", name="Tenancy", version="0.1.8", required_capabilities=( CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_TENANT_CONTEXT_SWITCHER, ), route_factory=_route_factory, capability_factories={ CAPABILITY_TENANCY_TENANT_RESOLVER: _tenant_resolver, }, documentation=( DocumentationTopic( id="tenancy.current-context", title="Work in the correct tenant context", summary="The active tenant determines which tenant-scoped data, roles, settings, and module configuration are visible for a request.", body="Accounts with access to more than one tenant can switch context through the platform tenant selector. Switching changes the active scope; it does not copy data or grant new authority. Always verify the selected tenant before creating or changing tenant-owned records.", documentation_types=("user",), audience=("user", "tenant_admin"), related_modules=("access",), metadata={ "kind": "reference", "help_contexts": ["tenancy.current-context", "tenancy.selector"], }, ), DocumentationTopic( id="tenancy.lifecycle-and-settings", title="Administer tenant lifecycle and settings", summary="Tenancy adds explicit tenant creation, activation, context resolution, and tenant-owned settings over Core's shared scope storage.", body="A tenant is a concrete administrative and data boundary. Tenant lifecycle changes must preserve ownership and recovery guarantees for module-owned records. Tenancy contributes system tenant management and tenant settings to the shared administration workspace; without this module, the Core and Access baseline can operate in single-scope compatibility mode. Core-reserved module entitlement settings are managed only through the Admin module's tenant-module policy endpoints and are preserved when generic tenant settings are replaced.", documentation_types=("admin",), audience=("system_admin", "tenant_admin", "operator"), related_modules=("access", "admin", "audit"), links=( DocumentationLink(label="Tenant administration", href="/admin", kind="runtime"), DocumentationLink(label="Tenant registry API", href="/api/v1/admin/tenants", kind="api"), DocumentationLink(label="Tenant settings API", href="/api/v1/admin/tenant/settings", kind="api"), ), metadata={ "kind": "reference", "help_contexts": [ "tenancy.admin.system-tenants", "tenancy.admin.tenant-settings", "tenancy.admin.lifecycle", "tenancy.admin.blocked", ], }, ), DocumentationTopic( id="tenancy.reference.admin-fields", title="Tenant administration fields and consequences", summary="Tenant identity, ownership, locale, governance overrides, and lifecycle state have different mutation and recovery consequences.", body="A tenant slug is immutable after creation and identifies the administrative boundary. The initial owner receives the protected tenant-owner role. Locale and enabled languages are bounded by system language packages. Governance overrides may narrow a system allowance but cannot loosen a system denial. Suspension keeps tenant-owned data and audit evidence while preventing normal use; an operator must switch away from the active tenant before suspending it.", documentation_types=("admin",), audience=("system_admin", "tenant_admin", "operator"), related_modules=("access", "admin", "audit"), links=( DocumentationLink(label="Tenant administration", href="/admin", kind="runtime"), DocumentationLink(label="Tenant registry API", href="/api/v1/admin/tenants", kind="api"), ), metadata={ "kind": "reference", "help_contexts": [ "tenancy.field.slug", "tenancy.field.initial-owner", "tenancy.field.locale", "tenancy.field.languages", "tenancy.field.governance", "tenancy.action.suspend", ], "consequence_classes": { "create": "Creates a new tenant boundary and provisions its protected initial owner.", "update": "Changes tenant-local identity, locale, or governance configuration.", "suspend": "Blocks normal tenant use while retaining data and audit evidence.", }, }, ), ), frontend=FrontendModule( module_id="tenancy", package_name="@govoplan/tenancy-webui", view_surfaces=( ViewSurface( id="tenancy.admin.system-tenants", module_id="tenancy", kind="section", label="System tenants", order=10, ), ViewSurface( id="tenancy.admin.tenant-settings", module_id="tenancy", kind="section", label="Tenant settings", order=90, ), ), ), architecture=declared_module_architecture( layer="institutional_foundation", kind="foundation", maturity="vertical_slice", documentation_ref="docs/TENANCY_MODULE_BOUNDARY.md", test_ref="tests/test_tenant_lifecycle.py", known_limits=("Cross-region tenant relocation and complete major-version recovery evidence are not implemented.",), owned_concepts=("tenant lifecycle", "tenant context", "tenant settings"), non_owned_concepts=("account authorization", "organization hierarchy", "module-owned tenant data"), recovery_docs=("docs/TENANCY_MODULE_BOUNDARY.md",), security_docs=("docs/TENANCY_MODULE_BOUNDARY.md",), ), ) def get_manifest() -> ModuleManifest: return manifest