149 lines
7.1 KiB
Python
149 lines
7.1 KiB
Python
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
|