Project pending approvals as authorized work

This commit is contained in:
2026-08-06 16:06:17 +02:00
parent 956624be0e
commit b691a0c2d5
8 changed files with 449 additions and 67 deletions
+42 -6
View File
@@ -26,6 +26,7 @@ from govoplan_core.core.modules import (
RoleTemplate,
)
from govoplan_core.core.provider_governance import declared_module_architecture
from govoplan_core.core.tasks import WorkItemProviderRegistration
from govoplan_core.core.views import ViewSurface
from govoplan_core.db.base import Base
from govoplan_approvals.backend.db import models as approval_models
@@ -39,7 +40,14 @@ READ_SCOPE = "approvals:workspace:read"
WRITE_SCOPE = "approvals:workspace:write"
DECIDE_SCOPE = "approvals:workspace:decide"
ADMIN_SCOPE = "approvals:workspace:admin"
OPTIONAL_DEPENDENCIES = ("workflow_engine", "audit", "files", "notifications", "policy")
OPTIONAL_DEPENDENCIES = (
"workflow_engine",
"audit",
"files",
"notifications",
"policy",
"tasks",
)
def _permission(scope: str, label: str, description: str) -> PermissionDefinition:
@@ -66,6 +74,12 @@ def _requests(_context: ModuleContext) -> SqlApprovalRequests:
return SqlApprovalRequests()
def _work_items(_context: ModuleContext):
from govoplan_approvals.backend.work_items import ApprovalWorkItemProvider
return ApprovalWorkItemProvider()
def _tenant_summary(session, tenant_id: str) -> dict[str, int]:
current = session.query(approval_models.ApprovalRequestRevision).filter(
approval_models.ApprovalRequestRevision.tenant_id == tenant_id,
@@ -196,6 +210,13 @@ manifest = ModuleManifest(
contract_version="0.1.0",
)
},
work_item_providers=(
WorkItemProviderRegistration(
id="approvals.pending",
factory=_work_items,
order=30,
),
),
migration_spec=MigrationSpec(
module_id=MODULE_ID,
metadata=Base.metadata,
@@ -229,7 +250,8 @@ manifest = ModuleManifest(
summary="Create exact-subject approval chains with delegation, separation of duties, escalation, and signature evidence.",
body=(
"An Approval request freezes its subject revision, ordered steps, eligible selectors, quorum, rejection policy, signature requirement, and governance references. "
"Decisions are append-only, tenant-bound, optimistic-concurrency protected, and replay safe. Consuming modules verify the exact subject through the capability rather than reading Approval tables."
"Decisions are append-only, tenant-bound, optimistic-concurrency protected, and replay safe. Consuming modules verify the exact subject through the capability rather than reading Approval tables. "
"When Tasks is enabled, a pending step appears in the common work inbox only for a principal who currently passes the exact decision eligibility checks."
),
layer="configured",
documentation_types=("admin", "user"),
@@ -312,10 +334,24 @@ manifest = ModuleManifest(
documentation_types=("admin", "user"),
audience=("operator", "module_admin", "product_owner", "auditor"),
links=(
DocumentationLink(label="Approval templates", href="/admin?section=tenant-approval-templates", kind="runtime"),
DocumentationLink(label="Template API", href="/api/v1/approvals/templates", kind="api"),
DocumentationLink(label="Template history API", href="/api/v1/approvals/templates/{template_id}/history", kind="api"),
DocumentationLink(label="Template comparison API", href="/api/v1/approvals/templates/{template_id}/compare", kind="api"),
DocumentationLink(
label="Approval templates",
href="/admin?section=tenant-approval-templates",
kind="runtime",
),
DocumentationLink(
label="Template API", href="/api/v1/approvals/templates", kind="api"
),
DocumentationLink(
label="Template history API",
href="/api/v1/approvals/templates/{template_id}/history",
kind="api",
),
DocumentationLink(
label="Template comparison API",
href="/api/v1/approvals/templates/{template_id}/compare",
kind="api",
),
),
metadata={
"help_contexts": [