feat: extract headless workflow engine

This commit is contained in:
2026-07-31 16:58:51 +02:00
commit 9bccbd68da
54 changed files with 16275 additions and 0 deletions
@@ -0,0 +1,329 @@
from __future__ import annotations
from pathlib import Path
from govoplan_core.core.access import (
CAPABILITY_ACCESS_DIRECTORY,
CAPABILITY_AUTH_AUTOMATION_PRINCIPAL_PROVIDER,
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
)
from govoplan_core.core.dataflows import CAPABILITY_DATAFLOW_RUN_LIFECYCLE
from govoplan_core.core.module_guards import (
drop_table_retirement_provider,
persistent_table_uninstall_guard,
)
from govoplan_core.core.modules import (
DocumentationTopic,
MigrationSpec,
ModuleContext,
ModuleInterfaceProvider,
ModuleInterfaceRequirement,
ModuleManifest,
PermissionDefinition,
RoleTemplate,
)
from govoplan_core.core.policy import (
CAPABILITY_POLICY_DEFINITION_GOVERNANCE,
)
from govoplan_core.core.notifications import (
CAPABILITY_NOTIFICATIONS_DISPATCH,
)
from govoplan_core.core.references import CAPABILITY_ACCESS_REFERENCE_OPTIONS
from govoplan_core.core.views import CAPABILITY_VIEWS_RESOLVER
from govoplan_core.core.workflows import (
CAPABILITY_WORKFLOW_DEFINITION_CONTRIBUTIONS,
CAPABILITY_WORKFLOW_RUNTIME_WORKER,
)
from govoplan_core.db.base import Base
from govoplan_workflow_engine.backend.db import models as workflow_models
MODULE_ID = "workflow_engine"
MODULE_NAME = "Workflow Engine"
MODULE_VERSION = "0.1.14"
DEFINITION_READ_SCOPE = "workflow:definition:read"
DEFINITION_WRITE_SCOPE = "workflow:definition:write"
INSTANCE_READ_SCOPE = "workflow:instance:read"
INSTANCE_START_SCOPE = "workflow:instance:start"
INSTANCE_TRANSITION_SCOPE = "workflow:instance:transition"
ADMIN_SCOPE = "workflow:instance:admin"
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="Workflow",
level="tenant",
module_id=module_id,
resource=resource,
action=action,
)
PERMISSIONS = (
_permission(
DEFINITION_READ_SCOPE,
"View workflow definitions",
"Read workflow graphs, versions, diagnostics, and referenced contracts.",
),
_permission(
DEFINITION_WRITE_SCOPE,
"Manage workflow definitions",
"Create, edit, validate, and publish workflow definitions.",
),
_permission(
INSTANCE_READ_SCOPE,
"View workflow instances",
"Read workflow progress, pending actions, and transition evidence.",
),
_permission(
INSTANCE_START_SCOPE,
"Start workflows",
"Start approved workflow definitions for authorized subjects.",
),
_permission(
INSTANCE_TRANSITION_SCOPE,
"Advance workflows",
"Complete activities and invoke authorized workflow transitions.",
),
_permission(
ADMIN_SCOPE,
"Administer workflows",
"Manage workflow definitions and instances across the tenant.",
),
)
ROLE_TEMPLATES = (
RoleTemplate(
slug="workflow_designer",
name="Workflow designer",
description="Design, validate, and publish workflow definitions.",
permissions=(DEFINITION_READ_SCOPE, DEFINITION_WRITE_SCOPE, INSTANCE_READ_SCOPE),
),
RoleTemplate(
slug="workflow_operator",
name="Workflow operator",
description="Start and advance approved workflows.",
permissions=(
DEFINITION_READ_SCOPE,
INSTANCE_READ_SCOPE,
INSTANCE_START_SCOPE,
INSTANCE_TRANSITION_SCOPE,
),
),
)
def _router(context: ModuleContext):
from govoplan_workflow_engine.backend.runtime import configure_runtime
configure_runtime(registry=context.registry, settings=context.settings)
from govoplan_workflow_engine.backend.router import router
return router
def _runtime_worker(context: ModuleContext):
from govoplan_workflow_engine.backend.instance_service import (
SqlWorkflowRuntimeWorker,
)
return SqlWorkflowRuntimeWorker(registry=context.registry)
def _definition_contribution_provider(context: ModuleContext):
from govoplan_workflow_engine.backend.contributions import (
SqlWorkflowDefinitionContributionProvider,
)
return SqlWorkflowDefinitionContributionProvider(registry=context.registry)
manifest = ModuleManifest(
id=MODULE_ID,
name=MODULE_NAME,
version=MODULE_VERSION,
permission_namespace="workflow",
dependencies=(),
optional_dependencies=(
"access",
"audit",
"dataflow",
"datasources",
"notifications",
"policy",
"tasks",
"views",
),
optional_capabilities=(
CAPABILITY_ACCESS_DIRECTORY,
CAPABILITY_ACCESS_REFERENCE_OPTIONS,
CAPABILITY_AUTH_AUTOMATION_PRINCIPAL_PROVIDER,
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
CAPABILITY_DATAFLOW_RUN_LIFECYCLE,
CAPABILITY_NOTIFICATIONS_DISPATCH,
CAPABILITY_POLICY_DEFINITION_GOVERNANCE,
CAPABILITY_VIEWS_RESOLVER,
),
provides_interfaces=(
ModuleInterfaceProvider(name="workflow.definition_graph", version="0.1.0"),
ModuleInterfaceProvider(name="workflow.node_library", version="0.1.0"),
ModuleInterfaceProvider(name="workflow.definition_catalogue", version="0.1.0"),
ModuleInterfaceProvider(
name="workflow.definition_contributions",
version="0.1.0",
),
ModuleInterfaceProvider(name="workflow.runtime_worker", version=MODULE_VERSION),
ModuleInterfaceProvider(name="workflow.bpmn_interchange", version="1.0.0"),
ModuleInterfaceProvider(
name="workflow.bpmn_execution_adapters",
version="1.0.0",
),
),
requires_interfaces=(
ModuleInterfaceRequirement(
name=CAPABILITY_ACCESS_REFERENCE_OPTIONS,
version_min="0.1.0",
version_max_exclusive="0.2.0",
optional=True,
),
ModuleInterfaceRequirement(
name="dataflow.run_lifecycle",
version_min="0.1.14",
version_max_exclusive="1.0.0",
optional=True,
),
ModuleInterfaceRequirement(
name="auth.automation_principal",
version_min="0.1.0",
version_max_exclusive="1.0.0",
optional=True,
),
ModuleInterfaceRequirement(
name=CAPABILITY_NOTIFICATIONS_DISPATCH,
version_min="0.1.0",
version_max_exclusive="1.0.0",
optional=True,
),
ModuleInterfaceRequirement(
name="policy.definition_governance",
version_min="0.1.0",
version_max_exclusive="1.0.0",
optional=True,
),
ModuleInterfaceRequirement(
name="views.resolver",
version_min="0.1.0",
version_max_exclusive="1.0.0",
optional=True,
),
),
permissions=PERMISSIONS,
role_templates=ROLE_TEMPLATES,
route_factory=_router,
capability_factories={
CAPABILITY_WORKFLOW_DEFINITION_CONTRIBUTIONS: (
_definition_contribution_provider
),
CAPABILITY_WORKFLOW_RUNTIME_WORKER: _runtime_worker,
},
migration_spec=MigrationSpec(
module_id=MODULE_ID,
metadata=Base.metadata,
script_location=str(Path(__file__).with_name("migrations") / "versions"),
retirement_supported=True,
retirement_provider=drop_table_retirement_provider(
workflow_models.WorkflowInstanceEvent,
workflow_models.WorkflowInstanceStep,
workflow_models.WorkflowInstance,
workflow_models.WorkflowDefinitionRevision,
workflow_models.WorkflowDefinition,
label="Workflow",
),
retirement_notes=(
"Destructive retirement drops Workflow definitions and immutable revisions "
"after the installer captures a database snapshot."
),
),
uninstall_guard_providers=(
persistent_table_uninstall_guard(
workflow_models.WorkflowDefinition,
workflow_models.WorkflowDefinitionRevision,
workflow_models.WorkflowInstance,
workflow_models.WorkflowInstanceStep,
workflow_models.WorkflowInstanceEvent,
label="Workflow",
),
),
documentation=(
DocumentationTopic(
id="workflow.definition-graphs",
title="Workflow definition graphs",
summary="Governed process graphs exposed independently of an editor.",
body=(
"Workflow Engine provides trigger, activity, decision, wait, integration, "
"and outcome node library on top of Core's domain-neutral graph contract. "
"Unlike Dataflow, Workflow permits cycles for correction and retry paths. "
"Module actions are addressed through versioned capabilities rather than "
"implementation imports. Definitions are persisted as immutable graph "
"revisions; activation pins the exact revision used by future instances."
),
layer="available",
documentation_types=("admin", "user"),
audience=("operator", "module_admin", "power_user", "product_owner"),
related_modules=("dataflow", "datasources", "tasks", "notifications", "audit"),
order=76,
),
DocumentationTopic(
id="workflow.bpmn-interchange",
title="BPMN modeling and execution profiles",
summary=(
"Lossless BPMN 2.0 revisions with explicit, fail-closed "
"execution conformance."
),
body=(
"BPMN 2.0 is Workflow's canonical native graph language. The "
"shared graph editor models BPMN nodes, flows, containment, and "
"diagram geometry directly without a separate browser-side "
"modeler. Imported XML is normalized into the graph and every "
"immutable revision pins a deterministic XML artifact. Activation "
"requires a pinned execution adapter and version whose declared "
"profile accepts every modeled runtime semantic. Unsupported "
"runtime constructs remain editable and exportable. "
"Adapter packages integrate through the "
"govoplan.workflow.bpmn_adapters entry-point group and must "
"materialize canonical Workflow runtime state; Workflow Engine never "
"imports a concrete engine module."
),
layer="available",
documentation_types=("admin", "user"),
audience=("operator", "module_admin", "power_user", "product_owner"),
related_modules=("audit", "policy", "views"),
order=77,
),
),
)
def get_manifest() -> ModuleManifest:
return manifest
__all__ = [
"ADMIN_SCOPE",
"DEFINITION_READ_SCOPE",
"DEFINITION_WRITE_SCOPE",
"INSTANCE_READ_SCOPE",
"INSTANCE_START_SCOPE",
"INSTANCE_TRANSITION_SCOPE",
"MODULE_ID",
"MODULE_VERSION",
"get_manifest",
"manifest",
]