feat: add tenant semantic documentation lifecycle

This commit is contained in:
2026-08-21 15:37:01 +02:00
parent 77eb7339e6
commit d6db344d81
22 changed files with 3717 additions and 8 deletions
+261 -3
View File
@@ -1,30 +1,53 @@
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.modules import (
CapabilityDocumentation,
DocumentationCondition,
DocumentationLink,
DocumentationSourceDefinition,
DocumentationTopic,
FrontendModule,
FrontendRoute,
MigrationSpec,
ModuleContext,
ModuleManifest,
ModuleInterfaceProvider,
NavItem,
PermissionDefinition,
RoleTemplate,
)
from govoplan_core.core.module_guards import (
drop_table_retirement_provider,
persistent_table_uninstall_guard,
)
from govoplan_core.core.provider_governance import (
ModuleArchitectureDeclaration,
ModuleArchitectureDocumentation,
ModuleMaturityEvidence,
)
from govoplan_core.db.base import Base
from govoplan_core.core.search import SearchSourceProviderRegistration
from govoplan_docs.backend.db import models as docs_models
from govoplan_docs.backend.dsar_provider import DOCS_DSAR_CAPABILITY, DocsDsarProvider
from govoplan_docs.backend.search_source import (
create_semantic_documentation_search_source,
)
DOCS_READ_SCOPE = "docs:documentation:read"
DOCS_ADMIN_READ_SCOPE = "docs:documentation:admin"
DOCS_SEMANTIC_CREATE_SCOPE = "docs:semantic:create"
DOCS_SEMANTIC_EDIT_SCOPE = "docs:semantic:edit"
DOCS_SEMANTIC_PUBLISH_SCOPE = "docs:semantic:publish"
DOCS_SEMANTIC_SUPERSEDE_SCOPE = "docs:semantic:supersede"
DOCS_SEMANTIC_RETIRE_SCOPE = "docs:semantic:retire"
DOCS_SEMANTIC_EXPORT_SCOPE = "docs:semantic:export"
DOCS_SEMANTIC_POLICY_SCOPE = "docs:semantic:policy"
DOCS_ADMIN_READ_SCOPES = (
DOCS_ADMIN_READ_SCOPE,
"system:settings:read",
@@ -42,6 +65,11 @@ ARCHITECTURE = ModuleArchitectureDeclaration(
reference="tests/test_docs_context.py",
summary="Tests audience-safe configured documentation and architecture projections.",
),
ModuleMaturityEvidence(
kind="test",
reference="tests/test_semantic_documentation.py",
summary="Tests tenant isolation, immutable revision lifecycle, publication policy, subject reauthorization, search, localization, and DSAR projection.",
),
ModuleMaturityEvidence(
kind="documentation",
reference="docs/DOCUMENTATION_LAYER_CONCEPT.md",
@@ -52,11 +80,21 @@ ARCHITECTURE = ModuleArchitectureDeclaration(
reference="docs/INTERFACE_PATTERN_MIGRATION.md",
summary="Records the Core-owned Docs workspace and page-layout boundary.",
),
ModuleMaturityEvidence(
kind="documentation",
reference="docs/SEMANTIC_DOCUMENTATION.md",
summary="Defines semantic authoring, authorization, lifecycle, export, and recovery behavior.",
),
),
known_limits=(
"Architecture declarations are in staged adoption, so undeclared modules remain visible as pending.",
),
owned_concepts=("configured documentation projection", "documentation audience filtering"),
owned_concepts=(
"configured documentation projection",
"documentation audience filtering",
"tenant semantic documentation revisions",
"semantic documentation publication lifecycle",
),
non_owned_concepts=("module feature behavior", "module evidence generation"),
documentation=ModuleArchitectureDocumentation(
security=("docs/DOCUMENTATION_LAYER_CONCEPT.md",),
@@ -86,21 +124,82 @@ def _route_factory(context: ModuleContext):
return router
def _dsar_provider(_context: ModuleContext) -> DocsDsarProvider:
return DocsDsarProvider()
manifest = ModuleManifest(
id="docs",
name="Docs",
version="0.1.18",
version="0.1.19",
required_capabilities=(
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
),
optional_dependencies=("policy", "audit", "ops", "workflow_engine", "search"),
provides_interfaces=(
ModuleInterfaceProvider(name=DOCS_DSAR_CAPABILITY, version="0.1.0"),
),
capability_factories={DOCS_DSAR_CAPABILITY: _dsar_provider},
capability_documentation={
DOCS_DSAR_CAPABILITY: CapabilityDocumentation(
label="Docs data-subject request provider",
summary=(
"Exports minimized tenant semantic-documentation authorship, "
"review, ownership, and stewardship references while retaining "
"published configuration-governance evidence."
),
contract_version="0.1.0",
),
},
optional_dependencies=(
"policy",
"audit",
"ops",
"workflow",
"forms",
"search",
),
permissions=(
_permission(
DOCS_READ_SCOPE,
"View configured documentation",
"Read user documentation generated for the current actor from installed modules and effective configuration.",
),
_permission(
DOCS_SEMANTIC_CREATE_SCOPE,
"Create semantic documentation",
"Create tenant-owned semantic documentation for configured subjects.",
),
_permission(
DOCS_SEMANTIC_EDIT_SCOPE,
"Edit semantic documentation",
"Edit drafts using immutable revisions and optimistic concurrency.",
),
_permission(
DOCS_SEMANTIC_PUBLISH_SCOPE,
"Publish semantic documentation",
"Review and publish semantic documentation under tenant policy.",
),
_permission(
DOCS_SEMANTIC_SUPERSEDE_SCOPE,
"Supersede semantic documentation",
"Replace semantic documentation with another published entry.",
),
_permission(
DOCS_SEMANTIC_RETIRE_SCOPE,
"Retire semantic documentation",
"Retire semantic documentation while retaining its revision history.",
),
_permission(
DOCS_SEMANTIC_EXPORT_SCOPE,
"Export tenant semantic documentation",
"Export tenant-owned semantic entries and immutable history.",
),
_permission(
DOCS_SEMANTIC_POLICY_SCOPE,
"Configure semantic publication policy",
"Choose direct publication or independent reviewer publication.",
),
_permission(
DOCS_ADMIN_READ_SCOPE,
"View administrative documentation",
@@ -115,6 +214,43 @@ manifest = ModuleManifest(
permissions=(DOCS_READ_SCOPE,),
default_authenticated=True,
),
RoleTemplate(
slug="semantic_documentation_author",
name="Semantic documentation author",
description="Discover configured subjects and create or revise their semantic documentation.",
permissions=(
DOCS_READ_SCOPE,
DOCS_SEMANTIC_CREATE_SCOPE,
DOCS_SEMANTIC_EDIT_SCOPE,
),
),
RoleTemplate(
slug="semantic_documentation_reviewer",
name="Semantic documentation reviewer",
description="Review, publish, supersede, and retire semantic documentation.",
permissions=(
DOCS_READ_SCOPE,
DOCS_SEMANTIC_PUBLISH_SCOPE,
DOCS_SEMANTIC_SUPERSEDE_SCOPE,
DOCS_SEMANTIC_RETIRE_SCOPE,
),
),
RoleTemplate(
slug="semantic_documentation_manager",
name="Semantic documentation manager",
description="Administer semantic authoring, review, lifecycle, policy, and tenant export.",
permissions=(
DOCS_READ_SCOPE,
DOCS_ADMIN_READ_SCOPE,
DOCS_SEMANTIC_CREATE_SCOPE,
DOCS_SEMANTIC_EDIT_SCOPE,
DOCS_SEMANTIC_PUBLISH_SCOPE,
DOCS_SEMANTIC_SUPERSEDE_SCOPE,
DOCS_SEMANTIC_RETIRE_SCOPE,
DOCS_SEMANTIC_EXPORT_SCOPE,
DOCS_SEMANTIC_POLICY_SCOPE,
),
),
RoleTemplate(
slug="docs_admin",
name="Documentation administrator",
@@ -142,6 +278,18 @@ manifest = ModuleManifest(
required_any=DOCS_READ_SCOPES,
order=880,
),
FrontendRoute(
path="/docs/semantic",
component="SemanticDocumentationPage",
required_any=(
DOCS_SEMANTIC_CREATE_SCOPE,
DOCS_SEMANTIC_EDIT_SCOPE,
DOCS_SEMANTIC_PUBLISH_SCOPE,
DOCS_SEMANTIC_SUPERSEDE_SCOPE,
DOCS_SEMANTIC_RETIRE_SCOPE,
),
order=881,
),
),
nav_items=(
NavItem(
@@ -154,6 +302,88 @@ manifest = ModuleManifest(
),
),
documentation=(
DocumentationTopic(
id="docs.semantic-documentation",
title="Tenant semantic documentation",
summary="Explain what configured forms, fields, workflows, steps, and other stable subjects mean in this tenant.",
body=(
"Authors select an authorized subject supplied by its owning module and create locale-specific plain-text guidance. "
"Every save creates an immutable revision. Tenant policy chooses direct publication or an independent reviewer. "
"Published content remains subject to the subject's current authorization, the documentation audience and classification, tenant isolation, and locale selection. "
"Changed, missing, superseded, or temporarily unavailable subjects are shown explicitly; direct links, contextual help, search, caches, and tenant exports apply the same read-time authorization. "
"Retirement and supersession preserve history. Generic public documentation exports never include tenant semantic entries; administrators use the separately authorized tenant export."
),
layer="always",
documentation_types=("admin", "user"),
audience=("tenant_admin", "module_admin", "documentation_author"),
order=11,
conditions=(
DocumentationCondition(
any_scopes=(
DOCS_SEMANTIC_CREATE_SCOPE,
DOCS_SEMANTIC_EDIT_SCOPE,
DOCS_SEMANTIC_PUBLISH_SCOPE,
DOCS_SEMANTIC_POLICY_SCOPE,
),
),
),
links=(
DocumentationLink(
label="Semantic documentation administration",
href="/docs/semantic",
kind="runtime",
),
DocumentationLink(
label="Semantic documentation operations",
href="govoplan-docs/docs/SEMANTIC_DOCUMENTATION.md",
kind="repository",
),
),
metadata={"kind": "workflow"},
),
DocumentationTopic(
id="docs.data-subject-requests",
title="Review Docs semantic attribution in a data-subject request",
summary="Export minimized author, reviewer, owner, and steward references without disclosing unrelated tenant-authored guidance.",
body=(
"Docs matches exact account and namespaced semantic-entry references within the active tenant. "
"The projection identifies the entry, revision, subject, locale, lifecycle state, and fields that matched, but excludes authored body content. "
"Published, superseded, and retired attribution is immutable configuration-governance evidence and is retained with a reason. "
"Draft attribution requires manual governance review so ownership or stewardship can be reassigned before any anonymization; Docs performs no automatic erasure."
),
layer="configured",
documentation_types=("admin",),
audience=("privacy_officer", "documentation_administrator", "operator"),
order=12,
conditions=(
DocumentationCondition(
required_modules=("docs", "access"),
any_scopes=(
"access:privacy:read",
"access:privacy:manage",
"access:privacy:erase",
),
),
),
links=(
DocumentationLink(
label="Data-subject requests",
href="/admin?section=tenant-data-subject-requests",
kind="runtime",
),
DocumentationLink(
label="Semantic documentation operations",
href="govoplan-docs/docs/SEMANTIC_DOCUMENTATION.md",
kind="repository",
),
),
related_modules=("access", "audit", "policy"),
metadata={
"kind": "workflow",
"route": "/admin?section=tenant-data-subject-requests",
"help_contexts": ["admin.privacy.data-subject-requests"],
},
),
DocumentationTopic(
id="docs.configured-system-documentation",
title="Configured system documentation",
@@ -434,6 +664,34 @@ manifest = ModuleManifest(
},
),
),
migration_spec=MigrationSpec(
module_id="docs",
metadata=Base.metadata,
script_location=str(Path(__file__).with_name("migrations") / "versions"),
retirement_supported=True,
retirement_provider=drop_table_retirement_provider(
docs_models.SemanticDocumentationRevision,
docs_models.SemanticDocumentationEntry,
label="Docs semantic documentation",
),
retirement_notes=(
"Destructive retirement removes tenant semantic entries and immutable "
"revision history after the installer captures a database snapshot."
),
),
uninstall_guard_providers=(
persistent_table_uninstall_guard(
docs_models.SemanticDocumentationEntry,
docs_models.SemanticDocumentationRevision,
label="Docs semantic documentation",
),
),
search_sources=(
SearchSourceProviderRegistration(
id="docs.semantic_documentation",
factory=create_semantic_documentation_search_source,
),
),
architecture=ARCHITECTURE,
)